From 7ad3935dc60397e2042bd9b94abb5b4146d52f2f Mon Sep 17 00:00:00 2001 From: Tim Felgentreff <timfelgentreff@gmail.com> Date: Fri, 3 Jul 2020 14:58:28 +0200 Subject: [PATCH] allow adding purely decorative tiles in the editor without requiring mixing, leaving that up to the user --- src/editor/edmap.cpp | 63 +++++++++++++++++++++++--------------- src/include/tile.h | 5 ++- src/include/tileset.h | 6 +++- src/map/mapfield.cpp | 6 ++++ src/map/script_map.cpp | 5 ++- src/map/script_tileset.cpp | 30 ++++++++++++++---- src/map/tileset.cpp | 11 +++++-- 7 files changed, 90 insertions(+), 36 deletions(-) diff --git a/src/editor/edmap.cpp b/src/editor/edmap.cpp index a2afd8333..210d23fc4 100644 --- a/src/editor/edmap.cpp +++ b/src/editor/edmap.cpp @@ -100,6 +100,9 @@ void EditorChangeTile(const Vec2i &pos, int tileIndex, const Vec2i &lock_pos) // Change the flags CMapField &mf = *Map.Field(pos); + if (mf.isDecorative()) { + return; + } int tile = tileIndex; if (TileToolRandom) { int n = 0; @@ -143,6 +146,10 @@ static void EditorChangeSurrounding(const Vec2i &pos, const Vec2i &lock_pos) return; } + if (mf.isDecorative()) { + return; + } + const unsigned int quad = QuadFromTile(pos); const unsigned int TH_QUAD_M = 0xFFFF0000; // Top half quad mask const unsigned int BH_QUAD_M = 0x0000FFFF; // Bottom half quad mask @@ -158,45 +165,53 @@ static void EditorChangeSurrounding(const Vec2i &pos, const Vec2i &lock_pos) if (pos.y) { const Vec2i offset(0, -1); // Insert into the bottom the new tile. - unsigned q2 = QuadFromTile(pos + offset); - unsigned u = (q2 & TH_QUAD_M) | ((quad >> 16) & BH_QUAD_M); - if (u != q2 && (pos + offset) != lock_pos) { - did_change = true; - int tile = Map.Tileset->tileFromQuad(u & BH_QUAD_M, u); - EditorChangeTile(pos + offset, tile, lock_pos); + if (!(Map.Field(pos + offset)->isDecorative())) { + unsigned q2 = QuadFromTile(pos + offset); + unsigned u = (q2 & TH_QUAD_M) | ((quad >> 16) & BH_QUAD_M); + if (u != q2 && (pos + offset) != lock_pos) { + did_change = true; + int tile = Map.Tileset->tileFromQuad(u & BH_QUAD_M, u); + EditorChangeTile(pos + offset, tile, lock_pos); + } } } if (pos.y < Map.Info.MapHeight - 1) { const Vec2i offset(0, 1); // Insert into the top the new tile. - unsigned q2 = QuadFromTile(pos + offset); - unsigned u = (q2 & BH_QUAD_M) | ((quad << 16) & TH_QUAD_M); - if (u != q2 && (pos + offset) != lock_pos) { - did_change = true; - int tile = Map.Tileset->tileFromQuad(u & TH_QUAD_M, u); - EditorChangeTile(pos + offset, tile, lock_pos); + if (!(Map.Field(pos + offset)->isDecorative())) { + unsigned q2 = QuadFromTile(pos + offset); + unsigned u = (q2 & BH_QUAD_M) | ((quad << 16) & TH_QUAD_M); + if (u != q2 && (pos + offset) != lock_pos) { + did_change = true; + int tile = Map.Tileset->tileFromQuad(u & TH_QUAD_M, u); + EditorChangeTile(pos + offset, tile, lock_pos); + } } } if (pos.x) { const Vec2i offset(-1, 0); // Insert into the left the new tile. - unsigned q2 = QuadFromTile(pos + offset); - unsigned u = (q2 & LH_QUAD_M) | ((quad >> 8) & RH_QUAD_M); - if (u != q2 && (pos + offset) != lock_pos) { - did_change = true; - int tile = Map.Tileset->tileFromQuad(u & RH_QUAD_M, u); - EditorChangeTile(pos + offset, tile, lock_pos); + if (!(Map.Field(pos + offset)->isDecorative())) { + unsigned q2 = QuadFromTile(pos + offset); + unsigned u = (q2 & LH_QUAD_M) | ((quad >> 8) & RH_QUAD_M); + if (u != q2 && (pos + offset) != lock_pos) { + did_change = true; + int tile = Map.Tileset->tileFromQuad(u & RH_QUAD_M, u); + EditorChangeTile(pos + offset, tile, lock_pos); + } } } if (pos.x < Map.Info.MapWidth - 1) { const Vec2i offset(1, 0); // Insert into the right the new tile. - unsigned q2 = QuadFromTile(pos + offset); - unsigned u = (q2 & RH_QUAD_M) | ((quad << 8) & LH_QUAD_M); - if (u != q2 && (pos + offset) != lock_pos) { - did_change = true; - int tile = Map.Tileset->tileFromQuad(u & LH_QUAD_M, u); - EditorChangeTile(pos + offset, tile, lock_pos); + if (!(Map.Field(pos + offset)->isDecorative())) { + unsigned q2 = QuadFromTile(pos + offset); + unsigned u = (q2 & RH_QUAD_M) | ((quad << 8) & LH_QUAD_M); + if (u != q2 && (pos + offset) != lock_pos) { + did_change = true; + int tile = Map.Tileset->tileFromQuad(u & LH_QUAD_M, u); + EditorChangeTile(pos + offset, tile, lock_pos); + } } } diff --git a/src/include/tile.h b/src/include/tile.h index 001a6707c..b8226a535 100644 --- a/src/include/tile.h +++ b/src/include/tile.h @@ -210,6 +210,9 @@ public: /// Returns true, if coast on the map tile field bool RockOnMap() const; + /// Returns true if the field should not need mixing with the surroundings + bool isDecorative() const; + bool isAWall() const; bool isHuman() const; bool isAHumanWall() const; @@ -227,7 +230,7 @@ private: #endif unsigned short tile; /// graphic tile number public: - unsigned short Flags; /// field flags + unsigned int Flags; /// field flags private: unsigned char cost; /// unit cost to move in this tile public: diff --git a/src/include/tileset.h b/src/include/tileset.h index 501df6ba0..39dd93853 100644 --- a/src/include/tileset.h +++ b/src/include/tileset.h @@ -37,6 +37,7 @@ ----------------------------------------------------------------------------*/ #include "vec2i.h" +#include <string> #include <vector> struct lua_State; @@ -61,6 +62,8 @@ struct lua_State; #define MapFieldSeaUnit 0x4000 /// Water unit on field #define MapFieldBuilding 0x8000 /// Building on field +#define MapFieldDecorative 0x10000 /// A field that needs no mixing with the surroundings, for the editor + /** ** These are used for lookup tiles types ** mainly used for the FOW implementation of the seen woods/rocks @@ -110,7 +113,7 @@ public: public: unsigned short tile; /// graphical pos - unsigned short flag; /// Flag + unsigned int flag; /// Flag CTileInfo tileinfo; /// Tile descriptions }; @@ -164,6 +167,7 @@ public: void parse(lua_State *l); void buildTable(lua_State *l); + int parseTilesetTileFlags(lua_State *l, int *back, int *j); private: unsigned int getOrAddSolidTileIndexByName(const std::string &name); diff --git a/src/map/mapfield.cpp b/src/map/mapfield.cpp index 2a0d2f576..01788bcb1 100644 --- a/src/map/mapfield.cpp +++ b/src/map/mapfield.cpp @@ -233,6 +233,12 @@ bool CMapField::RockOnMap() const return CheckMask(MapFieldRocks); } +/// Returns true if the field should not need mixing with the surroundings +bool CMapField::isDecorative() const +{ + return CheckMask(MapFieldDecorative); +} + bool CMapField::isAWall() const { return Flags & MapFieldWall; diff --git a/src/map/script_map.cpp b/src/map/script_map.cpp index 969d57191..b4f0c2787 100644 --- a/src/map/script_map.cpp +++ b/src/map/script_map.cpp @@ -468,8 +468,11 @@ static int CclSetTileFlags(lua_State *l) int j = 0; int flags = 0; - ParseTilesetTileFlags(l, &flags, &j); + unsigned char newBase = Map.Tileset->parseTilesetTileFlags(l, &flags, &j); Map.Tileset->tiles[tilenumber].flag = flags; + if (newBase) { + Map.Tileset->tiles[tilenumber].tileinfo.BaseTerrain = newBase; + } return 0; } diff --git a/src/map/script_tileset.cpp b/src/map/script_tileset.cpp index ddef899e2..a95f14559 100644 --- a/src/map/script_tileset.cpp +++ b/src/map/script_tileset.cpp @@ -38,6 +38,7 @@ #include "tileset.h" #include "script.h" +#include <cstring> /*---------------------------------------------------------------------------- -- Functions @@ -61,7 +62,8 @@ static bool ModifyFlag(const char *flagName, unsigned int *flag) {"air-unit", MapFieldAirUnit}, {"sea-unit", MapFieldSeaUnit}, {"building", MapFieldBuilding}, - {"human", MapFieldHuman} + {"human", MapFieldHuman}, + {"decorative", MapFieldDecorative} }; for (unsigned int i = 0; i != sizeof(flags) / sizeof(*flags); ++i) { @@ -98,8 +100,10 @@ static bool ModifyFlag(const char *flagName, unsigned int *flag) ** @param back pointer for the flags (return). ** @param j pointer for the location in the array. in and out ** +** @return index for basename, if the name this tile should be available as a different basename, or 0 +** */ -void ParseTilesetTileFlags(lua_State *l, int *back, int *j) +int CTileset::parseTilesetTileFlags(lua_State *l, int *back, int *j) { unsigned int flags = 3; @@ -114,12 +118,18 @@ void ParseTilesetTileFlags(lua_State *l, int *back, int *j) const char *value = LuaToString(l, -1); lua_pop(l, 1); - // Flags are only needed for the editor + // Flags are mostly needed for the editor if (ModifyFlag(value, &flags) == false) { LuaError(l, "solid: unsupported tag: %s" _C_ value); } } *back = flags; + + if (flags & MapFieldDecorative) { + return getOrAddSolidTileIndexByName(std::to_string(solidTerrainTypes.size())); + } else { + return 0; + } } /** @@ -190,7 +200,10 @@ void CTileset::parseSolid(lua_State *l) ++j; int f = 0; - ParseTilesetTileFlags(l, &f, &j); + if (parseTilesetTileFlags(l, &f, &j)) { + LuaError(l, "cannot set a custom basename in the main set of flags"); + } + // Vector: the tiles. lua_rawgeti(l, -1, j + 1); if (!lua_istable(l, -1)) { @@ -204,10 +217,13 @@ void CTileset::parseSolid(lua_State *l) if (lua_istable(l, -1)) { int k = 0; int tile_flag = 0; - ParseTilesetTileFlags(l, &tile_flag, &k); + unsigned char new_basename = parseTilesetTileFlags(l, &tile_flag, &k); --j; lua_pop(l, 1); tiles[index + j].flag = tile_flag; + if (new_basename) { + tiles[index + j].tileinfo.BaseTerrain = new_basename; + } continue; } const int pud = LuaToNumber(l, -1); @@ -248,7 +264,9 @@ void CTileset::parseMixed(lua_State *l) ++j; int f = 0; - ParseTilesetTileFlags(l, &f, &j); + if (parseTilesetTileFlags(l, &f, &j)) { + LuaError(l, "cannot set a custom basename in the main set of flags"); + } for (; j < args; ++j) { lua_rawgeti(l, -1, j + 1); diff --git a/src/map/tileset.cpp b/src/map/tileset.cpp index f9f581f39..43bc8d0a3 100644 --- a/src/map/tileset.cpp +++ b/src/map/tileset.cpp @@ -656,11 +656,16 @@ unsigned CTileset::getQuadFromTile(unsigned int tile) const void CTileset::fillSolidTiles(std::vector<unsigned int> *solidTiles) const { - for (size_t i = 16; i < tiles.size(); i += 16) { - const CTileInfo &info = tiles[i].tileinfo; + std::vector<int> seen_types; + seen_types.resize(solidTerrainTypes.size(), 0); + for (size_t i = 16; i < tiles.size(); i++) { + const CTileInfo &info = tiles[i].tileinfo; if (info.BaseTerrain && info.MixTerrain == 0) { - solidTiles->push_back(tiles[i].tile); + if (seen_types[info.BaseTerrain] == 0) { + seen_types[info.BaseTerrain] = 1; + solidTiles->push_back(tiles[i].tile); + } } } }