1 | // SuperTux |
2 | // Copyright (C) 2006 Matthias Braun <matze@braunis.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 "badguy/stumpy.hpp" |
18 | |
19 | #include <math.h> |
20 | |
21 | #include "audio/sound_manager.hpp" |
22 | #include "math/random.hpp" |
23 | #include "math/util.hpp" |
24 | #include "object/player.hpp" |
25 | #include "object/sprite_particle.hpp" |
26 | #include "sprite/sprite.hpp" |
27 | #include "supertux/sector.hpp" |
28 | |
29 | static const float STUMPY_SPEED = 120; |
30 | static const float INVINCIBLE_TIME = 1; |
31 | |
32 | Stumpy::Stumpy(const ReaderMapping& reader) : |
33 | WalkingBadguy(reader, "images/creatures/mr_tree/stumpy.sprite" ,"left" ,"right" , LAYER_OBJECTS, |
34 | "images/objects/lightmap_light/lightmap_light-large.sprite" ), |
35 | mystate(STATE_NORMAL), |
36 | invincible_timer() |
37 | { |
38 | walk_speed = STUMPY_SPEED; |
39 | max_drop_height = 16; |
40 | SoundManager::current()->preload("sounds/mr_treehit.ogg" ); |
41 | } |
42 | |
43 | Stumpy::Stumpy(const Vector& pos, Direction d) : |
44 | WalkingBadguy(pos, d, "images/creatures/mr_tree/stumpy.sprite" ,"left" ,"right" ), |
45 | mystate(STATE_INVINCIBLE), |
46 | invincible_timer() |
47 | { |
48 | walk_speed = STUMPY_SPEED; |
49 | max_drop_height = 16; |
50 | SoundManager::current()->preload("sounds/mr_treehit.ogg" ); |
51 | invincible_timer.start(INVINCIBLE_TIME); |
52 | } |
53 | |
54 | void |
55 | Stumpy::initialize() |
56 | { |
57 | switch (mystate) { |
58 | case STATE_INVINCIBLE: |
59 | m_sprite->set_action(m_dir == Direction::LEFT ? "dizzy-left" : "dizzy-right" ); |
60 | m_col.m_bbox.set_size(m_sprite->get_current_hitbox_width(), m_sprite->get_current_hitbox_height()); |
61 | m_physic.set_velocity_x(0); |
62 | break; |
63 | case STATE_NORMAL: |
64 | WalkingBadguy::initialize(); |
65 | break; |
66 | } |
67 | } |
68 | |
69 | void |
70 | Stumpy::active_update(float dt_sec) |
71 | { |
72 | switch (mystate) { |
73 | case STATE_INVINCIBLE: |
74 | if (invincible_timer.check()) { |
75 | mystate = STATE_NORMAL; |
76 | WalkingBadguy::initialize(); |
77 | } |
78 | BadGuy::active_update(dt_sec); |
79 | break; |
80 | case STATE_NORMAL: |
81 | WalkingBadguy::active_update(dt_sec); |
82 | break; |
83 | } |
84 | } |
85 | |
86 | bool |
87 | Stumpy::collision_squished(GameObject& object) |
88 | { |
89 | |
90 | // if we're still invincible, we ignore the hit |
91 | if (mystate == STATE_INVINCIBLE) { |
92 | SoundManager::current()->play("sounds/mr_treehit.ogg" , get_pos()); |
93 | auto player = dynamic_cast<Player*>(&object); |
94 | if (player) player->bounce(*this); |
95 | return true; |
96 | } |
97 | |
98 | // if we can die, we do |
99 | if (mystate == STATE_NORMAL) { |
100 | m_sprite->set_action(m_dir == Direction::LEFT ? "squished-left" : "squished-right" ); |
101 | m_col.set_size(m_sprite->get_current_hitbox_width(), m_sprite->get_current_hitbox_height()); |
102 | kill_squished(object); |
103 | // spawn some particles |
104 | // TODO: provide convenience function in MovingSprite or MovingObject? |
105 | for (int i = 0; i < 25; i++) { |
106 | Vector ppos = m_col.m_bbox.get_middle(); |
107 | float angle = graphicsRandom.randf(-math::PI_2, math::PI_2); |
108 | float velocity = graphicsRandom.randf(45, 90); |
109 | float vx = sinf(angle)*velocity; |
110 | float vy = -cosf(angle)*velocity; |
111 | Vector pspeed = Vector(vx, vy); |
112 | Vector paccel = Vector(0, Sector::get().get_gravity()*10); |
113 | Sector::get().add<SpriteParticle>("images/objects/particles/bark.sprite" , |
114 | "default" , |
115 | ppos, ANCHOR_MIDDLE, |
116 | pspeed, paccel, |
117 | LAYER_OBJECTS-1); |
118 | } |
119 | |
120 | return true; |
121 | |
122 | } |
123 | |
124 | //TODO: exception? |
125 | return true; |
126 | } |
127 | |
128 | void |
129 | Stumpy::collision_solid(const CollisionHit& hit) |
130 | { |
131 | update_on_ground_flag(hit); |
132 | |
133 | switch (mystate) { |
134 | case STATE_INVINCIBLE: |
135 | if (hit.top || hit.bottom) { |
136 | m_physic.set_velocity_y(0); |
137 | } |
138 | if (hit.left || hit.right) { |
139 | m_physic.set_velocity_x(0); |
140 | } |
141 | break; |
142 | case STATE_NORMAL: |
143 | WalkingBadguy::collision_solid(hit); |
144 | break; |
145 | } |
146 | } |
147 | |
148 | HitResponse |
149 | Stumpy::collision_badguy(BadGuy& badguy, const CollisionHit& hit) |
150 | { |
151 | switch (mystate) { |
152 | case STATE_INVINCIBLE: |
153 | if (hit.top || hit.bottom) { |
154 | m_physic.set_velocity_y(0); |
155 | } |
156 | if (hit.left || hit.right) { |
157 | m_physic.set_velocity_x(0); |
158 | } |
159 | return CONTINUE; |
160 | |
161 | case STATE_NORMAL: |
162 | return WalkingBadguy::collision_badguy(badguy, hit); |
163 | } |
164 | return CONTINUE; |
165 | } |
166 | |
167 | bool |
168 | Stumpy::is_freezable() const |
169 | { |
170 | return true; |
171 | } |
172 | |
173 | /* EOF */ |
174 | |