3 // SuperTux - "Totem" Badguy
4 // Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.de>
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
26 static const float WALKSPEED = 100;
27 static const float JUMP_ON_SPEED_Y = -400;
28 static const float JUMP_OFF_SPEED_Y = -500;
29 static const std::string LAND_ON_TOTEM_SOUND = "sounds/totem.ogg";
31 Totem::Totem(const lisp::Lisp& reader)
32 : BadGuy(reader, "images/creatures/totem/totem.sprite")
36 sound_manager->preload( LAND_ON_TOTEM_SOUND );
39 Totem::Totem(const Totem& other)
40 : BadGuy(other), carrying(other.carrying), carried_by(other.carried_by)
42 sound_manager->preload( LAND_ON_TOTEM_SOUND );
47 if (carrying) carrying->jump_off();
48 if (carried_by) jump_off();
52 Totem::updatePointers(const GameObject* from_object, GameObject* to_object)
54 if (from_object == carrying) {
55 carrying = dynamic_cast<Totem*>(to_object);
58 if (from_object == carried_by) {
59 carried_by = dynamic_cast<Totem*>(to_object);
66 Totem::write(lisp::Writer& writer)
68 writer.start_list("totem");
70 writer.write_float("x", start_position.x);
71 writer.write_float("y", start_position.y);
73 writer.end_list("totem");
80 physic.set_velocity_x(dir == LEFT ? -WALKSPEED : WALKSPEED);
81 sprite->set_action(dir == LEFT ? "walking-left" : "walking-right");
84 synchronize_with(carried_by);
85 sprite->set_action(dir == LEFT ? "stacked-left" : "stacked-right");
91 Totem::active_update(float elapsed_time)
93 BadGuy::active_update(elapsed_time);
96 if (on_ground() && might_fall())
98 dir = (dir == LEFT ? RIGHT : LEFT);
102 Sector* s = Sector::current();
104 // jump a bit if we find a suitable totem
105 for (std::vector<MovingObject*>::iterator i = s->moving_objects.begin(); i != s->moving_objects.end(); i++) {
106 Totem* t = dynamic_cast<Totem*>(*i);
109 // skip if we are not approaching each other
110 if (!((this->dir == LEFT) && (t->dir == RIGHT))) continue;
112 Vector p1 = this->get_pos();
113 Vector p2 = t->get_pos();
115 // skip if not on same height
116 float dy = (p1.y - p2.y);
117 if (fabsf(dy - 0) > 2) continue;
119 // skip if too far away
120 float dx = (p1.x - p2.x);
121 if (fabsf(dx - 128) > 2) continue;
123 physic.set_velocity_y(JUMP_ON_SPEED_Y);
132 this->synchronize_with(carried_by);
136 carrying->synchronize_with(this);
142 Totem::collision_squished(GameObject& object)
144 if (carrying) carrying->jump_off();
146 Player* player = dynamic_cast<Player*>(&object);
147 if (player) player->bounce(*this);
151 sprite->set_action(dir == LEFT ? "squished-left" : "squished-right");
152 bbox.set_size(sprite->get_current_hitbox_width(), sprite->get_current_hitbox_height());
154 kill_squished(object);
159 Totem::collision_solid(const CollisionHit& hit)
161 update_on_ground_flag(hit);
163 // if we are being carried around, pass event to bottom of stack and ignore it
165 carried_by->collision_solid(hit);
169 // If we hit something from above or below: stop moving in this direction
170 if (hit.top || hit.bottom) {
171 physic.set_velocity_y(0);
174 // If we are hit from the direction we are facing: turn around
175 if (hit.left && (dir == LEFT)) {
179 if (hit.right && (dir == RIGHT)) {
186 Totem::collision_badguy(BadGuy& badguy, const CollisionHit& hit)
188 // if we are being carried around, pass event to bottom of stack and ignore it
190 carried_by->collision_badguy(badguy, hit);
194 // if we hit a Totem that is not from our stack: have our base jump on its top
195 Totem* totem = dynamic_cast<Totem*>(&badguy);
197 Totem* thisBase = this; while (thisBase->carried_by) thisBase=thisBase->carried_by;
198 Totem* srcBase = totem; while (srcBase->carried_by) srcBase=srcBase->carried_by;
199 Totem* thisTop = this; while (thisTop->carrying) thisTop=thisTop->carrying;
200 if (srcBase != thisBase) {
201 srcBase->jump_on(thisTop);
205 // If we are hit from the direction we are facing: turn around
206 if(hit.left && (dir == LEFT)) {
210 if(hit.right && (dir == RIGHT)) {
221 if (carrying) carrying->jump_off();
222 if (carried_by) jump_off();
228 Totem::jump_on(Totem* target)
230 if (target->carrying) {
231 log_warning << "target is already carrying someone" << std::endl;
235 target->carrying = this;
237 this->carried_by = target;
239 bbox.set_size(sprite->get_current_hitbox_width(), sprite->get_current_hitbox_height());
241 sound_manager->play( LAND_ON_TOTEM_SOUND , get_pos());
244 this->synchronize_with(target);
250 log_warning << "not carried by anyone" << std::endl;
254 carried_by->carrying = 0;
256 this->carried_by = 0;
259 bbox.set_size(sprite->get_current_hitbox_width(), sprite->get_current_hitbox_height());
262 physic.set_velocity_y(JUMP_OFF_SPEED_Y);
266 Totem::synchronize_with(Totem* base)
269 if (dir != base->dir) {
271 sprite->set_action(dir == LEFT ? "stacked-left" : "stacked-right");
274 Vector pos = base->get_pos();
275 pos.y -= sprite->get_current_hitbox_height();
278 physic.set_velocity_x(base->physic.get_velocity_x());
279 physic.set_velocity_y(base->physic.get_velocity_y());
283 IMPLEMENT_FACTORY(Totem, "totem")