From 45393ef64ce4ed416994c9e3fbbc2eeda7410a6b Mon Sep 17 00:00:00 2001 From: Tim Felgentreff <timfelgentreff@gmail.com> Date: Fri, 11 Feb 2022 22:07:54 +0100 Subject: [PATCH] add ability to define additional colors and set custom unit color --- src/editor/editloop.cpp | 2 +- src/game/game.cpp | 6 ----- src/include/color.h | 40 ++++++--------------------------- src/include/player.h | 9 ++++---- src/include/unit.h | 9 ++------ src/include/unittype.h | 2 +- src/include/video.h | 4 ++-- src/map/minimap.cpp | 2 +- src/stratagus/player.cpp | 23 +++++-------------- src/stratagus/script_player.cpp | 32 +++++++++++++++++--------- src/ui/mainscr.cpp | 2 +- src/unit/script_unit.cpp | 31 +++++++++---------------- src/unit/unit.cpp | 3 +-- src/unit/unit_draw.cpp | 8 +++---- src/unit/unittype.cpp | 8 +++---- src/video/color.cpp | 10 ++++++--- src/video/graphic.cpp | 8 +++---- 17 files changed, 76 insertions(+), 123 deletions(-) diff --git a/src/editor/editloop.cpp b/src/editor/editloop.cpp index a1f85d524..a93d97d90 100644 --- a/src/editor/editloop.cpp +++ b/src/editor/editloop.cpp @@ -544,7 +544,7 @@ static void DrawPlayers() // if player exists, draw player color 2px inside highlight if (Map.Info.PlayerType[i] != PlayerNobody) { Video.FillRectangle( - PlayerColors[GameSettings.Presets[i].PlayerColor][0], + PlayerColorsRGB[GameSettings.Presets[i].PlayerColor][0], x + 2, y + 2, getPlayerButtonSize() - 2, getPlayerButtonSize() - 2); } diff --git a/src/game/game.cpp b/src/game/game.cpp index 0e86dd38b..bc6351a36 100644 --- a/src/game/game.cpp +++ b/src/game/game.cpp @@ -1067,12 +1067,6 @@ void CreateGame(const std::string &filename, CMap *map) // for (CUnitManager::Iterator it = UnitManager.begin(); it != UnitManager.end(); ++it) { CUnit &unit = **it; - // I don't really think that there can be any rescued units at this point. - if (unit.RescuedFrom) { - unit.Colors = &unit.RescuedFrom->UnitColors; - } else { - unit.Colors = &unit.Player->UnitColors; - } if (unit.Type->OnReady) { unit.Type->OnReady->pushPreamble(); unit.Type->OnReady->pushInteger(UnitNumber(unit)); diff --git a/src/include/color.h b/src/include/color.h index ef504838c..7366040ba 100644 --- a/src/include/color.h +++ b/src/include/color.h @@ -32,6 +32,10 @@ //@{ +#include <stdint.h> + +typedef uint32_t IntColor; // Uint32 in SDL + struct SDL_Color; struct lua_State; @@ -49,6 +53,9 @@ public: /// Cast to a SDL_Color operator SDL_Color() const; + /// Cast to IntColor + operator IntColor() const; + public: unsigned char R; /// Red unsigned char G; /// Green @@ -66,41 +73,8 @@ public: public: std::vector<CColor> Colors; - bool isCustom = false; }; -#include <stdint.h> - -class CUnitColorsOrPlayerIndex -{ -public: - CUnitColorsOrPlayerIndex(int player) { - playerIndexOrColors = static_cast<intptr_t>(player); - }; - - CUnitColorsOrPlayerIndex(CUnitColors *colors) { - playerIndexOrColors = reinterpret_cast<intptr_t>(colors); - }; - - bool isPlayer() { - // no valid pointer is smaller than PlayerMax - return playerIndexOrColors <= PlayerMax; - } - - int asPlayer() { - return static_cast<int>(playerIndexOrColors); - } - - CUnitColors *asUnitColors() { - return reinterpret_cast<CUnitColors*>(playerIndexOrColors); - } - -private: - intptr_t playerIndexOrColors; -}; - -typedef uint32_t IntColor; // Uint32 in SDL - /** * interpolate 2 RGB colors * @param color1 integer containing color as 0x00RRGGBB diff --git a/src/include/player.h b/src/include/player.h index 571ddb0f3..bfa00ee6c 100644 --- a/src/include/player.h +++ b/src/include/player.h @@ -399,9 +399,8 @@ extern int NumPlayers; /// How many player slots used extern CPlayer Players[PlayerMax]; /// All players extern CPlayer *ThisPlayer; /// Player on local computer extern bool NoRescueCheck; /// Disable rescue check -extern std::vector<CColor> PlayerColorsRGB[PlayerMax]; /// Player colors -extern std::vector<IntColor> PlayerColors[PlayerMax]; /// Player colors -extern std::string PlayerColorNames[PlayerMax]; /// Player color names +extern std::vector<std::vector<CColor>> PlayerColorsRGB; /// Player colors +extern std::vector<std::string> PlayerColorNames; /// Player color names extern PlayerRace PlayerRaces; /// Player races @@ -433,8 +432,8 @@ extern void PlayersEachCycle(); /// Called each second for a given player handler (AI) extern void PlayersEachSecond(int player); -/// Change current color set to new player of the sprite -extern void GraphicPlayerPixels(CUnitColorsOrPlayerIndex player, const CGraphic &sprite); +/// Change current color set to the player color of the sprite +extern void GraphicPlayerPixels(int colorIndex, const CGraphic &sprite); /// Output debug information for players extern void DebugPlayers(); diff --git a/src/include/unit.h b/src/include/unit.h index 9d358e0ed..877ac5d68 100644 --- a/src/include/unit.h +++ b/src/include/unit.h @@ -134,12 +134,7 @@ enum _directions_ { class CUnit { public: - CUnit() : tilePos(-1, -1), pathFinderData(NULL), SavedOrder(NULL), NewOrder(NULL), CriticalOrder(NULL) { Init(); } - ~CUnit() { - if (Colors->isCustom) { - delete Colors; - } - } + CUnit() : tilePos(-1, -1), pathFinderData(NULL), SavedOrder(NULL), NewOrder(NULL), CriticalOrder(NULL), Colors(-1) { Init(); } void Init(); @@ -354,7 +349,7 @@ public: // DISPLAY: int Frame; /// Image frame: <0 is mirrored - CUnitColors *Colors; /// Player colors + int Colors; /// custom colors bool IndividualUpgrades[UpgradeMax]; /// individual upgrades which the unit has signed char IX; /// X image displacement to map position diff --git a/src/include/unittype.h b/src/include/unittype.h index 10d2f5433..f8748f4a0 100644 --- a/src/include/unittype.h +++ b/src/include/unittype.h @@ -812,7 +812,7 @@ extern void SaveUnitTypes(CFile &file); /// Save the unit-type tabl extern CUnitType *NewUnitTypeSlot(const std::string &ident);/// Allocate an empty unit-type slot /// Draw the sprite frame of unit-type extern void DrawUnitType(const CUnitType &type, CPlayerColorGraphic *sprite, - CUnitColorsOrPlayerIndex player, int frame, const PixelPos &screenPos); + int colorIndex, int frame, const PixelPos &screenPos); extern void InitUnitTypes(int reset_player_stats); /// Init unit-type table extern void LoadUnitTypeSprite(CUnitType &unittype); /// Load the sprite for a unittype diff --git a/src/include/video.h b/src/include/video.h index 60643886e..8b83bcbf3 100644 --- a/src/include/video.h +++ b/src/include/video.h @@ -204,9 +204,9 @@ protected: } public: - void DrawPlayerColorFrameClipX(CUnitColorsOrPlayerIndex player, unsigned frame, int x, int y, + void DrawPlayerColorFrameClipX(int colorIndex, unsigned frame, int x, int y, SDL_Surface *surface = TheScreen); - void DrawPlayerColorFrameClip(CUnitColorsOrPlayerIndex player, unsigned frame, int x, int y, + void DrawPlayerColorFrameClip(int colorIndex, unsigned frame, int x, int y, SDL_Surface *surface = TheScreen); static CPlayerColorGraphic *New(const std::string &file, int w = 0, int h = 0); diff --git a/src/map/minimap.cpp b/src/map/minimap.cpp index 21fc3be85..206c583a7 100644 --- a/src/map/minimap.cpp +++ b/src/map/minimap.cpp @@ -339,7 +339,7 @@ static void DrawUnitOn(CUnit &unit, int red_phase) color = ColorGreen; } } else { - color = PlayerColors[GameSettings.Presets[unit.Player->Index].PlayerColor][0]; + color = PlayerColorsRGB[GameSettings.Presets[unit.Player->Index].PlayerColor][0]; } int mx = 1 + UI.Minimap.XOffset + Map2MinimapX[unit.tilePos.x]; diff --git a/src/stratagus/player.cpp b/src/stratagus/player.cpp index 9294bcf1f..b99645a56 100644 --- a/src/stratagus/player.cpp +++ b/src/stratagus/player.cpp @@ -318,10 +318,9 @@ bool NoRescueCheck; /// Disable rescue check /** ** Colors used for minimap. */ -std::vector<CColor> PlayerColorsRGB[PlayerMax]; -std::vector<IntColor> PlayerColors[PlayerMax]; +std::vector<std::vector<CColor>> PlayerColorsRGB; -std::string PlayerColorNames[PlayerMax]; +std::vector<std::string> PlayerColorNames; /** ** Which indexes to replace with player color @@ -375,9 +374,6 @@ void InitPlayers() if (!Players[p].Type) { Players[p].Type = PlayerNobody; } - for (int x = 0; x < PlayerColorIndexCount; ++x) { - PlayerColors[p][x] = Video.MapRGB(TheScreen->format, PlayerColorsRGB[p][x]); - } } } @@ -399,9 +395,8 @@ void FreePlayerColors() { for (int i = 0; i < PlayerMax; ++i) { Players[i].UnitColors.Colors.clear(); - PlayerColorsRGB[i].clear(); - PlayerColors[i].clear(); } + PlayerColorsRGB.clear(); } /** @@ -742,7 +737,7 @@ void CPlayer::Init(/* PlayerTypes */ int type) this->NumBuildings = 0; this->Score = 0; - this->Color = PlayerColors[NumPlayers][0]; + this->Color = PlayerColorsRGB[NumPlayers][0]; if (Players[NumPlayers].Type == PlayerComputer || Players[NumPlayers].Type == PlayerRescueActive) { this->AiEnabled = true; @@ -1257,18 +1252,12 @@ void PlayersEachSecond(int playerIdx) ** @param player Pointer to player. ** @param sprite The sprite in which the colors should be changed. */ -void GraphicPlayerPixels(CUnitColorsOrPlayerIndex colorsOrPlayer, const CGraphic &sprite) +void GraphicPlayerPixels(int colorIndex, const CGraphic &sprite) { Assert(PlayerColorIndexCount); Assert(SDL_MUSTLOCK(sprite.Surface) == 0); - std::vector<SDL_Color> sdlColors; - if (colorsOrPlayer.isPlayer()) { - CPlayer &player = Players[colorsOrPlayer.asPlayer()]; - sdlColors = std::vector<SDL_Color>(player.UnitColors.Colors.begin(), player.UnitColors.Colors.end()); - } else { - sdlColors = std::vector<SDL_Color>(colorsOrPlayer.asUnitColors()->Colors.begin(), colorsOrPlayer.asUnitColors()->Colors.end()); - } + std::vector<SDL_Color> sdlColors = std::vector<SDL_Color>(PlayerColorsRGB[colorIndex].begin(), PlayerColorsRGB[colorIndex].end()); SDL_SetPaletteColors(sprite.Surface->format->palette, &sdlColors[0], PlayerColorIndexStart, PlayerColorIndexCount); if (sprite.SurfaceFlip) { SDL_SetPaletteColors(sprite.SurfaceFlip->format->palette, &sdlColors[0], PlayerColorIndexStart, PlayerColorIndexCount); diff --git a/src/stratagus/script_player.cpp b/src/stratagus/script_player.cpp index 327a38b6c..681f79aa6 100644 --- a/src/stratagus/script_player.cpp +++ b/src/stratagus/script_player.cpp @@ -816,7 +816,8 @@ static int CclDefineRaceNames(lua_State *l) /** ** <b>Description</b> ** -** Define player colors +** Define player colors. Pass "false" as an optional second +** argument to add the colors to the existing ones. ** ** @param l Lua state. ** @@ -843,14 +844,24 @@ static int CclDefineRaceNames(lua_State *l) */ static int CclDefinePlayerColors(lua_State *l) { - LuaCheckArgs(l, 1); + int nargs = lua_gettop(l); + if (nargs < 1 || nargs > 2) { + LuaError(l, "wrong number of arguments"); + } if (!lua_istable(l, 1)) { LuaError(l, "incorrect argument"); } - const int args = lua_rawlen(l, 1); + if (nargs < 2 || LuaToBoolean(l, 2)) { + PlayerColorNames.clear(); + PlayerColorsRGB.clear(); + if (args / 2 < PlayerMax) { + LuaError(l, "You need to define at least %d colors" _C_ PlayerMax); + } + } + for (int i = 0; i < args; ++i) { - PlayerColorNames[i / 2] = LuaToString(l, 1, i + 1); + PlayerColorNames.push_back(LuaToString(l, 1, i + 1)); ++i; lua_rawgeti(l, 1, i + 1); if (!lua_istable(l, -1)) { @@ -860,11 +871,15 @@ static int CclDefinePlayerColors(lua_State *l) if (numcolors != PlayerColorIndexCount) { LuaError(l, "You should use %d colors (See DefinePlayerColorIndex())" _C_ PlayerColorIndexCount); } + std::vector<CColor> newColors; for (int j = 0; j < numcolors; ++j) { lua_rawgeti(l, -1, j + 1); - PlayerColorsRGB[i / 2][j].Parse(l); + CColor newColor; + newColor.Parse(l); + newColors.push_back(newColor); lua_pop(l, 1); } + PlayerColorsRGB.push_back(newColors); } return 0; @@ -894,12 +909,7 @@ static int CclDefinePlayerColorIndex(lua_State *l) PlayerColorIndexStart = LuaToNumber(l, 1); PlayerColorIndexCount = LuaToNumber(l, 2); - for (int i = 0; i < PlayerMax; ++i) { - PlayerColorsRGB[i].clear(); - PlayerColorsRGB[i].resize(PlayerColorIndexCount); - PlayerColors[i].clear(); - PlayerColors[i].resize(PlayerColorIndexCount, 0); - } + PlayerColorsRGB.clear(); return 0; } diff --git a/src/ui/mainscr.cpp b/src/ui/mainscr.cpp index 7c619b990..4dc1293df 100644 --- a/src/ui/mainscr.cpp +++ b/src/ui/mainscr.cpp @@ -1109,7 +1109,7 @@ static void InfoPanel_draw_no_selection() label.Draw(x + 15, y, i); Video.DrawRectangleClip(ColorWhite, x, y, 12, 12); - Video.FillRectangleClip(PlayerColors[GameSettings.Presets[i].PlayerColor][0], x + 1, y + 1, 10, 10); + Video.FillRectangleClip(PlayerColorsRGB[GameSettings.Presets[i].PlayerColor][0], x + 1, y + 1, 10, 10); label.Draw(x + 27, y, Players[i].Name); label.Draw(x + 117, y, Players[i].Score); diff --git a/src/unit/script_unit.cpp b/src/unit/script_unit.cpp index 5237d98b8..31cda4480 100644 --- a/src/unit/script_unit.cpp +++ b/src/unit/script_unit.cpp @@ -606,11 +606,6 @@ static int CclUnit(lua_State *l) MapMarkUnitSight(*unit); } - // Fix Colors for rescued units. - if (unit->RescuedFrom) { - unit->Colors = &unit->RescuedFrom->UnitColors; - } - return 0; } @@ -1313,25 +1308,19 @@ static int CclSetUnitVariable(lua_State *l) value = LuaToNumber(l, 3); unit->ChangeOwner(Players[value]); } else if (!strcmp(name, "Color")) { - if (lua_istable(l, 3)) { - const int numcolors = lua_rawlen(l, 3); - if (numcolors != PlayerColorIndexCount) { - LuaError(l, "You should use %d, not %d colors (See DefinePlayerColorIndex())" _C_ PlayerColorIndexCount _C_ numcolors); + if (lua_isstring(l, 3)) { + const char *colorName = LuaToString(l, 3); + for (size_t i = 0; i < PlayerColorNames.size(); i++) { + if (PlayerColorNames[i] == colorName) { + unit->Colors = i; + break; + } } - CUnitColors *customColor = new CUnitColors; - customColor->isCustom = true; - for (int j = 0; j < numcolors; ++j) { - lua_rawgeti(l, 3, j + 1); - CColor color; - color.Parse(l); - customColor->Colors.push_back(color); - lua_pop(l, 1); - } - unit->Colors = customColor; + } else if (lua_isnil(l, 3)) { + unit->Colors = -1; } else { value = LuaToNumber(l, 3); - unit->Colors = &Players[value].UnitColors; - unit->RescuedFrom = &Players[value]; + unit->Colors = value; } } else if (!strcmp(name, "TTL")) { value = LuaToNumber(l, 3); diff --git a/src/unit/unit.cpp b/src/unit/unit.cpp index 47ab04328..cb0a3c532 100644 --- a/src/unit/unit.cpp +++ b/src/unit/unit.cpp @@ -429,7 +429,7 @@ void CUnit::Init() pathFinderData = new PathFinderData; pathFinderData->input.SetUnit(*this); - Colors = NULL; + Colors = -1; IX = 0; IY = 0; Frame = 0; @@ -746,7 +746,6 @@ void CUnit::AssignToPlayer(CPlayer &player) } Player = &player; Stats = &type.Stats[Player->Index]; - Colors = &player.UnitColors; if (!SaveGameLoading) { if (UnitTypeVar.GetNumberVariable()) { Assert(Variable); diff --git a/src/unit/unit_draw.cpp b/src/unit/unit_draw.cpp index 19e3a9579..e2147fdd5 100644 --- a/src/unit/unit_draw.cpp +++ b/src/unit/unit_draw.cpp @@ -146,11 +146,11 @@ void DrawUnitSelection(const CViewport &vp, const CUnit &unit) } else if (ThisPlayer->IsEnemy(unit)) { color = ColorRed; } else { - color = PlayerColors[GameSettings.Presets[unit.Player->Index].PlayerColor][0]; + color = PlayerColorsRGB[GameSettings.Presets[unit.Player->Index].PlayerColor][0]; for (int i = 0; i < PlayerMax; ++i) { if (unit.TeamSelected & (1 << i)) { - color = PlayerColors[GameSettings.Presets[i].PlayerColor][0]; + color = PlayerColorsRGB[GameSettings.Presets[i].PlayerColor][0]; } } } @@ -988,13 +988,13 @@ void CUnit::Draw(const CViewport &vp) const const PixelPos pos(screenPos + (type->GetPixelSize()) / 2); DrawConstruction(GameSettings.Presets[player].PlayerColor, cframe, *type, frame, pos); } else { - DrawUnitType(*type, sprite, CUnitColorsOrPlayerIndex(GameSettings.Presets[player].PlayerColor), frame, screenPos); + DrawUnitType(*type, sprite, GameSettings.Presets[player].PlayerColor, frame, screenPos); } // // Draw the future unit type, if upgrading to it. // } else { - DrawUnitType(*type, sprite, CUnitColorsOrPlayerIndex(Colors), frame, screenPos); + DrawUnitType(*type, sprite, Colors < 0 ? GameSettings.Presets[player].PlayerColor : Colors, frame, screenPos); } // Unit's extras not fully supported.. need to be decorations themselves. diff --git a/src/unit/unittype.cpp b/src/unit/unittype.cpp index 31649a015..5d2f69ffe 100644 --- a/src/unit/unittype.cpp +++ b/src/unit/unittype.cpp @@ -891,7 +891,7 @@ CUnitType *NewUnitTypeSlot(const std::string &ident) ** @todo Do screen position caculation in high level. ** Better way to handle in x mirrored sprites. */ -void DrawUnitType(const CUnitType &type, CPlayerColorGraphic *sprite, CUnitColorsOrPlayerIndex player, int frame, const PixelPos &screenPos) +void DrawUnitType(const CUnitType &type, CPlayerColorGraphic *sprite, int colorIndex, int frame, const PixelPos &screenPos) { PixelPos pos = screenPos; // FIXME: move this calculation to high level. @@ -902,9 +902,9 @@ void DrawUnitType(const CUnitType &type, CPlayerColorGraphic *sprite, CUnitColor if (type.Flip) { if (frame < 0) { - sprite->DrawPlayerColorFrameClipX(player, -frame - 1, pos.x, pos.y); + sprite->DrawPlayerColorFrameClipX(colorIndex, -frame - 1, pos.x, pos.y); } else { - sprite->DrawPlayerColorFrameClip(player, frame, pos.x, pos.y); + sprite->DrawPlayerColorFrameClip(colorIndex, frame, pos.x, pos.y); } } else { const int row = type.NumDirections / 2 + 1; @@ -914,7 +914,7 @@ void DrawUnitType(const CUnitType &type, CPlayerColorGraphic *sprite, CUnitColor } else { frame = (frame / row) * type.NumDirections + frame % row; } - sprite->DrawPlayerColorFrameClip(player, frame, pos.x, pos.y); + sprite->DrawPlayerColorFrameClip(colorIndex, frame, pos.x, pos.y); } } diff --git a/src/video/color.cpp b/src/video/color.cpp index c0f0a6cd1..9e8331661 100644 --- a/src/video/color.cpp +++ b/src/video/color.cpp @@ -30,11 +30,8 @@ //@{ #include "stratagus.h" - #include "color.h" - #include "script.h" - #include "SDL.h" CColor::operator SDL_Color() const @@ -43,6 +40,13 @@ CColor::operator SDL_Color() const return c; } +extern SDL_Surface *TheScreen; + +CColor::operator IntColor() const +{ + return SDL_MapRGB(TheScreen->format, R, G, B); +} + void CColor::Parse(lua_State *l, const int offset) { if (!lua_istable(l, offset) || lua_rawlen(l, offset) != 3) { diff --git a/src/video/graphic.cpp b/src/video/graphic.cpp index bb27bec54..f09d6bf88 100644 --- a/src/video/graphic.cpp +++ b/src/video/graphic.cpp @@ -306,11 +306,11 @@ void CGraphic::DrawFrameClipCustomMod(unsigned frame, int x, int y, ** @param y y coordinate on the target surface ** @param surface target surface */ -void CPlayerColorGraphic::DrawPlayerColorFrameClip(CUnitColorsOrPlayerIndex player, unsigned frame, +void CPlayerColorGraphic::DrawPlayerColorFrameClip(int colorIndex, unsigned frame, int x, int y, SDL_Surface *surface /*= TheScreen*/) { - GraphicPlayerPixels(player, *this); + GraphicPlayerPixels(colorIndex, *this); DrawFrameClip(frame, x, y, surface); } @@ -397,11 +397,11 @@ void CGraphic::DrawFrameClipTransX(unsigned frame, int x, int y, int alpha, ** @param y y coordinate on the target surface ** @param surface target surface */ -void CPlayerColorGraphic::DrawPlayerColorFrameClipX(CUnitColorsOrPlayerIndex player, unsigned frame, +void CPlayerColorGraphic::DrawPlayerColorFrameClipX(int colorIndex, unsigned frame, int x, int y, SDL_Surface *surface /*= TheScreen*/) { - GraphicPlayerPixels(player, *this); + GraphicPlayerPixels(colorIndex, *this); DrawFrameClipX(frame, x, y, surface); }