bcd4363f98f7e2cd9e3c109280e73397b225e6bf
[supertux.git] / src / badguy / mrtree.cpp
1 //  $Id$
2 // 
3 //  SuperTux
4 //  Copyright (C) 2005 Matthias Braun <matze@braunis.de>
5 //
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.
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, write to the Free Software
18 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 //  02111-1307, USA.
20
21 #include <config.h>
22
23 #include "mrtree.hpp"
24 #include "poisonivy.hpp"
25
26 static const float WALKSPEED = 100;
27 static const float WALKSPEED_SMALL = 120;
28 static const float INVINCIBLE_TIME = 1;
29
30 MrTree::MrTree(const lisp::Lisp& reader)
31   : mystate(STATE_BIG)
32 {
33   reader.get("x", start_position.x);
34   reader.get("y", start_position.y);
35   stay_on_platform = false;
36   reader.get("stay-on-platform", stay_on_platform);
37   bbox.set_size(84.8, 84.8);
38   sprite = sprite_manager->create("images/creatures/mr_tree/mr_tree.sprite");
39 }
40
41 void
42 MrTree::write(lisp::Writer& writer)
43 {
44   writer.start_list("mrtree");
45
46   writer.write_float("x", start_position.x);
47   writer.write_float("y", start_position.y);
48
49   writer.end_list("mrtree");
50 }
51
52 void
53 MrTree::activate()
54 {
55   if (mystate == STATE_BIG) {
56     physic.set_velocity_x(dir == LEFT ? -WALKSPEED : WALKSPEED);
57     sprite->set_action(dir == LEFT ? "large-left" : "large-right");
58     return;
59   }
60   if (mystate == STATE_INVINCIBLE) {
61     physic.set_velocity_x(0);
62     sprite->set_action(dir == LEFT ? "small-left" : "small-right");
63     return;
64   }
65   if (mystate == STATE_NORMAL) {
66     physic.set_velocity_x(dir == LEFT ? -WALKSPEED_SMALL : WALKSPEED_SMALL);
67     sprite->set_action(dir == LEFT ? "small-left" : "small-right");
68     return;
69   }
70 }
71
72 void
73 MrTree::active_update(float elapsed_time)
74 {
75   if ((mystate == STATE_INVINCIBLE) && (invincible_timer.check())) {
76     mystate = STATE_NORMAL;
77     activate();
78   }
79
80   if (stay_on_platform && may_fall_off_platform())
81   {
82     dir = (dir == LEFT ? RIGHT : LEFT);
83     activate();
84   }
85
86   BadGuy::active_update(elapsed_time);
87 }
88
89 bool
90 MrTree::collision_squished(Player& player)
91 {
92   // if we're big, we shrink
93   if(mystate == STATE_BIG) {
94     mystate = STATE_INVINCIBLE;
95     invincible_timer.start(INVINCIBLE_TIME);
96     activate();
97
98     // shrink bounding box and adjust sprite position to where the stump once was
99     bbox.set_size(42, 62);
100     Vector pos = get_pos();
101     pos.x += 20;
102     pos.y += 23;
103     set_pos(pos);
104
105     sound_manager->play("sounds/mr_tree.ogg", get_pos());
106     player.bounce(*this);
107
108     Rect leaf1_bbox = Rect(pos.x-32-1, pos.y-23+1, pos.x-32-1+32, pos.y-23+1+32);
109     if (Sector::current()->is_free_space(leaf1_bbox)) {
110       PoisonIvy* leaf1 = new PoisonIvy(leaf1_bbox.p1.x, leaf1_bbox.p1.y, LEFT);
111       Sector::current()->add_object(leaf1);
112     }
113     Rect leaf2_bbox = Rect(pos.x+42+1, pos.y-23+1, pos.x+32+1+32, pos.y-23+1+32);
114     if (Sector::current()->is_free_space(leaf2_bbox)) {
115       PoisonIvy* leaf2 = new PoisonIvy(leaf2_bbox.p1.x, leaf2_bbox.p1.y, RIGHT);
116       Sector::current()->add_object(leaf2);
117     }
118
119     return true;
120   }
121
122   // if we're still invincible, we ignore the hit
123   if (mystate == STATE_INVINCIBLE) {
124     sound_manager->play("sounds/mr_treehit.ogg", get_pos());
125     player.bounce(*this);
126     return true;
127   }
128
129   // if we're small, we die
130   if (mystate == STATE_NORMAL) {
131     sprite->set_action(dir == LEFT ? "squished-left" : "squished-right");
132     bbox.set_size(42, 42);
133     kill_squished(player);
134     return true;
135   }
136
137   //TODO: exception?
138   return true;
139 }
140
141 HitResponse
142 MrTree::collision_solid(GameObject& , const CollisionHit& hit)
143 {
144   if(fabsf(hit.normal.y) > .5) {
145     physic.set_velocity_y(0);
146   } else {
147     dir = dir == LEFT ? RIGHT : LEFT;
148     activate();
149   }
150
151   return CONTINUE;
152 }
153
154 HitResponse
155 MrTree::collision_badguy(BadGuy& , const CollisionHit& hit)
156 {
157   if(fabsf(hit.normal.x) > .8) { // left or right hit
158     dir = dir == LEFT ? RIGHT : LEFT;
159     activate();
160   }
161
162   return CONTINUE;
163 }
164
165 IMPLEMENT_FACTORY(MrTree, "mrtree")
166