add ability to define additional colors and set custom unit color

This commit is contained in:
Tim Felgentreff 2022-02-11 22:07:54 +01:00
parent c5baa3dce7
commit 45393ef64c
17 changed files with 76 additions and 123 deletions

View file

@ -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);
}

View file

@ -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));

View file

@ -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

View file

@ -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();

View file

@ -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

View file

@ -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

View file

@ -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);

View file

@ -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];

View file

@ -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);

View file

@ -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;
}

View file

@ -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);

View file

@ -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);

View file

@ -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);

View file

@ -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.

View file

@ -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);
}
}

View file

@ -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) {

View file

@ -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);
}