Skip to content

Commit

Permalink
New Badguy: Dive Mine (#2495)
Browse files Browse the repository at this point in the history
Dive Mine is an underwater bomb enemy. They swim stationary, only very slightly moving up an down a few pixels.

If Tux gets into their trigger radius, their small headlight begins to blincking red (using their "ticking glow" sprites) and Dive Mine very, very slowly approaches him until either Tux leaves his trigger radius or he get touched by Dive Mine upon they will explode immediately.

Big thanks to @Vankata453 for the coding side! 👍
  • Loading branch information
Rusty-Box authored Jul 5, 2023
1 parent 5917b9a commit fbfc1e2
Show file tree
Hide file tree
Showing 33 changed files with 359 additions and 0 deletions.
58 changes: 58 additions & 0 deletions data/images/creatures/dive_mine/dive_mine.sprite
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
(supertux-sprite
(action
(name "left")
(fps 12.0)
(hitbox 14 19 32 32)
(images "left-0.png"
"left-1.png"
"left-2.png"
"left-3.png"
"left-4.png"
"left-5.png"
"left-6.png"
"left-7.png"
"left-8.png"
"left-9.png"
"left-10.png"
"left-11.png"))

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

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

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

(action
(name "ticking-left")
(fps 15.0)
(hitbox 14 19 32 32)
(images "ticking-0.png"
"ticking-1.png"
"ticking-2.png"
"ticking-3.png"
"ticking-4.png"
"ticking-5.png"
"ticking-6.png"
"ticking-7.png"
"ticking-8.png"
"ticking-9.png"
))


(action
(name "ticking-right")
(fps 15.0)
(hitbox 14 19 32 32)
(mirror-action "ticking-left"))

)
Binary file added data/images/creatures/dive_mine/left-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/dive_mine/left-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/dive_mine/left-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/dive_mine/left-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/dive_mine/left-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/dive_mine/left-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/dive_mine/left-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/dive_mine/left-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/dive_mine/left-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/dive_mine/left-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/dive_mine/left-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/dive_mine/left-9.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/dive_mine/ticking-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/dive_mine/ticking-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/dive_mine/ticking-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/dive_mine/ticking-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/dive_mine/ticking-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/dive_mine/ticking-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/dive_mine/ticking-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/dive_mine/ticking-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/dive_mine/ticking-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/dive_mine/ticking-9.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
19 changes: 19 additions & 0 deletions data/images/creatures/dive_mine/ticking_glow/ticking_glow.sprite
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
(supertux-sprite
(action
(name "idle")
(fps 15)
(images "ticking_glow-4.png")
(hitbox 48 48 0 0)
)

(action
(name "ticking")
(fps 15)
(images "ticking_glow-0.png"
"ticking_glow-1.png"
"ticking_glow-2.png"
"ticking_glow-3.png"
"ticking_glow-4.png")
(hitbox 48 48 0 0)
)
)
3 changes: 3 additions & 0 deletions data/images/engine/editor/objects.stoi
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@
(object
(class "ghoul")
(icon "images/creatures/ghoul/g1.png"))
(object
(class "dive-mine")
(icon "images/creatures/dive_mine/left-0.png"))
)

(objectgroup
Expand Down
207 changes: 207 additions & 0 deletions src/badguy/dive_mine.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
// SuperTux
// Copyright (C) 2023 Vankata453
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

#include "badguy/dive_mine.hpp"

#include "editor/editor.hpp"
#include "object/explosion.hpp"
#include "object/player.hpp"
#include "sprite/sprite.hpp"
#include "sprite/sprite_manager.hpp"
#include "supertux/sector.hpp"

const float DiveMine::s_trigger_radius = 100.f;
const float DiveMine::s_swim_speed = 20.f;
const float DiveMine::s_max_float_acceleration = 15.f;

DiveMine::DiveMine(const ReaderMapping& reader) :
BadGuy(reader, "images/creatures/dive_mine/dive_mine.sprite"),
m_ticking_glow(SpriteManager::current()->create("images/creatures/dive_mine/ticking_glow/ticking_glow.sprite")),
m_chasing(true)
{
reset_sprites();
}

void
DiveMine::reset_sprites()
{
set_action(m_dir);
m_ticking_glow->set_action("idle");
}

void
DiveMine::stop_chasing()
{
if (!m_chasing)
return;

m_physic.reset();
m_physic.set_velocity_y(1.f);
m_physic.set_acceleration_y(s_max_float_acceleration);

reset_sprites();
m_chasing = false;
}

void
DiveMine::explode()
{
remove_me();
Sector::get().add<Explosion>(m_col.m_bbox.get_middle(), EXPLOSION_STRENGTH_DEFAULT);
run_dead_script();
}

void
DiveMine::collision_solid(const CollisionHit& hit)
{
if (m_in_water)
{
if (hit.left || hit.right)
turn_around();
}
else
{
explode();
}
}

HitResponse
DiveMine::collision_badguy(BadGuy& badguy, const CollisionHit& hit)
{
if (!m_frozen &&
((hit.left && (m_dir == Direction::LEFT)) || (hit.right && (m_dir == Direction::RIGHT))))
{
turn_around();
}

BadGuy::collision_badguy(badguy, hit);
return CONTINUE;
}

HitResponse
DiveMine::collision_player(Player& player, const CollisionHit& hit)
{
if (!m_frozen)
explode();

return ABORT_MOVE;
}

void
DiveMine::draw(DrawingContext& context)
{
BadGuy::draw(context);

if (m_frozen || Editor::is_active())
return;

m_ticking_glow->set_blend(Blend::ADD);
m_ticking_glow->draw(context.light(),
Vector(m_col.m_bbox.get_left() + m_col.m_bbox.get_width() / 2,
m_col.m_bbox.get_top() - 8.f),
m_layer, m_flip);
}

void
DiveMine::active_update(float dt_sec)
{
BadGuy::active_update(dt_sec);

if (m_frozen || !m_in_water)
{
m_physic.enable_gravity(true);
return;
}
m_physic.enable_gravity(false);

// Update float cycles
if (!m_chasing)
{
if (std::abs(m_physic.get_acceleration_y()) > s_max_float_acceleration * 3)
m_physic.inverse_velocity_y();

m_physic.set_acceleration_y(m_physic.get_acceleration_y() + (s_max_float_acceleration / 25) * (m_physic.get_velocity_y() < 0.f ? 1 : -1));
}

// Detect if player is near
auto player = get_nearest_player();
if (player)
{
// Face the player
m_dir = (player->get_pos().x > get_pos().x) ? Direction::RIGHT : Direction::LEFT;
}

if (!player || !player->is_swimming())
{
stop_chasing();
return;
}

Vector dist = player->get_bbox().get_middle() - m_col.m_bbox.get_middle();
if (m_chasing)
{
if (glm::length(dist) > s_trigger_radius) // Player is out of trigger radius
{
stop_chasing();
return;
}

set_action("ticking", m_dir);
m_ticking_glow->set_action("ticking");

m_physic.set_velocity(glm::normalize(dist) * s_swim_speed);
}
else
{
set_action(m_dir);
m_chasing = (glm::length(dist) <= s_trigger_radius);
}
}

void
DiveMine::ignite()
{
explode();
}

void
DiveMine::freeze()
{
BadGuy::freeze();

m_physic.reset();
m_physic.set_velocity_y(1.f);
}

void
DiveMine::unfreeze(bool melt)
{
BadGuy::unfreeze();

m_chasing = true; // Ensure stop_chasing() will be executed
stop_chasing();
}

void
DiveMine::turn_around()
{
if (m_frozen || m_chasing)
return;

m_dir = (m_dir == Direction::LEFT ? Direction::RIGHT : Direction::LEFT);
}

/* EOF */
70 changes: 70 additions & 0 deletions src/badguy/dive_mine.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// SuperTux
// Copyright (C) 2023 Vankata453
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

#ifndef HEADER_SUPERTUX_BADGUY_DIVEMINE_HPP
#define HEADER_SUPERTUX_BADGUY_DIVEMINE_HPP

#include "badguy/badguy.hpp"

#include "sprite/sprite_ptr.hpp"

class DiveMine final : public BadGuy
{
private:
static const float s_trigger_radius;
static const float s_swim_speed;
static const float s_max_float_acceleration;

public:
DiveMine(const ReaderMapping& reader);

virtual void collision_solid(const CollisionHit& hit) override;
virtual HitResponse collision_badguy(BadGuy& badguy, const CollisionHit& hit) override;
virtual HitResponse collision_player(Player& player, const CollisionHit& hit) override;

virtual void draw(DrawingContext& context) override;
virtual void active_update(float dt_sec) override;

virtual void ignite() override;
virtual void freeze() override;
virtual void unfreeze(bool melt = true) override;
virtual bool is_freezable() const override { return true; }

static std::string class_name() { return "dive-mine"; }
virtual std::string get_class_name() const override { return class_name(); }
static std::string display_name() { return _("Dive Mine"); }
virtual std::string get_display_name() const override { return display_name(); }

private:
void reset_sprites();
void stop_chasing();

void explode();
void turn_around();

private:
SpritePtr m_ticking_glow;

bool m_chasing;

private:
DiveMine(const DiveMine&) = delete;
DiveMine& operator=(const DiveMine&) = delete;
};

#endif

/* EOF */
2 changes: 2 additions & 0 deletions src/supertux/game_object_factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "badguy/dart.hpp"
#include "badguy/darttrap.hpp"
#include "badguy/dispenser.hpp"
#include "badguy/dive_mine.hpp"
#include "badguy/fish_chasing.hpp"
#include "badguy/fish_harmless.hpp"
#include "badguy/fish_jumping.hpp"
Expand Down Expand Up @@ -169,6 +170,7 @@ GameObjectFactory::init_factories()
add_factory<Dart>("dart", OBJ_PARAM_DISPENSABLE);
add_factory<DartTrap>("darttrap");
add_factory<Dispenser>("dispenser", OBJ_PARAM_DISPENSABLE);
add_factory<DiveMine>("dive-mine", OBJ_PARAM_DISPENSABLE);
add_factory<FishChasing>("fish-chasing", OBJ_PARAM_DISPENSABLE);
add_factory<FishHarmless>("fish-harmless", OBJ_PARAM_DISPENSABLE);
add_factory<FishJumping>("fish"); // backward compatibility
Expand Down

0 comments on commit fbfc1e2

Please sign in to comment.