git repos / saland

commit 4043efc8

Poul Sander · 2026-08-07 15:04
4043efc82350975df68c996e1699a7e16a995065 patch · browse files
parent 97c2b9fe7f374ad2b3f92c243382e5339c553af8

Add spell to remove prefabs

Changed files

M data/saland/spells/base_spells.json before
M src/saland/Game.cpp before
M src/saland/GameRegion.cpp before
M src/saland/GameRegion.hpp before
M src/saland/Prefabs.cpp before
M src/saland/Prefabs.hpp before
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<MiscItem> barrel = std::make_shared<MiscItem>();
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 <algorithm>
std::vector<Prefab> 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);
+