Random stuff that I should have committed ages ago.
[supertux.git] / src / badguy / mole.cpp
1 //  $Id$
2 //
3 //  SuperTux - Mole Badguy
4 //  Copyright (C) 2006 Christoph Sommer <christoph.sommer@2006.expires.deltadevelopment.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  02111-1307, USA.
19
20 #include <config.h>
21
22 #include "mole.hpp"
23 #include "mole_rock.hpp"
24 #include "tile.hpp"
25 #include "object/tilemap.hpp"
26 #include "random_generator.hpp"
27 #include "log.hpp"
28 #include "level.hpp"
29 #include "lisp/writer.hpp"
30 #include "object_factory.hpp"
31 #include "audio/sound_manager.hpp"
32 #include "sector.hpp"
33 #include "sprite/sprite.hpp"
34
35 #include <math.h>
36
37 static const float IDLE_TIME = 0.2f; /**< time to wait before and after throwing */
38 static const float THROW_TIME = 4.6f; /**< time to spend throwing */
39 static const float THROW_INTERVAL = 1; /**< time between two thrown rocks */
40 static const float THROW_VELOCITY = 400; /**< initial velocity of thrown rocks */
41
42 Mole::Mole(const lisp::Lisp& reader)
43   : BadGuy(reader, "images/creatures/mole/mole.sprite", LAYER_TILES-1), state(PRE_THROWING)
44 {
45   physic.enable_gravity(false);
46   sound_manager->preload("sounds/fall.wav");
47   sound_manager->preload("sounds/squish.wav");
48   sound_manager->preload("sounds/dartfire.wav");
49 }
50
51 Mole::Mole(const Vector& pos)
52   : BadGuy(pos, "images/creatures/mole/mole.sprite", LAYER_TILES-1), state(PRE_THROWING)
53 {
54   physic.enable_gravity(false);
55   sound_manager->preload("sounds/fall.wav");
56   sound_manager->preload("sounds/squish.wav");
57   sound_manager->preload("sounds/dartfire.wav");
58 }
59
60 void
61 Mole::write(lisp::Writer& writer)
62 {
63   writer.start_list("mole");
64   writer.write("x", start_position.x);
65   writer.write("y", start_position.y);
66   writer.end_list("mole");
67 }
68
69 void
70 Mole::activate()
71 {
72   if (state != DEAD) set_state(PRE_THROWING);
73 }
74
75 void
76 Mole::kill_fall()
77 {
78   set_state(DEAD);
79   sound_manager->play("sounds/fall.wav", get_pos());
80   if (countMe) Sector::current()->get_level()->stats.badguys++;
81 }
82
83 HitResponse
84 Mole::collision_badguy(BadGuy& , const CollisionHit& )
85 {
86   return FORCE_MOVE;
87 }
88
89 bool
90 Mole::collision_squished(GameObject& )
91 {
92   set_state(DEAD);
93   sound_manager->play("sounds/squish.wav", get_pos());
94   if (countMe) Sector::current()->get_level()->stats.badguys++;
95   return true;
96 }
97
98 void
99 Mole::throw_rock()
100 {
101   float px = get_bbox().get_middle().x;
102   float py = get_bbox().get_middle().y;
103
104   float angle = systemRandom.rand(90 - 15, 90 + 15) * (M_PI / 180);
105   float vx = cos(angle) * THROW_VELOCITY;
106   float vy = -sin(angle) * THROW_VELOCITY;
107
108   sound_manager->play("sounds/dartfire.wav", get_pos());
109   Sector::current()->add_object(new MoleRock(Vector(px, py), Vector(vx, vy), this));
110 }
111
112 void
113 Mole::active_update(float elapsed_time)
114 {
115   BadGuy::active_update(elapsed_time);
116
117   switch (state) {
118     case PRE_THROWING:
119       if (timer.check()) {
120         set_state(THROWING);
121       }
122       break;
123     case THROWING:
124       if (throw_timer.check()) {
125         throw_rock();
126         throw_timer.start(THROW_INTERVAL);
127       }
128       if (timer.check()) {
129         set_state(POST_THROWING);
130       }
131       break;
132     case POST_THROWING:
133       if (timer.check()) {
134         set_state(PEEKING);
135       }
136       break;
137     case PEEKING:
138       if (sprite->animation_done()) {
139         set_state(PRE_THROWING);
140       }
141       break;
142     case DEAD:
143       break;
144   }
145
146 }
147
148 void
149 Mole::set_state(MoleState new_state)
150 {
151   switch (new_state) {
152     case PRE_THROWING:
153       sprite->set_action("idle");
154       set_colgroup_active(COLGROUP_DISABLED);
155       timer.start(IDLE_TIME);
156       break;
157     case THROWING:
158       sprite->set_action("idle");
159       set_colgroup_active(COLGROUP_DISABLED);
160       timer.start(THROW_TIME);
161       throw_timer.start(THROW_INTERVAL);
162       break;
163     case POST_THROWING:
164       sprite->set_action("idle");
165       set_colgroup_active(COLGROUP_DISABLED);
166       timer.start(IDLE_TIME);
167       break;
168     case PEEKING:
169       sprite->set_action("peeking", 1);
170       set_colgroup_active(COLGROUP_STATIC);
171       break;
172     case DEAD:
173       sprite->set_action("idle");
174       set_colgroup_active(COLGROUP_DISABLED);
175       break;
176   }
177
178   state = new_state;
179 }
180
181 IMPLEMENT_FACTORY(Mole, "mole")