Merged changes from branches/supertux-milestone2-grumbel/ to trunk/supertux/
[supertux.git] / src / object / icecrusher.cpp
1 //  IceCrusher - A block to stand on, which can drop down to crush the player
2 //  Copyright (C) 2008 Christoph Sommer <christoph.sommer@2008.expires.deltadevelopment.de>
3 //
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.
8 //
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.
13 //
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/>.
16
17 #include "object/icecrusher.hpp"
18
19 #include "badguy/badguy.hpp"
20 #include "sprite/sprite.hpp"
21 #include "object/player.hpp"
22 #include "supertux/object_factory.hpp"
23 #include "supertux/sector.hpp"
24
25 namespace {
26 const float DROP_SPEED = 500;
27 const float RECOVER_SPEED = 200;
28 }
29
30 IceCrusher::IceCrusher(const Reader& reader)
31   : MovingSprite(reader, "images/creatures/icecrusher/icecrusher.sprite", LAYER_OBJECTS, COLGROUP_STATIC), 
32     state(IDLE), speed(Vector(0,0))
33 {
34   start_position = get_bbox().p1;
35   set_state(state, true);
36 }
37
38 /*
39   IceCrusher::IceCrusher(const IceCrusher& other)
40   : MovingSprite(other), 
41   state(other.state), speed(other.speed) 
42   {
43   start_position = get_bbox().p1;
44   set_state(state, true);
45   }
46 */
47 void 
48 IceCrusher::set_state(IceCrusherState state, bool force) 
49 {
50   if ((this->state == state) && (!force)) return;
51   switch(state) {
52     case IDLE:
53       set_group(COLGROUP_STATIC);
54       speed=Vector(0,0);
55       sprite->set_action("idle");
56       break;
57     case CRUSHING:
58       set_group(COLGROUP_MOVING_STATIC);
59       speed=Vector(0, DROP_SPEED);
60       sprite->set_action("idle");
61       break;
62     case RECOVERING:
63       set_group(COLGROUP_MOVING_STATIC);
64       speed=Vector(0, -RECOVER_SPEED);
65       sprite->set_action("idle");
66       break;
67     default:
68       log_debug << "IceCrusher in invalid state" << std::endl;
69       break;
70   }
71   this->state = state;
72 }
73
74 HitResponse
75 IceCrusher::collision(GameObject& other, const CollisionHit& hit)
76 {
77   Player* player = dynamic_cast<Player*>(&other);
78   if (player && hit.bottom) {
79     if(player->is_invincible()) {
80       if (state == CRUSHING) set_state(RECOVERING);
81       return ABORT_MOVE;
82     }
83     player->kill(false);
84     if (state == CRUSHING) set_state(RECOVERING);
85     return FORCE_MOVE;
86   }
87   BadGuy* badguy = dynamic_cast<BadGuy*>(&other);
88   if (badguy) {
89     badguy->kill_fall();
90   }
91   return FORCE_MOVE;
92 }
93     
94 void 
95 IceCrusher::collision_solid(const CollisionHit& )
96 {
97   switch(state) {
98     case IDLE:
99       break;
100     case CRUSHING:
101       set_state(RECOVERING);
102       break;
103     case RECOVERING:
104       break;
105     default:
106       log_debug << "IceCrusher in invalid state" << std::endl;
107       break;
108   }
109 }
110
111 void
112 IceCrusher::update(float elapsed_time)
113 {
114   switch(state) {
115     case IDLE:
116       if (found_victim()) set_state(CRUSHING);
117       break;
118     case CRUSHING:
119       break;
120     case RECOVERING:
121       if (get_bbox().p1.y <= start_position.y+1) {
122         set_pos(start_position);
123         set_state(IDLE);
124       }
125       break;
126     default:
127       log_debug << "IceCrusher in invalid state" << std::endl;
128       break;
129   }
130   movement = speed * elapsed_time;
131 }
132
133 Player*
134 IceCrusher::get_nearest_player()
135 {
136   // FIXME: does not really return nearest player
137
138   std::vector<Player*> players = Sector::current()->get_players();
139   for (std::vector<Player*>::iterator playerIter = players.begin(); playerIter != players.end(); ++playerIter) {
140     Player* player = *playerIter;
141     if (player->is_dying() || player->is_dead()) continue;
142     return player;
143   }
144
145   return 0;
146 }
147
148 bool
149 IceCrusher::found_victim()
150 {
151   Player* player = this->get_nearest_player();
152   if (!player) return false;
153
154   const Rect& pr = player->get_bbox();
155   const Rect& br = get_bbox();
156   if ((pr.p2.x > br.p1.x) && (pr.p1.x < br.p2.x) && (pr.p1.y >= br.p2.y)) {
157     return true;
158   }
159   return false;
160 }
161
162 IMPLEMENT_FACTORY(IceCrusher, "icecrusher");
163
164 /* EOF */