diff -Nru supertux-0.6.3/CMakeLists.txt supertux-0.6.3/CMakeLists.txt --- supertux-0.6.3/CMakeLists.txt 2023-07-05 19:46:58.000000000 +0000 +++ supertux-0.6.3/CMakeLists.txt 2023-07-06 19:47:30.000000000 +0000 @@ -157,6 +157,7 @@ if(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") add_definitions(-DMACOSX) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L/usr/local/lib") endif() ## Add lots of dependencies to compiler switches diff -Nru supertux-0.6.3/data/images/creatures/dive_mine/dive_mine.sprite supertux-0.6.3/data/images/creatures/dive_mine/dive_mine.sprite --- supertux-0.6.3/data/images/creatures/dive_mine/dive_mine.sprite 1970-01-01 00:00:00.000000000 +0000 +++ supertux-0.6.3/data/images/creatures/dive_mine/dive_mine.sprite 2023-07-06 19:47:30.000000000 +0000 @@ -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 files /tmp/tmphjcrv065/cUymx0il7W/supertux-0.6.3/data/images/creatures/dive_mine/left-0.png and /tmp/tmphjcrv065/3gj1eNIu6Q/supertux-0.6.3/data/images/creatures/dive_mine/left-0.png differ Binary files /tmp/tmphjcrv065/cUymx0il7W/supertux-0.6.3/data/images/creatures/dive_mine/left-10.png and /tmp/tmphjcrv065/3gj1eNIu6Q/supertux-0.6.3/data/images/creatures/dive_mine/left-10.png differ Binary files /tmp/tmphjcrv065/cUymx0il7W/supertux-0.6.3/data/images/creatures/dive_mine/left-11.png and /tmp/tmphjcrv065/3gj1eNIu6Q/supertux-0.6.3/data/images/creatures/dive_mine/left-11.png differ Binary files /tmp/tmphjcrv065/cUymx0il7W/supertux-0.6.3/data/images/creatures/dive_mine/left-1.png and /tmp/tmphjcrv065/3gj1eNIu6Q/supertux-0.6.3/data/images/creatures/dive_mine/left-1.png differ Binary files /tmp/tmphjcrv065/cUymx0il7W/supertux-0.6.3/data/images/creatures/dive_mine/left-2.png and /tmp/tmphjcrv065/3gj1eNIu6Q/supertux-0.6.3/data/images/creatures/dive_mine/left-2.png differ Binary files /tmp/tmphjcrv065/cUymx0il7W/supertux-0.6.3/data/images/creatures/dive_mine/left-3.png and /tmp/tmphjcrv065/3gj1eNIu6Q/supertux-0.6.3/data/images/creatures/dive_mine/left-3.png differ Binary files /tmp/tmphjcrv065/cUymx0il7W/supertux-0.6.3/data/images/creatures/dive_mine/left-4.png and /tmp/tmphjcrv065/3gj1eNIu6Q/supertux-0.6.3/data/images/creatures/dive_mine/left-4.png differ Binary files /tmp/tmphjcrv065/cUymx0il7W/supertux-0.6.3/data/images/creatures/dive_mine/left-5.png and /tmp/tmphjcrv065/3gj1eNIu6Q/supertux-0.6.3/data/images/creatures/dive_mine/left-5.png differ Binary files /tmp/tmphjcrv065/cUymx0il7W/supertux-0.6.3/data/images/creatures/dive_mine/left-6.png and /tmp/tmphjcrv065/3gj1eNIu6Q/supertux-0.6.3/data/images/creatures/dive_mine/left-6.png differ Binary files /tmp/tmphjcrv065/cUymx0il7W/supertux-0.6.3/data/images/creatures/dive_mine/left-7.png and /tmp/tmphjcrv065/3gj1eNIu6Q/supertux-0.6.3/data/images/creatures/dive_mine/left-7.png differ Binary files /tmp/tmphjcrv065/cUymx0il7W/supertux-0.6.3/data/images/creatures/dive_mine/left-8.png and /tmp/tmphjcrv065/3gj1eNIu6Q/supertux-0.6.3/data/images/creatures/dive_mine/left-8.png differ Binary files /tmp/tmphjcrv065/cUymx0il7W/supertux-0.6.3/data/images/creatures/dive_mine/left-9.png and /tmp/tmphjcrv065/3gj1eNIu6Q/supertux-0.6.3/data/images/creatures/dive_mine/left-9.png differ Binary files /tmp/tmphjcrv065/cUymx0il7W/supertux-0.6.3/data/images/creatures/dive_mine/ticking-0.png and /tmp/tmphjcrv065/3gj1eNIu6Q/supertux-0.6.3/data/images/creatures/dive_mine/ticking-0.png differ Binary files /tmp/tmphjcrv065/cUymx0il7W/supertux-0.6.3/data/images/creatures/dive_mine/ticking-1.png and /tmp/tmphjcrv065/3gj1eNIu6Q/supertux-0.6.3/data/images/creatures/dive_mine/ticking-1.png differ Binary files /tmp/tmphjcrv065/cUymx0il7W/supertux-0.6.3/data/images/creatures/dive_mine/ticking-2.png and /tmp/tmphjcrv065/3gj1eNIu6Q/supertux-0.6.3/data/images/creatures/dive_mine/ticking-2.png differ Binary files /tmp/tmphjcrv065/cUymx0il7W/supertux-0.6.3/data/images/creatures/dive_mine/ticking-3.png and /tmp/tmphjcrv065/3gj1eNIu6Q/supertux-0.6.3/data/images/creatures/dive_mine/ticking-3.png differ Binary files /tmp/tmphjcrv065/cUymx0il7W/supertux-0.6.3/data/images/creatures/dive_mine/ticking-4.png and /tmp/tmphjcrv065/3gj1eNIu6Q/supertux-0.6.3/data/images/creatures/dive_mine/ticking-4.png differ Binary files /tmp/tmphjcrv065/cUymx0il7W/supertux-0.6.3/data/images/creatures/dive_mine/ticking-5.png and /tmp/tmphjcrv065/3gj1eNIu6Q/supertux-0.6.3/data/images/creatures/dive_mine/ticking-5.png differ Binary files /tmp/tmphjcrv065/cUymx0il7W/supertux-0.6.3/data/images/creatures/dive_mine/ticking-6.png and /tmp/tmphjcrv065/3gj1eNIu6Q/supertux-0.6.3/data/images/creatures/dive_mine/ticking-6.png differ Binary files /tmp/tmphjcrv065/cUymx0il7W/supertux-0.6.3/data/images/creatures/dive_mine/ticking-7.png and /tmp/tmphjcrv065/3gj1eNIu6Q/supertux-0.6.3/data/images/creatures/dive_mine/ticking-7.png differ Binary files /tmp/tmphjcrv065/cUymx0il7W/supertux-0.6.3/data/images/creatures/dive_mine/ticking-8.png and /tmp/tmphjcrv065/3gj1eNIu6Q/supertux-0.6.3/data/images/creatures/dive_mine/ticking-8.png differ Binary files /tmp/tmphjcrv065/cUymx0il7W/supertux-0.6.3/data/images/creatures/dive_mine/ticking-9.png and /tmp/tmphjcrv065/3gj1eNIu6Q/supertux-0.6.3/data/images/creatures/dive_mine/ticking-9.png differ Binary files /tmp/tmphjcrv065/cUymx0il7W/supertux-0.6.3/data/images/creatures/dive_mine/ticking_glow/ticking_glow-0.png and /tmp/tmphjcrv065/3gj1eNIu6Q/supertux-0.6.3/data/images/creatures/dive_mine/ticking_glow/ticking_glow-0.png differ Binary files /tmp/tmphjcrv065/cUymx0il7W/supertux-0.6.3/data/images/creatures/dive_mine/ticking_glow/ticking_glow-1.png and /tmp/tmphjcrv065/3gj1eNIu6Q/supertux-0.6.3/data/images/creatures/dive_mine/ticking_glow/ticking_glow-1.png differ Binary files /tmp/tmphjcrv065/cUymx0il7W/supertux-0.6.3/data/images/creatures/dive_mine/ticking_glow/ticking_glow-2.png and /tmp/tmphjcrv065/3gj1eNIu6Q/supertux-0.6.3/data/images/creatures/dive_mine/ticking_glow/ticking_glow-2.png differ Binary files /tmp/tmphjcrv065/cUymx0il7W/supertux-0.6.3/data/images/creatures/dive_mine/ticking_glow/ticking_glow-3.png and /tmp/tmphjcrv065/3gj1eNIu6Q/supertux-0.6.3/data/images/creatures/dive_mine/ticking_glow/ticking_glow-3.png differ Binary files /tmp/tmphjcrv065/cUymx0il7W/supertux-0.6.3/data/images/creatures/dive_mine/ticking_glow/ticking_glow-4.png and /tmp/tmphjcrv065/3gj1eNIu6Q/supertux-0.6.3/data/images/creatures/dive_mine/ticking_glow/ticking_glow-4.png differ diff -Nru supertux-0.6.3/data/images/creatures/dive_mine/ticking_glow/ticking_glow.sprite supertux-0.6.3/data/images/creatures/dive_mine/ticking_glow/ticking_glow.sprite --- supertux-0.6.3/data/images/creatures/dive_mine/ticking_glow/ticking_glow.sprite 1970-01-01 00:00:00.000000000 +0000 +++ supertux-0.6.3/data/images/creatures/dive_mine/ticking_glow/ticking_glow.sprite 2023-07-06 19:47:30.000000000 +0000 @@ -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 -Nru supertux-0.6.3/data/images/engine/editor/objects.stoi supertux-0.6.3/data/images/engine/editor/objects.stoi --- supertux-0.6.3/data/images/engine/editor/objects.stoi 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/data/images/engine/editor/objects.stoi 2023-07-06 19:47:30.000000000 +0000 @@ -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 -Nru supertux-0.6.3/debian/changelog supertux-0.6.3/debian/changelog --- supertux-0.6.3/debian/changelog 2023-07-05 19:47:55.000000000 +0000 +++ supertux-0.6.3/debian/changelog 2023-07-06 19:48:39.000000000 +0000 @@ -1,8 +1,8 @@ -supertux (0.6.3-2~git202307051947+17~ubuntu18.04.1) bionic; urgency=low +supertux (0.6.3-2~git202307061948+17~ubuntu18.04.1) bionic; urgency=low * Auto build. - -- Launchpad Package Builder Wed, 05 Jul 2023 19:47:55 +0000 + -- Launchpad Package Builder Thu, 06 Jul 2023 19:48:39 +0000 supertux (0.6.3) UNRELEASED; urgency=low diff -Nru supertux-0.6.3/debian/git-build-recipe.manifest supertux-0.6.3/debian/git-build-recipe.manifest --- supertux-0.6.3/debian/git-build-recipe.manifest 2023-07-05 19:47:55.000000000 +0000 +++ supertux-0.6.3/debian/git-build-recipe.manifest 2023-07-06 19:48:39.000000000 +0000 @@ -1,5 +1,5 @@ -# git-build-recipe format 0.4 deb-version {debupstream}-2~git202307051947+17 -lp:~supertux-dev/supertux/+git/github-clone git-commit:1414696cc7648786794ce4c708cf76f3f585c6e4 +# git-build-recipe format 0.4 deb-version {debupstream}-2~git202307061948+17 +lp:~supertux-dev/supertux/+git/github-clone git-commit:d78c56b917e702e5b0ba6e3c60a2588c16b01549 nest-part packaging lp:~supertux-dev/supertux/+git/supertux-debian debian debian git-commit:30d6625a450dd04d0a75f7ecf85fda0a8fc2acaa nest physfs lp:~supertux-dev/supertux/+git/external-physfs external/physfs git-commit:9bac3bc908b19997b301cc77f03008a90df55885 nest sexp-cpp lp:~supertux-dev/supertux/+git/external-sexp-cpp external/sexp-cpp git-commit:6018831abc1e5d5020c7b62f99962806dacf4c9f diff -Nru supertux-0.6.3/.github/workflows/macos.yml supertux-0.6.3/.github/workflows/macos.yml --- supertux-0.6.3/.github/workflows/macos.yml 2023-07-05 19:46:58.000000000 +0000 +++ supertux-0.6.3/.github/workflows/macos.yml 2023-07-06 19:47:30.000000000 +0000 @@ -81,8 +81,7 @@ -DWARNINGS=ON -DWERROR=ON -DGLBINDING_ENABLED=$GLBINDING \ -DENABLE_DISCORD=ON -DCMAKE_INSTALL_MESSAGE=NEVER \ -DCMAKE_INSTALL_PREFIX=/usr -DINSTALL_SUBDIR_BIN=bin \ - -DINSTALL_SUBDIR_SHARE=share/supertux2 -DBUILD_TESTS=ON \ - -DCMAKE_EXE_LINKER_FLAGS="-L/usr/local/lib" + -DINSTALL_SUBDIR_SHARE=share/supertux2 -DBUILD_TESTS=ON - name: Build and install working-directory: build diff -Nru supertux-0.6.3/.pc/.quilt_patches supertux-0.6.3/.pc/.quilt_patches --- supertux-0.6.3/.pc/.quilt_patches 2023-07-05 19:47:55.000000000 +0000 +++ supertux-0.6.3/.pc/.quilt_patches 2023-07-06 19:48:39.000000000 +0000 @@ -1 +1 @@ -/home/buildd/build-RECIPEBRANCHBUILD-3568915/chroot-autobuild/home/buildd/work/tree/recipe/debian/patches +/home/buildd/build-RECIPEBRANCHBUILD-3569372/chroot-autobuild/home/buildd/work/tree/recipe/debian/patches diff -Nru supertux-0.6.3/.pc/.quilt_series supertux-0.6.3/.pc/.quilt_series --- supertux-0.6.3/.pc/.quilt_series 2023-07-05 19:47:55.000000000 +0000 +++ supertux-0.6.3/.pc/.quilt_series 2023-07-06 19:48:39.000000000 +0000 @@ -1 +1 @@ -/home/buildd/build-RECIPEBRANCHBUILD-3568915/chroot-autobuild/home/buildd/work/tree/recipe/debian/patches/series +/home/buildd/build-RECIPEBRANCHBUILD-3569372/chroot-autobuild/home/buildd/work/tree/recipe/debian/patches/series diff -Nru supertux-0.6.3/src/badguy/badguy.cpp supertux-0.6.3/src/badguy/badguy.cpp --- supertux-0.6.3/src/badguy/badguy.cpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/badguy/badguy.cpp 2023-07-06 19:47:31.000000000 +0000 @@ -65,7 +65,6 @@ m_lightsprite(SpriteManager::current()->create(light_sprite_name)), m_freezesprite(SpriteManager::current()->create(ice_sprite_name)), m_glowing(false), - m_parent_dispenser(), m_state(STATE_INIT), m_is_active_flag(), m_state_timer(), @@ -102,7 +101,6 @@ m_lightsprite(SpriteManager::current()->create(light_sprite_name)), m_freezesprite(SpriteManager::current()->create(ice_sprite_name)), m_glowing(false), - m_parent_dispenser(), m_state(STATE_INIT), m_is_active_flag(), m_state_timer(), @@ -225,6 +223,7 @@ case STATE_INIT: case STATE_INACTIVE: m_is_active_flag = false; + m_in_water = !Sector::get().is_free_of_tiles(m_col.get_bbox(), false, Tile::WATER); inactive_update(dt_sec); try_activate(); break; diff -Nru supertux-0.6.3/src/badguy/badguy.hpp supertux-0.6.3/src/badguy/badguy.hpp --- supertux-0.6.3/src/badguy/badguy.hpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/badguy/badguy.hpp 2023-07-06 19:47:31.000000000 +0000 @@ -26,7 +26,6 @@ #include "supertux/physic.hpp" #include "supertux/timer.hpp" -class Dispenser; class Player; class Bullet; @@ -133,13 +132,6 @@ set_action(action, loops); } - /** Sets the dispenser that spawns this badguy. - @param parent The dispenser */ - void set_parent_dispenser(Dispenser* parent) { m_parent_dispenser = parent; } - - /** Returns the dispenser this badguys was spawned by */ - Dispenser* get_parent_dispenser() const { return m_parent_dispenser; } - /** Returns true if the badguy can currently be affected by wind */ virtual bool can_be_affected_by_wind() const; @@ -278,10 +270,6 @@ SpritePtr m_freezesprite; bool m_glowing; - /** If this badguy was dispensed from a dispenser, - save the dispenser here. */ - Dispenser* m_parent_dispenser; - private: State m_state; diff -Nru supertux-0.6.3/src/badguy/dispenser.cpp supertux-0.6.3/src/badguy/dispenser.cpp --- supertux-0.6.3/src/badguy/dispenser.cpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/badguy/dispenser.cpp 2023-07-06 19:47:31.000000000 +0000 @@ -25,14 +25,15 @@ #include "supertux/flip_level_transformer.hpp" #include "supertux/game_object_factory.hpp" #include "supertux/sector.hpp" +#include "util/reader_iterator.hpp" #include "util/reader_mapping.hpp" Dispenser::Dispenser(const ReaderMapping& reader) : BadGuy(reader, "images/creatures/dispenser/dropper.sprite"), ExposedObject(this), m_cycle(), - m_badguys(), - m_next_badguy(0), + m_objects(), + m_next_object(0), m_dispense_timer(), m_autotarget(false), m_random(), @@ -47,9 +48,25 @@ SoundManager::current()->preload("sounds/squish.wav"); reader.get("cycle", m_cycle, 5.0f); if (reader.get("gravity", m_gravity)) m_physic.enable_gravity(true); - if (!reader.get("badguy", m_badguys)) m_badguys.clear(); reader.get("random", m_random, false); + std::vector badguys; + if (reader.get("badguy", badguys)) // Backward compatibility + { + for (auto& badguy : badguys) + add_object(GameObjectFactory::instance().create(badguy)); + } + else + { + std::optional objects_mapping; + if (reader.get("objects", objects_mapping)) + { + auto iter = objects_mapping->get_iter(); + while (iter.next()) + add_object(GameObjectFactory::instance().create(iter.get_key(), iter.as_mapping())); + } + } + m_dir = m_start_dir; // Reset direction to default. reader.get("limit-dispensed-badguys", m_limit_dispensed_badguys, false); @@ -65,6 +82,21 @@ } void +Dispenser::add_object(std::unique_ptr object) +{ + auto moving_object = dynamic_cast(object.get()); + if (!GameObjectFactory::instance().has_params(object->get_class_name(), ObjectFactory::RegisteredObjectParam::OBJ_PARAM_DISPENSABLE) || + !moving_object) // Object is not MovingObject, or is not dispensable + { + log_warning << object->get_class_name() << " is not dispensable. Removing from dispenser object list." << std::endl; + return; + } + + moving_object->set_parent_dispenser(this); + m_objects.push_back(std::move(object)); +} + +void Dispenser::draw(DrawingContext& context) { if (m_type != DispenserType::POINT || Editor::is_active()) @@ -81,7 +113,7 @@ Dispenser::activate() { m_dispense_timer.start(m_cycle, true); - launch_badguy(); + launch_object(); } void @@ -123,18 +155,15 @@ } } } - launch_badguy(); + launch_object(); } } void -Dispenser::launch_badguy() +Dispenser::launch_object() { - if (m_badguys.empty()) return; + if (m_objects.empty()) return; if (m_frozen) return; - if (m_limit_dispensed_badguys && - m_current_badguys >= m_max_concurrent_badguys) - return; //FIXME: Does is_offscreen() work right here? if (!is_offscreen() && !Editor::is_active()) @@ -147,45 +176,43 @@ launch_dir = (player->get_pos().x > get_pos().x) ? Direction::RIGHT : Direction::LEFT; } - if (m_badguys.size() > 1) + if (m_objects.size() > 1) { if (m_random) { - m_next_badguy = static_cast(gameRandom.rand(static_cast(m_badguys.size()))); + m_next_object = static_cast(gameRandom.rand(static_cast(m_objects.size()))); } else { - m_next_badguy++; + m_next_object++; - if (m_next_badguy >= m_badguys.size()) - m_next_badguy = 0; + if (m_next_object >= m_objects.size()) + m_next_object = 0; } } - std::string badguy = m_badguys[m_next_badguy]; - - if (badguy == "random") - { - log_warning << "random is outdated; use a list of badguys to select from." << std::endl; - return; - } - if (badguy == "goldbomb") + auto object = m_objects[m_next_object].get(); + auto obj_badguy = dynamic_cast(object); + if (obj_badguy && m_limit_dispensed_badguys && + m_current_badguys >= m_max_concurrent_badguys) { - log_warning << "goldbomb is not allowed to be dispensed" << std::endl; + // The object is a badguy and max concurrent badguys limit has been reached. + // Do not dispense. return; } - try { - //Need to allocate the badguy first to figure out its bounding box. - auto game_object = GameObjectFactory::instance().create(badguy, get_pos(), launch_dir); - if (game_object == nullptr) - throw std::runtime_error("Creating " + badguy + " object failed."); - - auto& bad_guy = dynamic_cast(*game_object); - - Rectf object_bbox = bad_guy.get_bbox(); + try + { + auto game_object = GameObjectFactory::instance().create(object->get_class_name(), get_pos(), launch_dir, object->save()); + if (!game_object) + { + throw std::runtime_error("Creating " + object->get_class_name() + " object failed."); + } + auto moving_object = dynamic_cast(game_object.get()); + Rectf object_bbox = moving_object->get_bbox(); Vector spawnpoint(0.0f, 0.0f); + switch (m_type) { case DispenserType::DROPPER: @@ -221,21 +248,27 @@ } /* Now we set the real spawn position */ - bad_guy.set_pos(spawnpoint); + moving_object->set_pos(spawnpoint); - /* We don't want to count dispensed badguys in level stats */ - bad_guy.m_countMe = false; + /* Set reference to dispenser in the object itself */ + moving_object->set_parent_dispenser(this); - /* Set reference to dispenser in badguy itself */ - if (m_limit_dispensed_badguys) + if (obj_badguy) // The object is a badguy { - bad_guy.set_parent_dispenser(this); - m_current_badguys++; + auto badguy = dynamic_cast(moving_object); + + /* We don't want to count dispensed badguys in level stats */ + badguy->m_countMe = false; + + if (m_limit_dispensed_badguys) + m_current_badguys++; } Sector::get().add_object(std::move(game_object)); - } catch(const std::exception& e) { - log_warning << "Error dispensing badguy: " << e.what() << std::endl; + } + catch(const std::exception& e) + { + log_warning << "Error dispensing object: " << e.what() << std::endl; return; } } @@ -339,7 +372,7 @@ result.add_float(_("Interval (seconds)"), &m_cycle, "cycle"); result.add_bool(_("Random"), &m_random, "random", false); - result.add_badguy(_("Enemies"), &m_badguys, "badguy"); + result.add_objects(_("Objects"), &m_objects, this, "objects"); result.add_bool(_("Limit dispensed badguys"), &m_limit_dispensed_badguys, "limit-dispensed-badguys", false); result.add_bool(_("Obey Gravity"), &m_gravity, @@ -347,7 +380,7 @@ result.add_int(_("Max concurrent badguys"), &m_max_concurrent_badguys, "max-concurrent-badguys", 0); - result.reorder({"cycle", "random", "type", "badguy", "direction", "gravity", "limit-dispensed-badguys", "max-concurrent-badguys", "x", "y"}); + result.reorder({"cycle", "random", "type", "objects", "direction", "gravity", "limit-dispensed-badguys", "max-concurrent-badguys", "x", "y"}); return result; } diff -Nru supertux-0.6.3/src/badguy/dispenser.hpp supertux-0.6.3/src/badguy/dispenser.hpp --- supertux-0.6.3/src/badguy/dispenser.hpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/badguy/dispenser.hpp 2023-07-06 19:47:31.000000000 +0000 @@ -21,6 +21,8 @@ #include "scripting/dispenser.hpp" #include "squirrel/exposed_object.hpp" +class GameObject; + class Dispenser final : public BadGuy, public ExposedObject { @@ -32,6 +34,8 @@ public: Dispenser(const ReaderMapping& reader); + void add_object(std::unique_ptr object); + virtual void draw(DrawingContext& context) override; virtual void initialize() override; virtual void activate() override; @@ -72,7 +76,7 @@ protected: virtual HitResponse collision(GameObject& other, const CollisionHit& hit) override; - void launch_badguy(); + void launch_object(); void on_type_change(int old_type) override; @@ -81,8 +85,8 @@ private: float m_cycle; - std::vector m_badguys; - unsigned int m_next_badguy; + std::vector> m_objects; + unsigned int m_next_object; Timer m_dispense_timer; bool m_autotarget; bool m_random; diff -Nru supertux-0.6.3/src/badguy/dive_mine.cpp supertux-0.6.3/src/badguy/dive_mine.cpp --- supertux-0.6.3/src/badguy/dive_mine.cpp 1970-01-01 00:00:00.000000000 +0000 +++ supertux-0.6.3/src/badguy/dive_mine.cpp 2023-07-06 19:47:31.000000000 +0000 @@ -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 -Nru supertux-0.6.3/src/badguy/dive_mine.hpp supertux-0.6.3/src/badguy/dive_mine.hpp --- supertux-0.6.3/src/badguy/dive_mine.hpp 1970-01-01 00:00:00.000000000 +0000 +++ supertux-0.6.3/src/badguy/dive_mine.hpp 2023-07-06 19:47:31.000000000 +0000 @@ -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 -Nru supertux-0.6.3/src/badguy/fish_jumping.cpp supertux-0.6.3/src/badguy/fish_jumping.cpp --- supertux-0.6.3/src/badguy/fish_jumping.cpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/badguy/fish_jumping.cpp 2023-07-06 19:47:31.000000000 +0000 @@ -16,6 +16,7 @@ #include "badguy/fish_jumping.hpp" +#include "audio/sound_manager.hpp" #include "object/explosion.hpp" #include "sprite/sprite.hpp" #include "supertux/sector.hpp" @@ -80,6 +81,7 @@ if (!m_frozen) start_waiting(); m_col.set_movement(Vector(0, 0)); + SoundManager::current()->play("sounds/splash.ogg", get_pos()); } } if ((!(tile_attributes & Tile::WATER) || m_frozen) && (tile_attributes & Tile::HURTS)) { diff -Nru supertux-0.6.3/src/badguy/goldbomb.cpp supertux-0.6.3/src/badguy/goldbomb.cpp --- supertux-0.6.3/src/badguy/goldbomb.cpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/badguy/goldbomb.cpp 2023-07-06 19:47:31.000000000 +0000 @@ -195,7 +195,7 @@ EXPLOSION_STRENGTH_DEFAULT); run_dead_script(); } - Sector::get().add(get_pos() + Vector(0, -40)); + Sector::get().add(get_pos() + Vector(0, -40), !m_parent_dispenser); } } diff -Nru supertux-0.6.3/src/editor/layers_widget.cpp supertux-0.6.3/src/editor/layers_widget.cpp --- supertux-0.6.3/src/editor/layers_widget.cpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/editor/layers_widget.cpp 2023-07-06 19:47:31.000000000 +0000 @@ -199,7 +199,7 @@ else if (button.button == SDL_BUTTON_RIGHT) { if (m_hovered_item == HoveredItem::LAYERS && m_hovered_layer < m_layer_icons.size()) { - auto om = std::make_unique(m_editor, m_layer_icons[m_hovered_layer]->get_layer()); + auto om = std::make_unique(m_layer_icons[m_hovered_layer]->get_layer()); m_editor.m_deactivate_request = true; MenuManager::instance().push_menu(std::move(om)); return true; diff -Nru supertux-0.6.3/src/editor/object_menu.cpp supertux-0.6.3/src/editor/object_menu.cpp --- supertux-0.6.3/src/editor/object_menu.cpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/editor/object_menu.cpp 2023-07-06 19:47:31.000000000 +0000 @@ -24,9 +24,10 @@ #include "supertux/game_object.hpp" #include "supertux/moving_object.hpp" -ObjectMenu::ObjectMenu(Editor& editor, GameObject* go) : - m_editor(editor), - m_object(go) +ObjectMenu::ObjectMenu(GameObject* go, const std::function& remove_function) : + m_editor(*Editor::current()), + m_object(go), + m_remove_function(remove_function) { m_object->save_state(); @@ -41,6 +42,13 @@ oo.add_to_menu(*this); } } + + if (m_remove_function) + { + add_hl(); + add_entry(MNID_REMOVEFUNCTION, _("Remove")); + } + add_hl(); add_back(_("OK"), -1); } @@ -61,6 +69,11 @@ m_object->remove_me(); break; + case MNID_REMOVEFUNCTION: + if (m_remove_function(m_object)) + MenuManager::instance().pop_menu(); + break; + case MNID_TEST_FROM_HERE: { const MovingObject *here = dynamic_cast(m_object); m_editor.m_test_pos = std::make_pair(m_editor.get_sector()->get_name(), @@ -89,9 +102,12 @@ m_object->after_editor_set(); m_object->check_state(); - m_editor.m_reactivate_request = true; - if (!dynamic_cast(m_object)) { - m_editor.sort_layers(); + if (!MenuManager::instance().previous_menu()) + { + m_editor.m_reactivate_request = true; + if (!dynamic_cast(m_object)) { + m_editor.sort_layers(); + } } return true; diff -Nru supertux-0.6.3/src/editor/object_menu.hpp supertux-0.6.3/src/editor/object_menu.hpp --- supertux-0.6.3/src/editor/object_menu.hpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/editor/object_menu.hpp 2023-07-06 19:47:31.000000000 +0000 @@ -19,6 +19,8 @@ #include "gui/menu.hpp" +#include + class Editor; class GameObject; @@ -27,12 +29,13 @@ public: enum { MNID_REMOVE, + MNID_REMOVEFUNCTION, MNID_TEST_FROM_HERE, MNID_OPEN_PARTICLE_EDITOR, }; public: - ObjectMenu(Editor& editor, GameObject* go); + ObjectMenu(GameObject* go, const std::function& remove_function = {}); ~ObjectMenu() override; virtual void menu_action(MenuItem& item) override; @@ -41,6 +44,7 @@ private: Editor& m_editor; GameObject* m_object; + const std::function m_remove_function; private: ObjectMenu(const ObjectMenu&) = delete; diff -Nru supertux-0.6.3/src/editor/object_option.cpp supertux-0.6.3/src/editor/object_option.cpp --- supertux-0.6.3/src/editor/object_option.cpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/editor/object_option.cpp 2023-07-06 19:47:31.000000000 +0000 @@ -24,7 +24,10 @@ #include "editor/object_menu.hpp" #include "gui/menu.hpp" +#include "gui/menu_manager.hpp" +#include "gui/menu_object_select.hpp" #include "object/tilemap.hpp" +#include "supertux/moving_object.hpp" #include "util/gettext.hpp" #include "util/writer.hpp" #include "video/color.hpp" @@ -483,31 +486,43 @@ menu.add_color(get_text(), m_pointer); } -BadGuySelectObjectOption::BadGuySelectObjectOption(const std::string& text, std::vector* pointer, const std::string& key, - unsigned int flags) : +ObjectSelectObjectOption::ObjectSelectObjectOption(const std::string& text, std::vector>* pointer, + GameObject* parent, const std::string& key, unsigned int flags) : ObjectOption(text, key, flags), - m_pointer(pointer) + m_pointer(pointer), + m_parent(parent) { } void -BadGuySelectObjectOption::save(Writer& writer) const +ObjectSelectObjectOption::save(Writer& writer) const { - if (!get_key().empty()) { - writer.write(get_key(), *m_pointer); + if (get_key().empty()) + return; + + writer.start_list(get_key()); + for (auto it = m_pointer->begin(); it != m_pointer->end(); it++) + { + auto& obj = *it; + writer.start_list(obj->get_class_name()); + obj->save(writer); + writer.end_list(obj->get_class_name()); } + writer.end_list(get_key()); } std::string -BadGuySelectObjectOption::to_string() const +ObjectSelectObjectOption::to_string() const { return fmt_to_string(m_pointer->size()); } void -BadGuySelectObjectOption::add_to_menu(Menu& menu) const +ObjectSelectObjectOption::add_to_menu(Menu& menu) const { - menu.add_badguy_select(get_text(), m_pointer); + menu.add_entry(get_text(), [pointer = m_pointer, parent = m_parent]() { + MenuManager::instance().push_menu(std::make_unique(*pointer, parent)); + }); } TilesObjectOption::TilesObjectOption(const std::string& text, TileMap* tilemap, const std::string& key, diff -Nru supertux-0.6.3/src/editor/object_option.hpp supertux-0.6.3/src/editor/object_option.hpp --- supertux-0.6.3/src/editor/object_option.hpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/editor/object_option.hpp 2023-07-06 19:47:31.000000000 +0000 @@ -41,6 +41,7 @@ } // namespace sexp class Color; class Menu; +class GameObject; class Path; class PathObject; class Rectf; @@ -317,22 +318,23 @@ ColorObjectOption& operator=(const ColorObjectOption&) = delete; }; -class BadGuySelectObjectOption : public ObjectOption +class ObjectSelectObjectOption : public ObjectOption { public: - BadGuySelectObjectOption(const std::string& text, std::vector* pointer, const std::string& key, - unsigned int flags); + ObjectSelectObjectOption(const std::string& text, std::vector>* pointer, + GameObject* parent, const std::string& key, unsigned int flags); virtual void save(Writer& write) const override; virtual std::string to_string() const override; virtual void add_to_menu(Menu& menu) const override; private: - std::vector* const m_pointer; + std::vector>* const m_pointer; + GameObject* m_parent; private: - BadGuySelectObjectOption(const BadGuySelectObjectOption&) = delete; - BadGuySelectObjectOption& operator=(const BadGuySelectObjectOption&) = delete; + ObjectSelectObjectOption(const ObjectSelectObjectOption&) = delete; + ObjectSelectObjectOption& operator=(const ObjectSelectObjectOption&) = delete; }; class TilesObjectOption : public ObjectOption diff -Nru supertux-0.6.3/src/editor/object_settings.cpp supertux-0.6.3/src/editor/object_settings.cpp --- supertux-0.6.3/src/editor/object_settings.cpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/editor/object_settings.cpp 2023-07-06 19:47:31.000000000 +0000 @@ -35,10 +35,10 @@ } void -ObjectSettings::add_badguy(const std::string& text, std::vector* value_ptr, - const std::string& key, unsigned int flags) +ObjectSettings::add_objects(const std::string& text, std::vector>* value_ptr, + GameObject* parent, const std::string& key, unsigned int flags) { - add_option(std::make_unique(text, value_ptr, key, flags)); + add_option(std::make_unique(text, value_ptr, parent, key, flags)); } void diff -Nru supertux-0.6.3/src/editor/object_settings.hpp supertux-0.6.3/src/editor/object_settings.hpp --- supertux-0.6.3/src/editor/object_settings.hpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/editor/object_settings.hpp 2023-07-06 19:47:31.000000000 +0000 @@ -27,6 +27,7 @@ class Color; enum class Direction; +class GameObject; class PathObject; enum class WalkMode; namespace worldmap { @@ -69,8 +70,8 @@ void add_walk_mode(const std::string& text, WalkMode* value_ptr, const std::optional& default_value = {}, const std::string& key = {}, unsigned int flags = 0); - void add_badguy(const std::string& text, std::vector* value_ptr, - const std::string& key = {}, unsigned int flags = 0); + void add_objects(const std::string& text, std::vector>* value_ptr, + GameObject* parent = nullptr, const std::string& key = {}, unsigned int flags = 0); void add_color(const std::string& text, Color* value_ptr, const std::string& key = {}, const std::optional& default_value = {}, diff -Nru supertux-0.6.3/src/editor/overlay_widget.cpp supertux-0.6.3/src/editor/overlay_widget.cpp --- supertux-0.6.3/src/editor/overlay_widget.cpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/editor/overlay_widget.cpp 2023-07-06 19:47:31.000000000 +0000 @@ -721,7 +721,7 @@ void EditorOverlayWidget::show_object_menu(GameObject& object) { - auto menu = std::make_unique(m_editor, &object); + auto menu = std::make_unique(&object); m_editor.m_deactivate_request = true; MenuManager::instance().push_menu(std::move(menu)); } diff -Nru supertux-0.6.3/src/gui/item_badguy_select.cpp supertux-0.6.3/src/gui/item_badguy_select.cpp --- supertux-0.6.3/src/gui/item_badguy_select.cpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/gui/item_badguy_select.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,36 +0,0 @@ -// SuperTux -// Copyright (C) 2016 Hume2 -// -// 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 "gui/item_badguy_select.hpp" - -#include "gui/menu.hpp" -#include "gui/menu_badguy_select.hpp" -#include "gui/menu_manager.hpp" - -ItemBadguySelect::ItemBadguySelect(const std::string& text, std::vector* badguys_, int id) : - MenuItem(text, id), - badguys(badguys_) -{ -} - -void -ItemBadguySelect::process_action(const MenuAction& action) { - if (action == MenuAction::HIT) { - MenuManager::instance().push_menu(std::make_unique(badguys)); - } -} - -/* EOF */ diff -Nru supertux-0.6.3/src/gui/item_badguy_select.hpp supertux-0.6.3/src/gui/item_badguy_select.hpp --- supertux-0.6.3/src/gui/item_badguy_select.hpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/gui/item_badguy_select.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,40 +0,0 @@ -// SuperTux -// Copyright (C) 2016 Hume2 -// -// 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_GUI_ITEM_BADGUY_SELECT_HPP -#define HEADER_SUPERTUX_GUI_ITEM_BADGUY_SELECT_HPP - -#include "gui/menu_item.hpp" - -class ItemBadguySelect final : public MenuItem -{ -public: - ItemBadguySelect(const std::string& text, std::vector* badguys_, int id = -1); - - /** Processes the menu action. */ - virtual void process_action(const MenuAction& action) override; - -private: - std::vector* badguys; - -private: - ItemBadguySelect(const ItemBadguySelect&) = delete; - ItemBadguySelect& operator=(const ItemBadguySelect&) = delete; -}; - -#endif - -/* EOF */ diff -Nru supertux-0.6.3/src/gui/menu_badguy_select.cpp supertux-0.6.3/src/gui/menu_badguy_select.cpp --- supertux-0.6.3/src/gui/menu_badguy_select.cpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/gui/menu_badguy_select.cpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,101 +0,0 @@ -// SuperTux -// Copyright (C) 2016 Hume2 -// -// 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 "gui/menu_badguy_select.hpp" - -#include - -#include "gui/dialog.hpp" -#include "gui/menu_item.hpp" -#include "gui/menu_manager.hpp" -#include "gui/menu_list.hpp" -#include "supertux/game_object_factory.hpp" -#include "editor/editor.hpp" -BadguySelectMenu::BadguySelectMenu(std::vector* badguys_) : - badguys(badguys_), - selected(), - remove_item() -{ - refresh(); -} - -void -BadguySelectMenu::refresh() -{ - m_items.clear(); - - add_label(_("List of enemies")); - add_hl(); - add_entry(-2, fmt::format(_("Select enemy ({})"), selected)); - add_entry(-3, _("Add")); - add_hl(); - - int i = 0; - for (auto& badguy : *badguys) { - add_entry(i, badguy); - i++; - } - - add_hl(); - add_back(_("OK")); -} - -void -BadguySelectMenu::remove_badguy() -{ - badguys->erase(badguys->begin() + remove_item); - refresh(); - if (m_items[m_active_item]->skippable()) { - //We are on the bottom headline. - m_active_item++; - } -} - -void -BadguySelectMenu::add_badguy() -{ - if (selected == "") - { - log_warning << "Cannot add an empty enemy." << std::endl; - return; - } - badguys->push_back(selected); - refresh(); - -} - -void -BadguySelectMenu::menu_action(MenuItem& item) -{ - if (item.get_id() >= 0) { - remove_item = item.get_id(); - auto self = this; - // confirmation dialog - auto dialog = std::make_unique(); - dialog->set_text(_("Do you want to delete this badguy from the list?")); - dialog->add_default_button(_("Yes"), [self] { - self->remove_badguy(); - }); - dialog->add_cancel_button(_("No")); - MenuManager::instance().set_dialog(std::move(dialog)); - } else if (item.get_id() == -2) { - MenuManager::instance().push_menu(std::make_unique(GameObjectFactory::instance().get_registered_badguys(), &selected, this)); - } else if (item.get_id() == -3) { - add_badguy(); - } -} - -/* EOF */ diff -Nru supertux-0.6.3/src/gui/menu_badguy_select.hpp supertux-0.6.3/src/gui/menu_badguy_select.hpp --- supertux-0.6.3/src/gui/menu_badguy_select.hpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/gui/menu_badguy_select.hpp 1970-01-01 00:00:00.000000000 +0000 @@ -1,47 +0,0 @@ -// SuperTux -// Copyright (C) 2016 Hume2 -// -// 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_GUI_MENU_BADGUY_SELECT_HPP -#define HEADER_SUPERTUX_GUI_MENU_BADGUY_SELECT_HPP - -#include "gui/menu.hpp" - -class BadguySelectMenu final : public Menu -{ -public: - BadguySelectMenu(std::vector* badguys_); - - void menu_action(MenuItem& item) override; - - void remove_badguy(); - - void refresh() override; - -private: - std::vector* badguys; - std::string selected; - int remove_item; - - void add_badguy(); - -private: - BadguySelectMenu(const BadguySelectMenu&) = delete; - BadguySelectMenu& operator=(const BadguySelectMenu&) = delete; -}; - -#endif - -/* EOF */ diff -Nru supertux-0.6.3/src/gui/menu.cpp supertux-0.6.3/src/gui/menu.cpp --- supertux-0.6.3/src/gui/menu.cpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/gui/menu.cpp 2023-07-06 19:47:31.000000000 +0000 @@ -19,7 +19,6 @@ #include "control/input_manager.hpp" #include "gui/item_action.hpp" #include "gui/item_back.hpp" -#include "gui/item_badguy_select.hpp" #include "gui/item_color.hpp" #include "gui/item_colorchannel.hpp" #include "gui/item_colordisplay.hpp" @@ -339,14 +338,6 @@ auto item_ptr = item.get(); add_item(std::move(item)); return *item_ptr; -} - -ItemBadguySelect& -Menu::add_badguy_select(const std::string& text, std::vector* badguys, int id) { - auto item = std::make_unique(text, badguys, id); - auto item_ptr = item.get(); - add_item(std::move(item)); - return *item_ptr; } ItemStringArray& diff -Nru supertux-0.6.3/src/gui/menu.hpp supertux-0.6.3/src/gui/menu.hpp --- supertux-0.6.3/src/gui/menu.hpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/gui/menu.hpp 2023-07-06 19:47:31.000000000 +0000 @@ -28,7 +28,6 @@ class ItemAction; class ItemBack; -class ItemBadguySelect; class ItemColor; class ItemColorChannelRGBA; class ItemColorChannelOKLab; @@ -42,6 +41,7 @@ class ItemInactive; class ItemIntField; class ItemLabel; +class ItemObjectSelect; class ItemPaths; class ItemScript; class ItemScriptLine; @@ -95,7 +95,6 @@ ItemScriptLine& add_script_line(std::string* input, int id = -1); ItemIntField& add_intfield(const std::string& text, int* input, int id = -1, bool positive = false); ItemFloatField& add_floatfield(const std::string& text, float* input, int id = -1, bool positive = false); - ItemBadguySelect& add_badguy_select(const std::string& text, std::vector* badguys, int id = -1); ItemFile& add_file(const std::string& text, std::string* input, const std::vector& extensions, const std::string& basedir, bool path_relative_to_basedir, int id = -1); diff -Nru supertux-0.6.3/src/gui/menu_list.cpp supertux-0.6.3/src/gui/menu_list.cpp --- supertux-0.6.3/src/gui/menu_list.cpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/gui/menu_list.cpp 2023-07-06 19:47:31.000000000 +0000 @@ -1,5 +1,6 @@ // SuperTux -- List menu // Copyright (C) 2021 Rami +// 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 @@ -19,24 +20,33 @@ #include "gui/menu_manager.hpp" #include "util/gettext.hpp" -ListMenu::ListMenu(const std::vector& items, std::string* selected, Menu* parent) : +ListMenu::ListMenu(const std::vector& entries, std::string* selected, Menu* parent, + const std::function& text_processor) : + m_entries(entries), m_selected(selected), m_parent(parent) { - for(size_t i = 0; i < items.size(); i++) { - add_entry(static_cast(i), items[i]); + for (int i = 0; i < static_cast(m_entries.size()); i++) + { + if (text_processor) + add_entry(i, text_processor(m_entries[i])); + else + add_entry(i, m_entries[i]); } + add_hl(); add_back(_("Cancel")); } void -ListMenu::menu_action(MenuItem& item) { - if(m_selected) { - *m_selected = item.get_text(); - } +ListMenu::menu_action(MenuItem& item) +{ + if (m_selected) + *m_selected = m_entries.at(item.get_id()); + if (m_parent) m_parent->refresh(); + MenuManager::instance().pop_menu(); } diff -Nru supertux-0.6.3/src/gui/menu_list.hpp supertux-0.6.3/src/gui/menu_list.hpp --- supertux-0.6.3/src/gui/menu_list.hpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/gui/menu_list.hpp 2023-07-06 19:47:31.000000000 +0000 @@ -1,5 +1,6 @@ // SuperTux -- List menu // Copyright (C) 2021 Rami +// 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 @@ -19,19 +20,22 @@ #include "gui/menu.hpp" +#include + class ListMenu final : public Menu { public: - ListMenu(const std::vector& items, std::string* selected, Menu* parent); + ListMenu(const std::vector& entries, std::string* selected, Menu* parent, + const std::function& text_processor = {}); void menu_action(MenuItem& item) override; private: + const std::vector m_entries; std::string* m_selected; Menu* m_parent; private: - // non-copyable footer ListMenu(const ListMenu&) = delete; ListMenu& operator=(const ListMenu&) = delete; }; diff -Nru supertux-0.6.3/src/gui/menu_object_select.cpp supertux-0.6.3/src/gui/menu_object_select.cpp --- supertux-0.6.3/src/gui/menu_object_select.cpp 1970-01-01 00:00:00.000000000 +0000 +++ supertux-0.6.3/src/gui/menu_object_select.cpp 2023-07-06 19:47:31.000000000 +0000 @@ -0,0 +1,129 @@ +// SuperTux +// Copyright (C) 2016 Hume2 +// 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 "gui/menu_object_select.hpp" + +#include + +#include "badguy/dispenser.hpp" +#include "editor/object_menu.hpp" +#include "gui/dialog.hpp" +#include "gui/menu_item.hpp" +#include "gui/menu_list.hpp" +#include "gui/menu_manager.hpp" +#include "supertux/game_object_factory.hpp" +#include "util/log.hpp" + +ObjectSelectMenu::ObjectSelectMenu(std::vector>& objects, GameObject* parent) : + m_objects(objects), + m_parent(parent), + m_selected() +{ + refresh(); +} + +void +ObjectSelectMenu::refresh() +{ + clear(); + + add_label(_("List of objects")); + add_hl(); + add_entry(-2, fmt::format(fmt::runtime(_("Select object ({})")), + m_selected.empty() ? "" : GameObjectFactory::instance().get_display_name(m_selected))); + add_entry(-3, _("Add")); + add_hl(); + + int i = 0; + for (auto& obj : m_objects) + { + add_entry(i, obj->get_display_name()); + i++; + } + + add_hl(); + add_back(_("OK")); +} + +void +ObjectSelectMenu::add_object() +{ + if (m_selected.empty()) + { + log_warning << "Cannot add object: No object selected." << std::endl; + return; + } + + auto obj = GameObjectFactory::instance().create(m_selected); + + Dispenser* dispenser = dynamic_cast(m_parent); + if (dispenser) + dispenser->add_object(std::move(obj)); // The Dispenser itself should add the object, running appropriate checks + else + m_objects.push_back(std::move(obj)); + + refresh(); +} + +void +ObjectSelectMenu::remove_object(GameObject* obj) +{ + m_objects.erase( + std::remove_if(m_objects.begin(), m_objects.end(), [obj](const auto& found_obj) + { + return obj == found_obj.get(); + }), m_objects.end()); + refresh(); +} + +const std::vector +ObjectSelectMenu::get_available_objects() const +{ + if (dynamic_cast(m_parent)) + return GameObjectFactory::instance().get_registered_objects(ObjectFactory::RegisteredObjectParam::OBJ_PARAM_DISPENSABLE); + + return GameObjectFactory::instance().get_registered_objects(); +} + +void +ObjectSelectMenu::menu_action(MenuItem& item) +{ + if (item.get_id() >= 0) + { + MenuManager::instance().push_menu(std::make_unique(m_objects[item.get_id()].get(), + [this](GameObject* obj) { + Dialog::show_confirmation(_("Are you sure you want to remove this object from the list?"), [this, obj]() { + remove_object(obj); + MenuManager::instance().pop_menu(); + }); + return false; + })); + } + else if (item.get_id() == -2) + { + MenuManager::instance().push_menu(std::make_unique(get_available_objects(), + &m_selected, this, [](const std::string& obj_name) { + return GameObjectFactory::instance().get_display_name(obj_name); + })); + } + else if (item.get_id() == -3) + { + add_object(); + } +} + +/* EOF */ diff -Nru supertux-0.6.3/src/gui/menu_object_select.hpp supertux-0.6.3/src/gui/menu_object_select.hpp --- supertux-0.6.3/src/gui/menu_object_select.hpp 1970-01-01 00:00:00.000000000 +0000 +++ supertux-0.6.3/src/gui/menu_object_select.hpp 2023-07-06 19:47:31.000000000 +0000 @@ -0,0 +1,52 @@ +// SuperTux +// Copyright (C) 2016 Hume2 +// 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_GUI_MENU_OBJECT_SELECT_HPP +#define HEADER_SUPERTUX_GUI_MENU_OBJECT_SELECT_HPP + +#include "gui/menu.hpp" + +class GameObject; + +class ObjectSelectMenu final : public Menu +{ +public: + ObjectSelectMenu(std::vector>& objects, GameObject* parent); + + void refresh() override; + void menu_action(MenuItem& item) override; + +private: + void add_object(); + void remove_object(GameObject* obj); + + const std::vector get_available_objects() const; + +private: + std::vector>& m_objects; + GameObject* m_parent; + + std::string m_selected; + +private: + ObjectSelectMenu(const ObjectSelectMenu&) = delete; + ObjectSelectMenu& operator=(const ObjectSelectMenu&) = delete; +}; + +#endif + +/* EOF */ diff -Nru supertux-0.6.3/src/object/bonus_block.cpp supertux-0.6.3/src/object/bonus_block.cpp --- supertux-0.6.3/src/object/bonus_block.cpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/object/bonus_block.cpp 2023-07-06 19:47:31.000000000 +0000 @@ -292,7 +292,7 @@ Sector::get().add(get_pos(), true); SoundManager::current()->play("sounds/coin.wav", get_pos()); player->get_status().add_coins(1, false); - if (m_hit_counter != 0) + if (m_hit_counter != 0 && !m_parent_dispenser) Sector::get().get_level().m_stats.increment_coins(); break; } @@ -379,13 +379,13 @@ } case Content::RAIN: { - Sector::get().add(get_pos(), true); + Sector::get().add(get_pos(), true, !m_parent_dispenser); play_upgrade_sound = true; break; } case Content::EXPLODE: { - Sector::get().add(get_pos() + Vector (0, -40)); + Sector::get().add(get_pos() + Vector (0, -40), !m_parent_dispenser); play_upgrade_sound = true; break; } @@ -529,7 +529,7 @@ } case Content::EXPLODE: { - Sector::get().add(get_pos() + Vector (0, 40)); + Sector::get().add(get_pos() + Vector (0, 40), !m_parent_dispenser); play_upgrade_sound = true; countdown = true; break; diff -Nru supertux-0.6.3/src/object/coin.cpp supertux-0.6.3/src/object/coin.cpp --- supertux-0.6.3/src/object/coin.cpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/object/coin.cpp 2023-07-06 19:47:31.000000000 +0000 @@ -28,7 +28,7 @@ #include "util/reader_mapping.hpp" #include "util/writer.hpp" -Coin::Coin(const Vector& pos) : +Coin::Coin(const Vector& pos, bool count_stats) : MovingSprite(pos, "images/objects/coin/coin.sprite", LAYER_OBJECTS - 1, COLGROUP_TOUCHABLE), PathObject(), m_offset(0.0f, 0.0f), @@ -36,12 +36,13 @@ m_add_path(false), m_physic(), m_collect_script(), - m_starting_node(0) + m_starting_node(0), + m_count_stats(count_stats) { SoundManager::current()->preload("sounds/coin.wav"); } -Coin::Coin(const ReaderMapping& reader) : +Coin::Coin(const ReaderMapping& reader, bool count_stats) : MovingSprite(reader, "images/objects/coin/coin.sprite", LAYER_OBJECTS - 1, COLGROUP_TOUCHABLE), PathObject(), m_offset(0.0f, 0.0f), @@ -49,7 +50,8 @@ m_add_path(false), m_physic(), m_collect_script(), - m_starting_node(0) + m_starting_node(0), + m_count_stats(count_stats) { reader.get("starting-node", m_starting_node, 0); @@ -187,7 +189,8 @@ Sector::get().get_players()[0]->get_status().add_coins(1, false); Sector::get().add(get_pos(), false, get_sprite_name()); - Sector::get().get_level().m_stats.increment_coins(); + if (m_count_stats && !m_parent_dispenser) + Sector::get().get_level().m_stats.increment_coins(); remove_me(); if (!m_collect_script.empty()) { @@ -207,8 +210,8 @@ } /* The following defines a coin subject to gravity */ -HeavyCoin::HeavyCoin(const Vector& pos, const Vector& init_velocity) : - Coin(pos), +HeavyCoin::HeavyCoin(const Vector& pos, const Vector& init_velocity, bool count_stats) : + Coin(pos, count_stats), m_physic(), m_last_hit() { @@ -218,8 +221,8 @@ m_physic.set_velocity(init_velocity); } -HeavyCoin::HeavyCoin(const ReaderMapping& reader) : - Coin(reader), +HeavyCoin::HeavyCoin(const ReaderMapping& reader, bool count_stats) : + Coin(reader, count_stats), m_physic(), m_last_hit() { diff -Nru supertux-0.6.3/src/object/coin_explode.cpp supertux-0.6.3/src/object/coin_explode.cpp --- supertux-0.6.3/src/object/coin_explode.cpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/object/coin_explode.cpp 2023-07-06 19:47:31.000000000 +0000 @@ -20,8 +20,9 @@ #include "object/coin.hpp" #include "supertux/sector.hpp" -CoinExplode::CoinExplode(const Vector& pos) : - position(pos) +CoinExplode::CoinExplode(const Vector& pos, bool count_stats) : + position(pos), + m_count_stats(count_stats) { } @@ -31,16 +32,16 @@ float mag = 100.0f; // madnitude that coins are to be thrown float rand = 30.0f; // max variation to be subtracted from magnitide - Sector::get().add(position, Vector(2.5, -4.5) * (mag - gameRandom.randf(rand))); - Sector::get().add(position, Vector(2, -5) * (mag - gameRandom.randf(rand))); - Sector::get().add(position, Vector(1.5, -5.5) * (mag - gameRandom.randf(rand))); - Sector::get().add(position, Vector(1, -6) * (mag+gameRandom.randf(rand))); - Sector::get().add(position, Vector(0.5, -6.5) * (mag - gameRandom.randf(rand))); - Sector::get().add(position, Vector(-2.5, -4.5) * (mag - gameRandom.randf(rand))); - Sector::get().add(position, Vector(-2, -5) * (mag - gameRandom.randf(rand))); - Sector::get().add(position, Vector(-1.5, -5.5) * (mag - gameRandom.randf(rand))); - Sector::get().add(position, Vector(-1, -6) * (mag+gameRandom.randf(rand))); - Sector::get().add(position, Vector(-0.5, -6.5) * (mag - gameRandom.randf(rand))); + Sector::get().add(position, Vector(2.5, -4.5) * (mag - gameRandom.randf(rand)), m_count_stats); + Sector::get().add(position, Vector(2, -5) * (mag - gameRandom.randf(rand)), m_count_stats); + Sector::get().add(position, Vector(1.5, -5.5) * (mag - gameRandom.randf(rand)), m_count_stats); + Sector::get().add(position, Vector(1, -6) * (mag+gameRandom.randf(rand)), m_count_stats); + Sector::get().add(position, Vector(0.5, -6.5) * (mag - gameRandom.randf(rand)), m_count_stats); + Sector::get().add(position, Vector(-2.5, -4.5) * (mag - gameRandom.randf(rand)), m_count_stats); + Sector::get().add(position, Vector(-2, -5) * (mag - gameRandom.randf(rand)), m_count_stats); + Sector::get().add(position, Vector(-1.5, -5.5) * (mag - gameRandom.randf(rand)), m_count_stats); + Sector::get().add(position, Vector(-1, -6) * (mag+gameRandom.randf(rand)), m_count_stats); + Sector::get().add(position, Vector(-0.5, -6.5) * (mag - gameRandom.randf(rand)), m_count_stats); remove_me(); } diff -Nru supertux-0.6.3/src/object/coin_explode.hpp supertux-0.6.3/src/object/coin_explode.hpp --- supertux-0.6.3/src/object/coin_explode.hpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/object/coin_explode.hpp 2023-07-06 19:47:31.000000000 +0000 @@ -23,7 +23,7 @@ class CoinExplode final : public GameObject { public: - CoinExplode(const Vector& pos); + CoinExplode(const Vector& pos, bool count_stats = true); virtual void update(float dt_sec) override; virtual void draw(DrawingContext& context) override; virtual bool is_saveable() const override { @@ -32,6 +32,7 @@ private: Vector position; + const bool m_count_stats; }; #endif diff -Nru supertux-0.6.3/src/object/coin.hpp supertux-0.6.3/src/object/coin.hpp --- supertux-0.6.3/src/object/coin.hpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/object/coin.hpp 2023-07-06 19:47:31.000000000 +0000 @@ -32,8 +32,8 @@ friend class HeavyCoin; public: - Coin(const Vector& pos); - Coin(const ReaderMapping& reader); + Coin(const Vector& pos, bool count_stats = true); + Coin(const ReaderMapping& reader, bool count_stats = true); virtual void finish_construction() override; virtual HitResponse collision(GameObject& other, const CollisionHit& hit) override; @@ -63,6 +63,8 @@ int m_starting_node; + const bool m_count_stats; + private: Coin(const Coin&) = delete; Coin& operator=(const Coin&) = delete; @@ -71,8 +73,8 @@ class HeavyCoin final : public Coin { public: - HeavyCoin(const Vector& pos, const Vector& init_velocity); - HeavyCoin(const ReaderMapping& reader); + HeavyCoin(const Vector& pos, const Vector& init_velocity, bool count_stats = true); + HeavyCoin(const ReaderMapping& reader, bool count_stats = true); virtual void update(float dt_sec) override; virtual void collision_solid(const CollisionHit& hit) override; diff -Nru supertux-0.6.3/src/object/coin_rain.cpp supertux-0.6.3/src/object/coin_rain.cpp --- supertux-0.6.3/src/object/coin_rain.cpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/object/coin_rain.cpp 2023-07-06 19:47:31.000000000 +0000 @@ -24,13 +24,14 @@ static const float DROP_TIME = .1f; // time duration between "drops" of coin rain -CoinRain::CoinRain(const Vector& pos, bool emerge) : +CoinRain::CoinRain(const Vector& pos, bool emerge, bool count_stats) : sprite(SpriteManager::current()->create("images/objects/coin/coin.sprite")), position(pos), emerge_distance(0), timer(), counter(0), - drop(0) + drop(0), + m_count_stats(count_stats) { if (emerge) { emerge_distance = static_cast(sprite->get_height()); @@ -49,7 +50,7 @@ else if (counter==0){ drop = gameRandom.rand(10); Sector::get().add(Vector(position.x + 32.0f * static_cast((drop < 5) ? -drop - 1 : drop - 4), -32.0f), - Vector(0, 0)); + Vector(0, 0), m_count_stats); counter++; timer.start(DROP_TIME); } // finally the remainder of the coins drop in a determined but appears to be a random order @@ -58,7 +59,7 @@ drop += 7; if (drop >= 10) drop -=10; Sector::get().add(Vector(position.x + 32.0f * static_cast((drop < 5) ? -drop - 1 : drop - 4), -32.0f), - Vector(0, 0)); + Vector(0, 0), m_count_stats); counter++; timer.start(DROP_TIME); } else { diff -Nru supertux-0.6.3/src/object/coin_rain.hpp supertux-0.6.3/src/object/coin_rain.hpp --- supertux-0.6.3/src/object/coin_rain.hpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/object/coin_rain.hpp 2023-07-06 19:47:31.000000000 +0000 @@ -25,7 +25,7 @@ class CoinRain final : public GameObject { public: - CoinRain(const Vector& pos, bool emerge=false); + CoinRain(const Vector& pos, bool emerge=false, bool count_stats = true); virtual void update(float dt_sec) override; virtual void draw(DrawingContext& context) override; virtual bool is_saveable() const override { @@ -39,6 +39,7 @@ Timer timer; int counter; int drop; + const bool m_count_stats; }; #endif diff -Nru supertux-0.6.3/src/object/explosion.hpp supertux-0.6.3/src/object/explosion.hpp --- supertux-0.6.3/src/object/explosion.hpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/object/explosion.hpp 2023-07-06 19:47:31.000000000 +0000 @@ -30,6 +30,8 @@ Explosion(const Vector& pos, float push_strength, int num_particles=100, bool short_fuse = false); Explosion(const ReaderMapping& reader); + static std::string class_name() { return "explosion"; } + virtual std::string get_class_name() const override { return class_name(); } static std::string display_name() { return _("Explosion"); } virtual std::string get_display_name() const override { return display_name(); } diff -Nru supertux-0.6.3/src/supertux/game_object.cpp supertux-0.6.3/src/supertux/game_object.cpp --- supertux-0.6.3/src/supertux/game_object.cpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/supertux/game_object.cpp 2023-07-06 19:47:31.000000000 +0000 @@ -131,6 +131,9 @@ void GameObject::save_state() { + if (!m_parent) + return; + if (!m_parent->undo_tracking_enabled()) { m_last_state.clear(); @@ -146,6 +149,9 @@ void GameObject::check_state() { + if (!m_parent) + return; + if (!m_parent->undo_tracking_enabled()) { m_last_state.clear(); diff -Nru supertux-0.6.3/src/supertux/game_object_factory.cpp supertux-0.6.3/src/supertux/game_object_factory.cpp --- supertux-0.6.3/src/supertux/game_object_factory.cpp 2023-07-05 19:46:59.000000000 +0000 +++ supertux-0.6.3/src/supertux/game_object_factory.cpp 2023-07-06 19:47:31.000000000 +0000 @@ -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" @@ -161,65 +162,69 @@ // badguys m_adding_badguys = true; add_factory("angrystone"); - add_factory("bouncingsnowball"); - add_factory("captainsnowball"); - add_factory("crystallo"); - add_factory("dart"); + add_factory("bouncingsnowball", OBJ_PARAM_DISPENSABLE); + add_factory("captainsnowball", OBJ_PARAM_DISPENSABLE); + add_factory("crusher"); + add_factory("icecrusher"); // backward compatibility + add_factory("crystallo", OBJ_PARAM_DISPENSABLE); + add_factory("dart", OBJ_PARAM_DISPENSABLE); add_factory("darttrap"); - add_factory("dispenser"); - add_factory("fish-chasing"); - add_factory("fish-harmless"); + 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 - add_factory("fish-jumping"); - add_factory("fish-swimming"); - add_factory("flame"); - add_factory("flyingsnowball"); - add_factory("ghostflame"); + add_factory("fish-jumping", OBJ_PARAM_DISPENSABLE); + add_factory("fish-swimming", OBJ_PARAM_DISPENSABLE); + add_factory("flame", OBJ_PARAM_DISPENSABLE); + add_factory("flyingsnowball", OBJ_PARAM_DISPENSABLE); + add_factory("ghostflame", OBJ_PARAM_DISPENSABLE); add_factory("ghosttree"); - add_factory("ghoul"); - add_factory("goldbomb", RegisteredObjectParam::OBJ_PARAM_PORTABLE); - add_factory("haywire"); - add_factory("iceflame"); - add_factory("igel"); - add_factory("jumpy"); - add_factory("kamikazesnowball"); - add_factory("kugelblitz"); - add_factory("leafshot"); - add_factory("livefire"); - add_factory("livefire_asleep"); - add_factory("livefire_dormant"); + add_factory("ghoul", OBJ_PARAM_DISPENSABLE); + add_factory("goldbomb", OBJ_PARAM_PORTABLE | OBJ_PARAM_DISPENSABLE); + add_factory("haywire", OBJ_PARAM_DISPENSABLE); + add_factory("iceflame", OBJ_PARAM_DISPENSABLE); + add_factory("igel", OBJ_PARAM_DISPENSABLE); + add_factory("ispy"); + add_factory("jumpy", OBJ_PARAM_DISPENSABLE); + add_factory("kamikazesnowball", OBJ_PARAM_DISPENSABLE); + add_factory("kugelblitz", OBJ_PARAM_DISPENSABLE); + add_factory("leafshot", OBJ_PARAM_DISPENSABLE); + add_factory("livefire", OBJ_PARAM_DISPENSABLE); + add_factory("livefire_asleep", OBJ_PARAM_DISPENSABLE); + add_factory("livefire_dormant", OBJ_PARAM_DISPENSABLE); add_factory("mole"); - add_factory("mole_rock"); - add_factory("mrbomb", RegisteredObjectParam::OBJ_PARAM_PORTABLE); - add_factory("mriceblock", RegisteredObjectParam::OBJ_PARAM_PORTABLE); - add_factory("mrtree"); - add_factory("owl"); - add_factory("plant"); - add_factory("rcrystallo"); - add_factory("scrystallo"); - add_factory("short_fuse"); - add_factory("sspiky"); - add_factory("skydive", RegisteredObjectParam::OBJ_PARAM_PORTABLE); - add_factory("skullyhop"); - add_factory("smartball"); - add_factory("smartblock", RegisteredObjectParam::OBJ_PARAM_PORTABLE); - add_factory("snail", RegisteredObjectParam::OBJ_PARAM_PORTABLE); - add_factory("snowball"); - add_factory("snowman"); - add_factory("spidermite"); - add_factory("spiky"); - add_factory("stalactite"); - add_factory("stumpy"); - add_factory("toad"); - add_factory("totem"); + add_factory("mole_rock", OBJ_PARAM_DISPENSABLE); + add_factory("mrbomb", OBJ_PARAM_PORTABLE | OBJ_PARAM_DISPENSABLE); + add_factory("mriceblock", OBJ_PARAM_PORTABLE | OBJ_PARAM_DISPENSABLE); + add_factory("mrtree", OBJ_PARAM_DISPENSABLE); + add_factory("owl", OBJ_PARAM_DISPENSABLE); + add_factory("plant", OBJ_PARAM_DISPENSABLE); + add_factory("rcrystallo", OBJ_PARAM_DISPENSABLE); + add_factory("scrystallo", OBJ_PARAM_DISPENSABLE); + add_factory("short_fuse", OBJ_PARAM_DISPENSABLE); + add_factory("sspiky", OBJ_PARAM_DISPENSABLE); + add_factory("skydive", OBJ_PARAM_PORTABLE | OBJ_PARAM_DISPENSABLE); + add_factory("skullyhop", OBJ_PARAM_DISPENSABLE); + add_factory("smartball", OBJ_PARAM_DISPENSABLE); + add_factory("smartblock", OBJ_PARAM_PORTABLE | OBJ_PARAM_DISPENSABLE); + add_factory("snail", OBJ_PARAM_PORTABLE | OBJ_PARAM_DISPENSABLE); + add_factory("snowball", OBJ_PARAM_DISPENSABLE); + add_factory("snowman", OBJ_PARAM_DISPENSABLE); + add_factory("spidermite", OBJ_PARAM_DISPENSABLE); + add_factory("spiky", OBJ_PARAM_DISPENSABLE); + add_factory("stalactite", OBJ_PARAM_DISPENSABLE); + add_factory("stumpy", OBJ_PARAM_DISPENSABLE); + add_factory("toad", OBJ_PARAM_DISPENSABLE); + add_factory("totem", OBJ_PARAM_DISPENSABLE); add_factory("poisonivy"); // backward compatibility - add_factory("viciousivy"); - add_factory("walking_candle"); - add_factory("walkingleaf"); - add_factory("willowisp"); + add_factory("viciousivy", OBJ_PARAM_DISPENSABLE); + add_factory("walking_candle", OBJ_PARAM_DISPENSABLE); + add_factory("walkingleaf", OBJ_PARAM_DISPENSABLE); + add_factory("willowisp", OBJ_PARAM_DISPENSABLE); add_factory("yeti"); add_factory("yeti_stalactite"); - add_factory("zeekling"); + add_factory("zeekling", OBJ_PARAM_DISPENSABLE); m_adding_badguys = false; // other objects @@ -229,34 +234,31 @@ add_factory("background"); add_factory("path"); add_factory("bicycle-platform"); - add_factory("bonusblock"); - add_factory("brick"); + add_factory("bonusblock", OBJ_PARAM_DISPENSABLE); + add_factory("brick", OBJ_PARAM_DISPENSABLE); add_factory("bumper"); add_factory("camera"); add_factory("candle"); add_factory("circleplatform"); add_factory("particles-clouds"); add_factory("conveyor-belt"); - add_factory("icecrusher"); // backward compatibility - add_factory("crusher"); add_factory("particles-custom"); add_factory("particles-custom-file"); - add_factory("coin"); + add_factory("coin", OBJ_PARAM_DISPENSABLE); add_factory("decal"); - add_factory("explosion"); - add_factory("fallblock"); + add_factory("explosion", OBJ_PARAM_DISPENSABLE); + add_factory("fallblock", OBJ_PARAM_DISPENSABLE); add_factory("firefly"); add_factory("particles-ghosts"); add_factory("gradient"); - add_factory("heavy-brick"); + add_factory("heavy-brick", OBJ_PARAM_DISPENSABLE); add_factory("heavycoin"); add_factory("hurting_platform"); - add_factory("infoblock"); - add_factory("invisible_block"); + add_factory("infoblock", OBJ_PARAM_DISPENSABLE); + add_factory("invisible_block", OBJ_PARAM_DISPENSABLE); add_factory("invisible_wall"); - add_factory("ispy"); add_factory("key"); - add_factory("lantern", RegisteredObjectParam::OBJ_PARAM_PORTABLE); + add_factory("lantern", OBJ_PARAM_PORTABLE | OBJ_PARAM_DISPENSABLE); add_factory("leveltime"); add_factory("lit-object"); add_factory("magicblock"); @@ -264,13 +266,13 @@ add_factory("particle-zone"); add_factory("platform"); add_factory("pneumatic-platform"); - add_factory("powerup"); + add_factory("powerup", OBJ_PARAM_DISPENSABLE); add_factory("pushbutton"); add_factory("particles-rain"); - add_factory("rock", RegisteredObjectParam::OBJ_PARAM_PORTABLE); - add_factory("rublight"); + add_factory("rock", OBJ_PARAM_PORTABLE | OBJ_PARAM_DISPENSABLE); + add_factory("rublight", OBJ_PARAM_DISPENSABLE); add_factory("scriptedobject"); - add_factory("shard"); + add_factory("shard", OBJ_PARAM_DISPENSABLE); add_factory("skull_tile"); add_factory("particles-snow"); add_factory("spotlight"); @@ -278,10 +280,10 @@ add_factory("text-array"); add_factory("thunderstorm"); add_factory("torch"); - add_factory("trampoline", RegisteredObjectParam::OBJ_PARAM_PORTABLE); - add_factory("rustytrampoline", RegisteredObjectParam::OBJ_PARAM_PORTABLE); + add_factory("trampoline", OBJ_PARAM_PORTABLE | OBJ_PARAM_DISPENSABLE); + add_factory("rustytrampoline", OBJ_PARAM_PORTABLE | OBJ_PARAM_DISPENSABLE); add_factory("unstable_tile"); - add_factory("weak_block"); + add_factory("weak_block", OBJ_PARAM_DISPENSABLE); add_factory("wind"); add_factory