00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "badguy/totem.hpp"
00018
00019 #include "audio/sound_manager.hpp"
00020 #include "object/player.hpp"
00021 #include "sprite/sprite.hpp"
00022 #include "supertux/object_factory.hpp"
00023 #include "supertux/sector.hpp"
00024
00025 #include <math.h>
00026
00027 static const float JUMP_ON_SPEED_Y = -400;
00028 static const float JUMP_OFF_SPEED_Y = -500;
00029 static const std::string LAND_ON_TOTEM_SOUND = "sounds/totem.ogg";
00030
00031 Totem::Totem(const Reader& reader) :
00032 BadGuy(reader, "images/creatures/totem/totem.sprite"),
00033 carrying(0),
00034 carried_by(0)
00035 {
00036 sound_manager->preload( LAND_ON_TOTEM_SOUND );
00037 }
00038
00039 Totem::~Totem()
00040 {
00041 if (carrying) carrying->jump_off();
00042 if (carried_by) jump_off();
00043 }
00044
00045 bool
00046 Totem::updatePointers(const GameObject* from_object, GameObject* to_object)
00047 {
00048 if (from_object == carrying) {
00049 carrying = dynamic_cast<Totem*>(to_object);
00050 return true;
00051 }
00052 if (from_object == carried_by) {
00053 carried_by = dynamic_cast<Totem*>(to_object);
00054 return true;
00055 }
00056 return false;
00057 }
00058
00059 void
00060 Totem::initialize()
00061 {
00062 if (!carried_by) {
00063 static const float WALKSPEED = 100;
00064 physic.set_velocity_x(dir == LEFT ? -WALKSPEED : WALKSPEED);
00065 sprite->set_action(dir == LEFT ? "walking-left" : "walking-right");
00066 return;
00067 } else {
00068 synchronize_with(carried_by);
00069 sprite->set_action(dir == LEFT ? "stacked-left" : "stacked-right");
00070 return;
00071 }
00072 }
00073
00074 void
00075 Totem::active_update(float elapsed_time)
00076 {
00077 BadGuy::active_update(elapsed_time);
00078
00079 if (!carried_by) {
00080 if (on_ground() && might_fall())
00081 {
00082 dir = (dir == LEFT ? RIGHT : LEFT);
00083 initialize();
00084 }
00085
00086 Sector* s = Sector::current();
00087 if (s) {
00088
00089 for (std::vector<MovingObject*>::iterator i = s->moving_objects.begin(); i != s->moving_objects.end(); i++) {
00090 Totem* t = dynamic_cast<Totem*>(*i);
00091 if (!t) continue;
00092
00093
00094 if (!((this->dir == LEFT) && (t->dir == RIGHT))) continue;
00095
00096 Vector p1 = this->get_pos();
00097 Vector p2 = t->get_pos();
00098
00099
00100 float dy = (p1.y - p2.y);
00101 if (fabsf(dy - 0) > 2) continue;
00102
00103
00104 float dx = (p1.x - p2.x);
00105 if (fabsf(dx - 128) > 2) continue;
00106
00107 physic.set_velocity_y(JUMP_ON_SPEED_Y);
00108 p1.y -= 1;
00109 this->set_pos(p1);
00110 break;
00111 }
00112 }
00113 }
00114
00115 if (carried_by) {
00116 this->synchronize_with(carried_by);
00117 }
00118
00119 if (carrying) {
00120 carrying->synchronize_with(this);
00121 }
00122
00123 }
00124
00125 bool
00126 Totem::collision_squished(GameObject& object)
00127 {
00128 if (carrying) carrying->jump_off();
00129 if (carried_by) {
00130 Player* player = dynamic_cast<Player*>(&object);
00131 if (player) player->bounce(*this);
00132 jump_off();
00133 }
00134
00135 sprite->set_action(dir == LEFT ? "squished-left" : "squished-right");
00136 bbox.set_size(sprite->get_current_hitbox_width(), sprite->get_current_hitbox_height());
00137
00138 kill_squished(object);
00139 return true;
00140 }
00141
00142 void
00143 Totem::collision_solid(const CollisionHit& hit)
00144 {
00145 update_on_ground_flag(hit);
00146
00147
00148 if (carried_by) {
00149 carried_by->collision_solid(hit);
00150 return;
00151 }
00152
00153
00154 if (hit.top || hit.bottom) {
00155 physic.set_velocity_y(0);
00156 }
00157
00158
00159 if (hit.left && (dir == LEFT)) {
00160 dir = RIGHT;
00161 initialize();
00162 }
00163 if (hit.right && (dir == RIGHT)) {
00164 dir = LEFT;
00165 initialize();
00166 }
00167 }
00168
00169 HitResponse
00170 Totem::collision_badguy(BadGuy& badguy, const CollisionHit& hit)
00171 {
00172
00173 if (carried_by) {
00174 carried_by->collision_badguy(badguy, hit);
00175 return CONTINUE;
00176 }
00177
00178
00179 Totem* totem = dynamic_cast<Totem*>(&badguy);
00180 if (totem) {
00181 Totem* thisBase = this; while (thisBase->carried_by) thisBase=thisBase->carried_by;
00182 Totem* srcBase = totem; while (srcBase->carried_by) srcBase=srcBase->carried_by;
00183 Totem* thisTop = this; while (thisTop->carrying) thisTop=thisTop->carrying;
00184 if (srcBase != thisBase) {
00185 srcBase->jump_on(thisTop);
00186 }
00187 }
00188
00189
00190 if(hit.left && (dir == LEFT)) {
00191 dir = RIGHT;
00192 initialize();
00193 }
00194 if(hit.right && (dir == RIGHT)) {
00195 dir = LEFT;
00196 initialize();
00197 }
00198
00199 return CONTINUE;
00200 }
00201
00202 void
00203 Totem::kill_fall()
00204 {
00205 if (carrying) carrying->jump_off();
00206 if (carried_by) jump_off();
00207
00208 BadGuy::kill_fall();
00209 }
00210
00211 void
00212 Totem::jump_on(Totem* target)
00213 {
00214 if (target->carrying) {
00215 log_warning << "target is already carrying someone" << std::endl;
00216 return;
00217 }
00218
00219 target->carrying = this;
00220
00221 this->carried_by = target;
00222 this->initialize();
00223 bbox.set_size(sprite->get_current_hitbox_width(), sprite->get_current_hitbox_height());
00224
00225 sound_manager->play( LAND_ON_TOTEM_SOUND , get_pos());
00226
00227 this->synchronize_with(target);
00228 }
00229
00230 void
00231 Totem::jump_off() {
00232 if (!carried_by) {
00233 log_warning << "not carried by anyone" << std::endl;
00234 return;
00235 }
00236
00237 carried_by->carrying = 0;
00238
00239 this->carried_by = 0;
00240
00241 this->initialize();
00242 bbox.set_size(sprite->get_current_hitbox_width(), sprite->get_current_hitbox_height());
00243
00244 physic.set_velocity_y(JUMP_OFF_SPEED_Y);
00245 }
00246
00247 void
00248 Totem::synchronize_with(Totem* base)
00249 {
00250
00251 if (dir != base->dir) {
00252 dir = base->dir;
00253 sprite->set_action(dir == LEFT ? "stacked-left" : "stacked-right");
00254 }
00255
00256 Vector pos = base->get_pos();
00257 pos.y -= sprite->get_current_hitbox_height();
00258 set_pos(pos);
00259
00260 physic.set_velocity_x(base->physic.get_velocity_x());
00261 physic.set_velocity_y(base->physic.get_velocity_y());
00262 }
00263
00264