Skip to content

Commit

Permalink
Scared Gold Bomb (#2559)
Browse files Browse the repository at this point in the history
Gold Bomb will panic when Tux gets too close or any type of bomb is about to explode nearby.

They will run away for as long as Tux and/or a triggered bomb is in close range. If they reach a bottomless pit they "freeze" quivering in fear for as long as the "threat" is nearby (if there is safe ground they will drop down). When the area is all-clear, after a couple seconds, they will slowly resume their original behavior again.
  • Loading branch information
Rusty-Box authored Sep 2, 2023
1 parent 175c310 commit ff4dbe3
Show file tree
Hide file tree
Showing 25 changed files with 268 additions and 28 deletions.
Binary file added data/images/creatures/gold_bomb/flee-0.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added data/images/creatures/gold_bomb/flee-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added data/images/creatures/gold_bomb/flee-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added data/images/creatures/gold_bomb/flee-3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added data/images/creatures/gold_bomb/flee-4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added data/images/creatures/gold_bomb/flee-5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added data/images/creatures/gold_bomb/flee-6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added data/images/creatures/gold_bomb/flee-7.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
73 changes: 71 additions & 2 deletions data/images/creatures/gold_bomb/gold_bomb.sprite
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,83 @@
(hitbox 14 19 32 32)
(mirror-action "left"))

(action
(name "flee-left")
(fps 25.0)
(hitbox 14 19 32 32)
(images "flee-0.png"
"flee-1.png"
"flee-2.png"
"flee-3.png"
"flee-4.png"
"flee-5.png"
"flee-6.png"
"flee-7.png"))

(action
(name "flee-right")
(fps 25.0)
(hitbox 14 19 32 32)
(mirror-action "flee-left"))

(action
(name "scared-left")
(fps 25.0)
(hitbox 14 19 32 32)
(images "scared-0.png"
"scared-1.png"))

(action
(name "scared-right")
(fps 25.0)
(hitbox 14 19 32 32)
(mirror-action "scared-left"))

(action
(name "recover-left")
(fps 20.0)
(loops 1)
(hitbox 14 19 32 32)
(images "scared-2.png"
"scared-3.png"
"scared-4.png"
"scared-5.png"
"scared-6.png"
"scared-7.png"
"scared-4.png"
"scared-5.png"
"scared-6.png"
"scared-7.png"
"scared-8.png"
"scared-9.png"
"scared-9.png"
"scared-9.png"
"scared-9.png"
"scared-9.png"
"scared-10.png"
"scared-11.png"
"scared-11.png"
"scared-11.png"
"scared-11.png"
"scared-11.png"
"scared-10.png"
"scared-7.png"))

(action
(name "recover-right")
(fps 20.0)
(loops 1)
(hitbox 14 19 32 32)
(mirror-action "recover-left"))

(action
(name "iced-left")
(hitbox 5 8 32 32)
(hitbox 14 19 32 32)
(images "left-0.png"))

(action
(name "iced-right")
(hitbox 5 8 32 32)
(hitbox 14 19 32 32)
(mirror-action "iced-left"))

(action
Expand Down
Binary file added data/images/creatures/gold_bomb/scared-0.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added data/images/creatures/gold_bomb/scared-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added data/images/creatures/gold_bomb/scared-10.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added data/images/creatures/gold_bomb/scared-11.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added data/images/creatures/gold_bomb/scared-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added data/images/creatures/gold_bomb/scared-3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added data/images/creatures/gold_bomb/scared-4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added data/images/creatures/gold_bomb/scared-5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added data/images/creatures/gold_bomb/scared-6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added data/images/creatures/gold_bomb/scared-7.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added data/images/creatures/gold_bomb/scared-8.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added data/images/creatures/gold_bomb/scared-9.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
177 changes: 170 additions & 7 deletions src/badguy/goldbomb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@

#include "audio/sound_manager.hpp"
#include "audio/sound_source.hpp"
#include "badguy/bomb.hpp"
#include "badguy/haywire.hpp"
#include "badguy/owl.hpp"
#include "object/coin_explode.hpp"
#include "object/explosion.hpp"
Expand All @@ -29,14 +31,29 @@
#include "supertux/sector.hpp"
#include "util/reader_mapping.hpp"

static const float HOP_HEIGHT = -250.f;
static const float REALIZE_TIME = 0.5f;

// SAFE_DIST >= REALIZE_DIST
static const float REALIZE_DIST = 32.f * 8.f;
static const float SAFE_DIST = 32.f * 10.f;

static const float NORMAL_WALK_SPEED = 80.0f;
static const float FLEEING_WALK_SPEED = 180.0f;
static const int NORMAL_MAX_DROP_HEIGHT = 16;
static const int FLEEING_MAX_DROP_HEIGHT = 600;

GoldBomb::GoldBomb(const ReaderMapping& reader) :
WalkingBadguy(reader, "images/creatures/gold_bomb/gold_bomb.sprite", "left", "right"),
tstate(STATE_NORMAL),
m_realize_timer(),
ticking(),
m_exploding_sprite(SpriteManager::current()->create("images/creatures/mr_bomb/ticking_glow/ticking_glow.sprite"))
{
walk_speed = 80;
max_drop_height = 16;
assert(SAFE_DIST >= REALIZE_DIST);

walk_speed = NORMAL_WALK_SPEED;
max_drop_height = NORMAL_MAX_DROP_HEIGHT;

SoundManager::current()->preload("sounds/explosion.wav");

Expand All @@ -54,7 +71,11 @@ GoldBomb::collision_solid(const CollisionHit& hit)

update_on_ground_flag(hit);
return;
} else if (tstate != STATE_NORMAL && (hit.left || hit.right)) {
cornered();
return;
}

WalkingBadguy::collision_solid(hit);
}

Expand Down Expand Up @@ -94,9 +115,10 @@ GoldBomb::collision_badguy(BadGuy& badguy, const CollisionHit& hit)
{
if (tstate == STATE_TICKING)
{
if (m_physic.get_velocity() != Vector())
kill_fall();
if (m_physic.get_velocity() != Vector()) kill_fall();
return ABORT_MOVE;
} else if (tstate != STATE_NORMAL) {
return FORCE_MOVE;
}
return WalkingBadguy::collision_badguy(badguy, hit);
}
Expand All @@ -113,7 +135,7 @@ GoldBomb::collision_squished(GameObject& object)
kill_fall();
return true;
}
if (is_valid() && tstate == STATE_NORMAL) {
if (is_valid() && tstate != STATE_TICKING) {
tstate = STATE_TICKING;
m_frozen = false;
set_action(m_dir == Direction::LEFT ? "ticking-left" : "ticking-right", 1);
Expand Down Expand Up @@ -147,15 +169,122 @@ GoldBomb::active_update(float dt_sec)
}
return;
}
if (is_grabbed())

if ((tstate == STATE_FLEEING || tstate == STATE_CORNERED) && on_ground() && might_fall(FLEEING_MAX_DROP_HEIGHT+1))
{
// also check for STATE_CORNERED just so
// the bomb doesnt automatically turn around
cornered();
return;
}
WalkingBadguy::active_update(dt_sec);

if (m_frozen) return;

// Look for any of these in safe distance:
// Player, ticking Haywire, ticking Bomb or ticking GoldBomb
MovingObject* obj = nullptr;
std::vector<MovingObject*> objs = Sector::get().get_nearby_objects(get_bbox().get_middle(), SAFE_DIST);
for (MovingObject* currobj : objs)
{
obj = currobj;

auto player = dynamic_cast<Player*>(obj);
if (player && !player->get_ghost_mode()) break;

auto haywire = dynamic_cast<Haywire*>(obj);
if (haywire && haywire->is_exploding()) break;

auto bomb = dynamic_cast<Bomb*>(obj);
if (bomb) break;

auto goldbomb = dynamic_cast<GoldBomb*>(obj);
if (goldbomb && goldbomb->is_ticking()) break;

obj = nullptr;
}

if (!obj)
{
// Everybody's outside of safe distance. Am I cornered?

if (tstate == STATE_CORNERED)
{
// Look back to check.
set_action("recover", m_dir);
if (!m_sprite->animation_done()) return;
}

// Finally, when done recovering, go back to normal.
if (tstate == STATE_NORMAL) return;

tstate = STATE_NORMAL;
m_physic.set_velocity_x(NORMAL_WALK_SPEED * (m_dir == Direction::LEFT ? -1 : 1));
m_physic.set_acceleration_x(0);
set_action(m_dir);
max_drop_height = NORMAL_MAX_DROP_HEIGHT;
set_walk_speed(NORMAL_WALK_SPEED);
return;
}

// Someone's in safe distance
const Vector p1 = get_bbox().get_middle();
const Vector p2 = obj->get_bbox().get_middle();
const Vector vecdist = p2-p1;

// But I only react to those who are in realize distance
if (glm::length(vecdist) > REALIZE_DIST && tstate == STATE_NORMAL) return;

// Someone's around!
switch (tstate)
{
case STATE_FLEEING:
// They popped up from the other side! Turn around!
if (m_dir == (vecdist.x > 0 ? Direction::LEFT : Direction::RIGHT)) return;
[[fallthrough]];

case STATE_NORMAL:
{
if (!on_ground()) break;

// Gold bomb is solid therefore raycast from
// one of the upper corners of the hitbox.
// (grown 1 just to make sure it doesnt interfere.)
const Rectf eye = get_bbox().grown(1.f);
if (!Sector::get().free_line_of_sight(
vecdist.x <= 0 ? eye.p1() : Vector(eye.get_right(), eye.get_top()),
obj->get_bbox().get_middle(),
false,
obj
)) break;

// Hop before fleeing.
set_walk_speed(0);
m_physic.set_velocity_y(HOP_HEIGHT);
m_physic.set_velocity_x(0);
m_physic.set_acceleration_x(0);
m_dir = vecdist.x > 0 ? Direction::RIGHT : Direction::LEFT;
m_sprite->set_action("flee", m_dir);
tstate = STATE_REALIZING;
m_realize_timer.start(REALIZE_TIME);
break;
}

case STATE_REALIZING:
if (!m_realize_timer.check()) break;

flee(vecdist.x > 0 ? Direction::LEFT : Direction::RIGHT);
break;

default: break;
}
}

void
GoldBomb::draw(DrawingContext& context)
{
m_sprite->draw(context.color(), get_pos(), m_layer, m_flip);

if (tstate == STATE_TICKING)
{
m_exploding_sprite->set_blend(Blend::ADD);
Expand Down Expand Up @@ -267,7 +396,8 @@ GoldBomb::ungrab(MovingObject& object, Direction dir_)
void
GoldBomb::freeze()
{
if (tstate == STATE_NORMAL) {
if (tstate != STATE_TICKING) {
tstate = STATE_NORMAL;
WalkingBadguy::freeze();
}
}
Expand Down Expand Up @@ -298,4 +428,37 @@ void GoldBomb::play_looping_sounds()
}
}

void
GoldBomb::flee(Direction dir)
{
set_walk_speed(FLEEING_WALK_SPEED);
max_drop_height = FLEEING_MAX_DROP_HEIGHT;
m_dir = dir;

const float speed = FLEEING_WALK_SPEED * (m_dir == Direction::LEFT ? -1 : 1);
m_physic.set_acceleration_x(speed);
m_physic.set_velocity_x(speed);

if (get_action() == dir_to_string(m_dir))
m_sprite->set_animation_loops(-1);
else
set_action("flee", m_dir);

tstate = STATE_FLEEING;
}

void
GoldBomb::cornered()
{
if (tstate == STATE_CORNERED) return;

set_walk_speed(0);
m_physic.set_velocity_x(0);
m_physic.set_acceleration_x(0);

set_action("scared", m_dir);

tstate = STATE_CORNERED;
}

/* EOF */
13 changes: 11 additions & 2 deletions src/badguy/goldbomb.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,17 +54,26 @@ class GoldBomb final : public WalkingBadguy
virtual void stop_looping_sounds() override;
virtual void play_looping_sounds() override;

bool is_ticking() const { return tstate == STATE_TICKING; }

protected:
virtual bool collision_squished(GameObject& object) override;

private:
void flee(Direction dir);
void cornered();

private:
enum Ticking_State {
STATE_NORMAL,
STATE_TICKING
STATE_TICKING,
STATE_REALIZING,
STATE_FLEEING,
STATE_CORNERED
};

private:
Ticking_State tstate;
Timer m_realize_timer;

std::unique_ptr<SoundSource> ticking;
SpritePtr m_exploding_sprite;
Expand Down
Loading

0 comments on commit ff4dbe3

Please sign in to comment.