Unstable tile: Implement a "slow fall" phase for sprites without "shake" and "dissolv...
[supertux.git] / src / object / unstable_tile.cpp
1 //  SuperTux - Unstable Tile
2 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
3 //  Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.de>
4 //  Copyright (C) 2010 Florian Forster <supertux at octo.it>
5 //
6 //  This program is free software: you can redistribute it and/or modify
7 //  it under the terms of the GNU General Public License as published by
8 //  the Free Software Foundation, either version 3 of the License, or
9 //  (at your option) any later version.
10 //
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.
15 //
16 //  You should have received a copy of the GNU General Public License
17 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
19 #include "object/unstable_tile.hpp"
20
21 #include "object/explosion.hpp"
22 #include "object/player.hpp"
23 #include "sprite/sprite.hpp"
24 #include "supertux/constants.hpp"
25 #include "supertux/object_factory.hpp"
26
27 UnstableTile::UnstableTile(const Reader& lisp) :
28   MovingSprite(lisp, LAYER_TILES, COLGROUP_STATIC), 
29   physic(),
30   state(STATE_NORMAL)
31 {
32   sprite->set_action("normal");
33   physic.set_gravity_modifier (.98);
34   physic.enable_gravity (false);
35 }
36
37 HitResponse
38 UnstableTile::collision(GameObject& other, const CollisionHit& )
39 {
40   if(state == STATE_NORMAL) {
41     Player* player = dynamic_cast<Player*> (&other);
42     if(player != NULL &&
43        player->get_bbox().get_bottom() < get_bbox().get_top() + SHIFT_DELTA) {
44       shake ();
45     }
46
47     if (dynamic_cast<Explosion*> (&other)) {
48       shake ();
49     }
50   }
51   return FORCE_MOVE;
52 }
53
54 void UnstableTile::shake (void)
55 {
56   if (state != STATE_NORMAL)
57     return;
58
59   if (sprite->has_action ("shake")) {
60     state = STATE_SHAKE;
61     this->set_action ("shake", /* loops = */ 1);
62   }
63   else {
64     dissolve ();
65   }
66 }
67
68 void UnstableTile::dissolve (void)
69 {
70   if ((state != STATE_NORMAL) && (state != STATE_SHAKE))
71     return;
72
73   if (sprite->has_action ("dissolve")) {
74     state = STATE_DISSOLVE;
75     this->set_action ("dissolve", /* loops = */ 1);
76   }
77   else {
78     slow_fall ();
79   }
80 }
81
82 void UnstableTile::slow_fall (void)
83 {
84   /* Only enter slow-fall if neither shake nor dissolve is available. */
85   if (state != STATE_NORMAL) {
86     this->fall_down ();
87     return;
88   }
89
90   if (sprite->has_action ("fall-down")) {
91     state = STATE_SLOWFALL;
92     this->set_action ("fall-down", /* loops = */ 1);
93     physic.set_gravity_modifier (.10);
94     physic.enable_gravity (true);
95     slowfall_timer = 0.5; /* Fall slowly for half a second. */
96   }
97   else {
98     remove_me ();
99   }
100 }
101
102 void UnstableTile::fall_down (void)
103 {
104   if ((state != STATE_NORMAL)
105       && (state != STATE_SHAKE)
106       && (state != STATE_DISSOLVE)
107       && (state != STATE_SLOWFALL))
108     return;
109
110   if (sprite->has_action ("fall-down")) {
111     state = STATE_FALL;
112     this->set_action ("fall-down", /* loops = */ 1);
113     physic.set_gravity_modifier (.98);
114     physic.enable_gravity (true);
115   }
116   else {
117     remove_me ();
118   }
119 }
120
121 void
122 UnstableTile::update(float elapsed_time)
123 {
124   switch (state)
125   {
126     case STATE_NORMAL:
127       break;
128
129     case STATE_SHAKE:
130       if (sprite->animation_done())
131         dissolve ();
132       break;
133
134     case STATE_DISSOLVE:
135       if (sprite->animation_done()) {
136         /* dissolving is done. Set to non-solid. */
137         set_group (COLGROUP_DISABLED);
138         fall_down ();
139       }
140       break;
141
142     case STATE_SLOWFALL:
143       if (slowfall_timer >= elapsed_time)
144         slowfall_timer -= elapsed_time;
145       else /* Switch to normal falling procedure */
146         fall_down ();
147       movement = physic.get_movement (elapsed_time);
148       break;
149
150     case STATE_FALL:
151       if (sprite->animation_done())
152         remove_me ();
153       else
154         movement = physic.get_movement (elapsed_time);
155       break;
156   }
157 }
158
159 /* EOF */