diff --git a/data/images/creatures/dive_mine/dive_mine.sprite b/data/images/creatures/dive_mine/dive_mine.sprite new file mode 100644 index 00000000000..8fc2fea1016 --- /dev/null +++ b/data/images/creatures/dive_mine/dive_mine.sprite @@ -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")) + +) diff --git a/data/images/creatures/dive_mine/left-0.png b/data/images/creatures/dive_mine/left-0.png new file mode 100644 index 00000000000..fcc72f8f1c8 Binary files /dev/null and b/data/images/creatures/dive_mine/left-0.png differ diff --git a/data/images/creatures/dive_mine/left-1.png b/data/images/creatures/dive_mine/left-1.png new file mode 100644 index 00000000000..ef5eacd38c4 Binary files /dev/null and b/data/images/creatures/dive_mine/left-1.png differ diff --git a/data/images/creatures/dive_mine/left-10.png b/data/images/creatures/dive_mine/left-10.png new file mode 100644 index 00000000000..a5d993172d5 Binary files /dev/null and b/data/images/creatures/dive_mine/left-10.png differ diff --git a/data/images/creatures/dive_mine/left-11.png b/data/images/creatures/dive_mine/left-11.png new file mode 100644 index 00000000000..8759577feae Binary files /dev/null and b/data/images/creatures/dive_mine/left-11.png differ diff --git a/data/images/creatures/dive_mine/left-2.png b/data/images/creatures/dive_mine/left-2.png new file mode 100644 index 00000000000..4e4a429c633 Binary files /dev/null and b/data/images/creatures/dive_mine/left-2.png differ diff --git a/data/images/creatures/dive_mine/left-3.png b/data/images/creatures/dive_mine/left-3.png new file mode 100644 index 00000000000..24883d82fb7 Binary files /dev/null and b/data/images/creatures/dive_mine/left-3.png differ diff --git a/data/images/creatures/dive_mine/left-4.png b/data/images/creatures/dive_mine/left-4.png new file mode 100644 index 00000000000..65aec8d71fa Binary files /dev/null and b/data/images/creatures/dive_mine/left-4.png differ diff --git a/data/images/creatures/dive_mine/left-5.png b/data/images/creatures/dive_mine/left-5.png new file mode 100644 index 00000000000..e4c7a7e0130 Binary files /dev/null and b/data/images/creatures/dive_mine/left-5.png differ diff --git a/data/images/creatures/dive_mine/left-6.png b/data/images/creatures/dive_mine/left-6.png new file mode 100644 index 00000000000..62e24139e21 Binary files /dev/null and b/data/images/creatures/dive_mine/left-6.png differ diff --git a/data/images/creatures/dive_mine/left-7.png b/data/images/creatures/dive_mine/left-7.png new file mode 100644 index 00000000000..b8636dd363b Binary files /dev/null and b/data/images/creatures/dive_mine/left-7.png differ diff --git a/data/images/creatures/dive_mine/left-8.png b/data/images/creatures/dive_mine/left-8.png new file mode 100644 index 00000000000..0841717904a Binary files /dev/null and b/data/images/creatures/dive_mine/left-8.png differ diff --git a/data/images/creatures/dive_mine/left-9.png b/data/images/creatures/dive_mine/left-9.png new file mode 100644 index 00000000000..190dff94907 Binary files /dev/null and b/data/images/creatures/dive_mine/left-9.png differ diff --git a/data/images/creatures/dive_mine/ticking-0.png b/data/images/creatures/dive_mine/ticking-0.png new file mode 100644 index 00000000000..ea1476b28fc Binary files /dev/null and b/data/images/creatures/dive_mine/ticking-0.png differ diff --git a/data/images/creatures/dive_mine/ticking-1.png b/data/images/creatures/dive_mine/ticking-1.png new file mode 100644 index 00000000000..79b3b6278a7 Binary files /dev/null and b/data/images/creatures/dive_mine/ticking-1.png differ diff --git a/data/images/creatures/dive_mine/ticking-2.png b/data/images/creatures/dive_mine/ticking-2.png new file mode 100644 index 00000000000..499e6c73265 Binary files /dev/null and b/data/images/creatures/dive_mine/ticking-2.png differ diff --git a/data/images/creatures/dive_mine/ticking-3.png b/data/images/creatures/dive_mine/ticking-3.png new file mode 100644 index 00000000000..7adf77f9535 Binary files /dev/null and b/data/images/creatures/dive_mine/ticking-3.png differ diff --git a/data/images/creatures/dive_mine/ticking-4.png b/data/images/creatures/dive_mine/ticking-4.png new file mode 100644 index 00000000000..0243d2299e3 Binary files /dev/null and b/data/images/creatures/dive_mine/ticking-4.png differ diff --git a/data/images/creatures/dive_mine/ticking-5.png b/data/images/creatures/dive_mine/ticking-5.png new file mode 100644 index 00000000000..059dbb976f8 Binary files /dev/null and b/data/images/creatures/dive_mine/ticking-5.png differ diff --git a/data/images/creatures/dive_mine/ticking-6.png b/data/images/creatures/dive_mine/ticking-6.png new file mode 100644 index 00000000000..4127d03d921 Binary files /dev/null and b/data/images/creatures/dive_mine/ticking-6.png differ diff --git a/data/images/creatures/dive_mine/ticking-7.png b/data/images/creatures/dive_mine/ticking-7.png new file mode 100644 index 00000000000..69b61bd7c74 Binary files /dev/null and b/data/images/creatures/dive_mine/ticking-7.png differ diff --git a/data/images/creatures/dive_mine/ticking-8.png b/data/images/creatures/dive_mine/ticking-8.png new file mode 100644 index 00000000000..e1bccbda977 Binary files /dev/null and b/data/images/creatures/dive_mine/ticking-8.png differ diff --git a/data/images/creatures/dive_mine/ticking-9.png b/data/images/creatures/dive_mine/ticking-9.png new file mode 100644 index 00000000000..1a2cc3851bf Binary files /dev/null and b/data/images/creatures/dive_mine/ticking-9.png differ diff --git a/data/images/creatures/dive_mine/ticking_glow/ticking_glow-0.png b/data/images/creatures/dive_mine/ticking_glow/ticking_glow-0.png new file mode 100644 index 00000000000..ffbecf47554 Binary files /dev/null and b/data/images/creatures/dive_mine/ticking_glow/ticking_glow-0.png differ diff --git a/data/images/creatures/dive_mine/ticking_glow/ticking_glow-1.png b/data/images/creatures/dive_mine/ticking_glow/ticking_glow-1.png new file mode 100644 index 00000000000..978ac9e9c02 Binary files /dev/null and b/data/images/creatures/dive_mine/ticking_glow/ticking_glow-1.png differ diff --git a/data/images/creatures/dive_mine/ticking_glow/ticking_glow-2.png b/data/images/creatures/dive_mine/ticking_glow/ticking_glow-2.png new file mode 100644 index 00000000000..e257091d111 Binary files /dev/null and b/data/images/creatures/dive_mine/ticking_glow/ticking_glow-2.png differ diff --git a/data/images/creatures/dive_mine/ticking_glow/ticking_glow-3.png b/data/images/creatures/dive_mine/ticking_glow/ticking_glow-3.png new file mode 100644 index 00000000000..93d58e23848 Binary files /dev/null and b/data/images/creatures/dive_mine/ticking_glow/ticking_glow-3.png differ diff --git a/data/images/creatures/dive_mine/ticking_glow/ticking_glow-4.png b/data/images/creatures/dive_mine/ticking_glow/ticking_glow-4.png new file mode 100644 index 00000000000..8e9527cb346 Binary files /dev/null and b/data/images/creatures/dive_mine/ticking_glow/ticking_glow-4.png differ diff --git a/data/images/creatures/dive_mine/ticking_glow/ticking_glow.sprite b/data/images/creatures/dive_mine/ticking_glow/ticking_glow.sprite new file mode 100644 index 00000000000..e1336b7e598 --- /dev/null +++ b/data/images/creatures/dive_mine/ticking_glow/ticking_glow.sprite @@ -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) + ) +) diff --git a/data/images/engine/editor/objects.stoi b/data/images/engine/editor/objects.stoi index 1db914bb094..5aaf6e284e4 100644 --- a/data/images/engine/editor/objects.stoi +++ b/data/images/engine/editor/objects.stoi @@ -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 diff --git a/src/badguy/dive_mine.cpp b/src/badguy/dive_mine.cpp new file mode 100644 index 00000000000..8b99adcb5c7 --- /dev/null +++ b/src/badguy/dive_mine.cpp @@ -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 . + +#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(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 */ diff --git a/src/badguy/dive_mine.hpp b/src/badguy/dive_mine.hpp new file mode 100644 index 00000000000..6fe8f50a9c7 --- /dev/null +++ b/src/badguy/dive_mine.hpp @@ -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 . + +#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 */ diff --git a/src/supertux/game_object_factory.cpp b/src/supertux/game_object_factory.cpp index 9d5e5273038..f1c1a611fdd 100644 --- a/src/supertux/game_object_factory.cpp +++ b/src/supertux/game_object_factory.cpp @@ -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" @@ -169,6 +170,7 @@ GameObjectFactory::init_factories() add_factory("dart", OBJ_PARAM_DISPENSABLE); add_factory("darttrap"); add_factory("dispenser", OBJ_PARAM_DISPENSABLE); + add_factory("dive-mine", OBJ_PARAM_DISPENSABLE); add_factory("fish-chasing", OBJ_PARAM_DISPENSABLE); add_factory("fish-harmless", OBJ_PARAM_DISPENSABLE); add_factory("fish"); // backward compatibility