diff --git a/data/saland/spells/base_spells.json b/data/saland/spells/base_spells.json index 231c136..5755ec7 100644 --- a/data/saland/spells/base_spells.json +++ b/data/saland/spells/base_spells.json @@ -81,5 +81,10 @@ "name" : "spell_place_prefab", "type" : "tile" } + ,{ + "icon" : "icon_trash_can", + "name" : "spell_remove_prefab", + "type" : "dot" + } ] } diff --git a/src/saland/Game.cpp b/src/saland/Game.cpp index 4d84ee3..f71fe29 100644 --- a/src/saland/Game.cpp +++ b/src/saland/Game.cpp @@ -1251,6 +1251,15 @@ void Game::Update() { data->gameRegion.SpawnPrefab(getPrefabByIndex(data->selectedPrefabIndex), base_tile_x, base_tile_y); } } + if (data->spell_holder->slot_spell.at(data->spell_holder->slot_selected).name == "spell_remove_prefab") { + if (data->human->castTimeRemaining == 0) { + data->human->castTimeRemaining = data->human->castTime; + data->human->animation = "spellcast"; + int tile_x = data->world_mouse_x/32; + int tile_y = data->world_mouse_y/32; + data->gameRegion.RemovePrefabAtTile(tile_x, tile_y); + } + } } data->middleField.SetText(middleText); } diff --git a/src/saland/GameRegion.cpp b/src/saland/GameRegion.cpp index 3629bbe..1f6f5c5 100644 --- a/src/saland/GameRegion.cpp +++ b/src/saland/GameRegion.cpp @@ -100,6 +100,16 @@ void GameRegion::SpawnPrefab(const Prefab& prefab, int destX, int destY) { this->world.init_physics(this->physicsBox); } +bool GameRegion::RemovePrefabAtTile(int tileX, int tileY) { + PlacedPrefabInfo info; + if (!FindPlacedPrefabAtTile(world.tm, tileX, tileY, info)) { + return false; + } + RemovePlacedPrefab(world.tm, info); + this->world.init_physics(this->physicsBox); + return true; +} + void GameRegion::SpawnItem(const ItemDef& def, float destX, float destY) { std::shared_ptr barrel = std::make_shared(); barrel.get()->Radius = def.radius; diff --git a/src/saland/GameRegion.hpp b/src/saland/GameRegion.hpp index bcf2f66..7ca7e18 100644 --- a/src/saland/GameRegion.hpp +++ b/src/saland/GameRegion.hpp @@ -66,6 +66,7 @@ public: void SpawnMonster(const MonsterDef& def, float destX, float destY, int level = 1) ; void SpawnItem(const ItemDef& def, float destX, float destY) ; void SpawnPrefab(const Prefab& prefab, int destX, int destY); + bool RemovePrefabAtTile(int tileX, int tileY); void ProcessRegionFirstTimeEnter(World& world); void CreateLake(World& world); void CreateLake(World& world, int tile_x, int tile_y); diff --git a/src/saland/Prefabs.cpp b/src/saland/Prefabs.cpp index bfb4729..da89690 100644 --- a/src/saland/Prefabs.cpp +++ b/src/saland/Prefabs.cpp @@ -24,6 +24,7 @@ https://github.com/salandgame/saland #include "Prefabs.hpp" #include "../sago/SagoMisc.hpp" #include "../sagotmx/tmx_struct.h" +#include std::vector prefabs; @@ -130,6 +131,54 @@ const Prefab& getPrefabByIndex(size_t index) { return prefabs.at(index); } +bool FindPlacedPrefabAtTile(const sago::tiled::TileMap& tm, int tileX, int tileY, PlacedPrefabInfo& out) { + for (const auto& group : tm.object_groups) { + if (group.name != "prefab_marking") { + continue; + } + for (const auto& o : group.objects) { + int destX = (o.x - 2) / 32; + int destY = (o.y - 2) / 32; + int width = (o.width + 4) / 32; + int height = (o.height + 4) / 32; + if (tileX >= destX && tileX < destX+width && tileY >= destY && tileY < destY+height) { + out.name = o.name; + out.destX = destX; + out.destY = destY; + out.width = width; + out.height = height; + return true; + } + } + } + return false; +} + +void RemovePlacedPrefab(sago::tiled::TileMap& dest, const PlacedPrefabInfo& info) { + static const char* destLayers[] = {"prefab_ground_1", "blocking", "prefab_blocking_2", "prefab_overlay_1"}; + for (const char* destLayer : destLayers) { + int destLayerNumber = GetLayerNumber(dest, destLayer); + if (destLayerNumber < 0) { + continue; + } + for (int i = 0; i < info.width; ++i) { + for (int j = 0; j < info.height; ++j) { + sago::tiled::setTileOnLayerNumber(dest, destLayerNumber, info.destX+i, info.destY+j, 0); + } + } + } + for (auto& group : dest.object_groups) { + if (group.name != "prefab_marking") { + continue; + } + auto& objects = group.objects; + objects.erase(std::remove_if(objects.begin(), objects.end(), [&info](const sago::tiled::TileObject& o) { + return o.name == info.name && (o.x - 2) / 32 == info.destX && (o.y - 2) / 32 == info.destY; + }), objects.end()); + break; + } +} + void TestApplyPrefab(sago::tiled::TileMap& dest, int destX, int destY) { if (prefabs.size() == 0) { return; diff --git a/src/saland/Prefabs.hpp b/src/saland/Prefabs.hpp index 642f704..6fd4b3b 100644 --- a/src/saland/Prefabs.hpp +++ b/src/saland/Prefabs.hpp @@ -53,3 +53,23 @@ size_t getPrefabCount(); const Prefab& getPrefabByIndex(size_t index); +struct PlacedPrefabInfo { + std::string name; + int destX = 0; + int destY = 0; + int width = 0; + int height = 0; +}; + +/** + * Looks for a previously placed prefab (tracked via its "prefab_marking" object) whose + * footprint covers the given tile. Returns false if no placed prefab covers that tile. + */ +bool FindPlacedPrefabAtTile(const sago::tiled::TileMap& tm, int tileX, int tileY, PlacedPrefabInfo& out); + +/** + * Clears the tiles stamped by a previously placed prefab and removes its marking object. + * Use FindPlacedPrefabAtTile to locate the prefab to remove. + */ +void RemovePlacedPrefab(sago::tiled::TileMap& dest, const PlacedPrefabInfo& info); +