1 // SuperTux - "Totem" Badguy
2 // Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.de>
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "badguy/totem.hpp"
19 #include "audio/sound_manager.hpp"
20 #include "object/player.hpp"
21 #include "sprite/sprite.hpp"
22 #include "supertux/object_factory.hpp"
23 #include "supertux/sector.hpp"
27 static const float WALKSPEED = 100;
28 static const float JUMP_ON_SPEED_Y = -400;
29 static const float JUMP_OFF_SPEED_Y = -500;
30 static const std::string LAND_ON_TOTEM_SOUND = "sounds/totem.ogg";
32 Totem::Totem(const Reader& reader) :
33 BadGuy(reader, "images/creatures/totem/totem.sprite"),
37 sound_manager->preload( LAND_ON_TOTEM_SOUND );
42 if (carrying) carrying->jump_off();
43 if (carried_by) jump_off();
47 Totem::updatePointers(const GameObject* from_object, GameObject* to_object)
49 if (from_object == carrying) {
50 carrying = dynamic_cast<Totem*>(to_object);
53 if (from_object == carried_by) {
54 carried_by = dynamic_cast<Totem*>(to_object);
64 physic.set_velocity_x(dir == LEFT ? -WALKSPEED : WALKSPEED);
65 sprite->set_action(dir == LEFT ? "walking-left" : "walking-right");
68 synchronize_with(carried_by);
69 sprite->set_action(dir == LEFT ? "stacked-left" : "stacked-right");
75 Totem::active_update(float elapsed_time)
77 BadGuy::active_update(elapsed_time);
80 if (on_ground() && might_fall())
82 dir = (dir == LEFT ? RIGHT : LEFT);
86 Sector* s = Sector::current();
88 // jump a bit if we find a suitable totem
89 for (std::vector<MovingObject*>::iterator i = s->moving_objects.begin(); i != s->moving_objects.end(); i++) {
90 Totem* t = dynamic_cast<Totem*>(*i);
93 // skip if we are not approaching each other
94 if (!((this->dir == LEFT) && (t->dir == RIGHT))) continue;
96 Vector p1 = this->get_pos();
97 Vector p2 = t->get_pos();
99 // skip if not on same height
100 float dy = (p1.y - p2.y);
101 if (fabsf(dy - 0) > 2) continue;
103 // skip if too far away
104 float dx = (p1.x - p2.x);
105 if (fabsf(dx - 128) > 2) continue;
107 physic.set_velocity_y(JUMP_ON_SPEED_Y);
116 this->synchronize_with(carried_by);
120 carrying->synchronize_with(this);
126 Totem::collision_squished(GameObject& object)
128 if (carrying) carrying->jump_off();
130 Player* player = dynamic_cast<Player*>(&object);
131 if (player) player->bounce(*this);
135 sprite->set_action(dir == LEFT ? "squished-left" : "squished-right");
136 bbox.set_size(sprite->get_current_hitbox_width(), sprite->get_current_hitbox_height());
138 kill_squished(object);
143 Totem::collision_solid(const CollisionHit& hit)
145 update_on_ground_flag(hit);
147 // if we are being carried around, pass event to bottom of stack and ignore it
149 carried_by->collision_solid(hit);
153 // If we hit something from above or below: stop moving in this direction
154 if (hit.top || hit.bottom) {
155 physic.set_velocity_y(0);
158 // If we are hit from the direction we are facing: turn around
159 if (hit.left && (dir == LEFT)) {
163 if (hit.right && (dir == RIGHT)) {
170 Totem::collision_badguy(BadGuy& badguy, const CollisionHit& hit)
172 // if we are being carried around, pass event to bottom of stack and ignore it
174 carried_by->collision_badguy(badguy, hit);
178 // if we hit a Totem that is not from our stack: have our base jump on its top
179 Totem* totem = dynamic_cast<Totem*>(&badguy);
181 Totem* thisBase = this; while (thisBase->carried_by) thisBase=thisBase->carried_by;
182 Totem* srcBase = totem; while (srcBase->carried_by) srcBase=srcBase->carried_by;
183 Totem* thisTop = this; while (thisTop->carrying) thisTop=thisTop->carrying;
184 if (srcBase != thisBase) {
185 srcBase->jump_on(thisTop);
189 // If we are hit from the direction we are facing: turn around
190 if(hit.left && (dir == LEFT)) {
194 if(hit.right && (dir == RIGHT)) {
205 if (carrying) carrying->jump_off();
206 if (carried_by) jump_off();
212 Totem::jump_on(Totem* target)
214 if (target->carrying) {
215 log_warning << "target is already carrying someone" << std::endl;
219 target->carrying = this;
221 this->carried_by = target;
223 bbox.set_size(sprite->get_current_hitbox_width(), sprite->get_current_hitbox_height());
225 sound_manager->play( LAND_ON_TOTEM_SOUND , get_pos());
227 this->synchronize_with(target);
233 log_warning << "not carried by anyone" << std::endl;
237 carried_by->carrying = 0;
239 this->carried_by = 0;
242 bbox.set_size(sprite->get_current_hitbox_width(), sprite->get_current_hitbox_height());
244 physic.set_velocity_y(JUMP_OFF_SPEED_Y);
248 Totem::synchronize_with(Totem* base)
251 if (dir != base->dir) {
253 sprite->set_action(dir == LEFT ? "stacked-left" : "stacked-right");
256 Vector pos = base->get_pos();
257 pos.y -= sprite->get_current_hitbox_height();
260 physic.set_velocity_x(base->physic.get_velocity_x());
261 physic.set_velocity_y(base->physic.get_velocity_y());
264 IMPLEMENT_FACTORY(Totem, "totem");