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
29static const float STUMPY_SPEED = 120;
30static const float INVINCIBLE_TIME = 1;
31
32Stumpy::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
43Stumpy::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
54void
55Stumpy::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
69void
70Stumpy::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
86bool
87Stumpy::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
128void
129Stumpy::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
148HitResponse
149Stumpy::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
167bool
168Stumpy::is_freezable() const
169{
170 return true;
171}
172
173/* EOF */
174