[+] Ability to view unit's dependencies in button popup

[+] Ability to show button in grayscale if not available
[+] Ability to view number of free workers
[+] Some enhancement in button popup system
[+] Upgrades could now have a name
[*] Correction of AI rally point finder and attacking
[-] Incorrect SetPlayerData for SpeedUpgrade
This commit is contained in:
cybermind 2012-11-10 21:19:15 +06:00
parent 48e338c83b
commit c7d7ca33d9
22 changed files with 469 additions and 73 deletions

View file

@ -94,6 +94,18 @@ private:
const CUnit **enemy;
};
class IsAnAlliedUnitOf
{
public:
explicit IsAnAlliedUnitOf(const CPlayer &_player) : player(&_player) {}
bool operator()(const CUnit *unit) const {
return unit->IsVisibleAsGoal(*player) && (unit->Player->Index == player->Index
|| unit->IsAllied(*player));
}
private:
const CPlayer *player;
};
/*----------------------------------------------------------------------------
-- Variables
----------------------------------------------------------------------------*/
@ -305,9 +317,9 @@ private:
VisitResult AiForceRallyPointFinder::Visit(TerrainTraversal &terrainTraversal, const Vec2i &pos, const Vec2i &from)
{
if (AiEnemyUnitsInDistance(*startUnit.Player, NULL, pos, 20) == false
&& Distance(pos, startPos) <= distance) {
*resultPos = pos;
return VisitResult_Finished;
&& Distance(pos, startPos) <= abs(distance - 20)) {
*resultPos = pos;
return VisitResult_Finished;
}
if (CanMoveToMask(pos, movemask)) { // reachable
return VisitResult_Ok;
@ -330,7 +342,7 @@ bool AiForce::NewRallyPoint(const Vec2i &startPos, Vec2i *resultPos)
Assert(Map.Info.IsPointOnMap(startPos));
terrainTraversal.PushPos(startPos);
AiForceRallyPointFinder aiForceRallyPointFinder(leader, distance, startPos, resultPos);
AiForceRallyPointFinder aiForceRallyPointFinder(leader, distance, leader.tilePos, resultPos);
return terrainTraversal.Run(aiForceRallyPointFinder);
}
@ -797,21 +809,42 @@ void AiForce::Update()
return;
}
const int thresholdDist = 5; // Hard coded value
Assert(Map.Info.IsPointOnMap(GoalPos));
if (State == AiForceAttackingState_GoingToRallyPoint) {
// Check if we are near the goalpos
if (Units[0]->MapDistanceTo(GoalPos) <= 20) {
int maxDist, minDist;
maxDist = minDist = Units[0]->MapDistanceTo(this->GoalPos);
// We must put away all units which are too far from main group
for (size_t i = 0; i != Size(); ++i) {
const int distance = Units[i]->MapDistanceTo(this->GoalPos);
minDist = std::min(minDist, Units[i]->MapDistanceTo(this->GoalPos));
}
for (size_t i = 0; i != Size(); ++i) {
const int distance = Units[i]->MapDistanceTo(this->GoalPos);
// Don't count units which are too far away from main group
if (abs(minDist - distance) > thresholdDist * 8) {
continue;
}
maxDist = std::max(maxDist, Units[i]->MapDistanceTo(this->GoalPos));
}
if (maxDist <= thresholdDist) {
const CUnit *unit = NULL;
AiForceEnemyFinder<AIATTACK_BUILDING>(*this, &unit);
if (!unit) {
// No enemy found, give up
// FIXME: should the force go home or keep trying to attack?
DebugPrint("%d: Attack force #%lu can't find a target, giving up\n"
_C_ AiPlayer->Player->Index _C_(long unsigned int)(this - & (AiPlayer->Force[0])));
Attacking = false;
State = AiForceAttackingState_Waiting;
return;
AiForceEnemyFinder<AIATTACK_ALLMAP>(*this, &unit);
if (!unit) {
// No enemy found, give up
// FIXME: should the force go home or keep trying to attack?
DebugPrint("%d: Attack force #%lu can't find a target, giving up\n"
_C_ AiPlayer->Player->Index _C_(long unsigned int)(this - & (AiPlayer->Force[0])));
Attacking = false;
State = AiForceAttackingState_Waiting;
return;
}
}
this->GoalPos = unit->tilePos;
State = AiForceAttackingState_Attacking;
@ -839,7 +872,6 @@ void AiForce::Update()
}
if (State == AiForceAttackingState_Attacking) {
const int thresholdDist = 5; // Hard coded value
int maxDist = 0;
for (size_t i = 0; i != Size(); ++i) {
@ -894,25 +926,35 @@ void AiForceManager::Update()
force.ReturnToHome();
}
} else { // Find idle units and order them to defend
std::vector<CUnit *> idleUnits;
for (unsigned int i = 0; i != force.Size(); ++i) {
CUnit &aiunit = *force.Units[i];
// Don't attack if there aren't our units near goal point
std::vector<CUnit *> nearGoal;
const int range = force.Units[0]->Type->ReactRangeComputer;
const Vec2i offset(15, 15);
Select(force.GoalPos - offset, force.GoalPos + offset, nearGoal,
IsAnAlliedUnitOf(*force.Units[0]->Player));
if (nearGoal.empty()) {
force.ReturnToHome();
} else {
std::vector<CUnit *> idleUnits;
for (unsigned int i = 0; i != force.Size(); ++i) {
CUnit &aiunit = *force.Units[i];
if (aiunit.IsIdle() && aiunit.IsAliveOnMap()) {
idleUnits.push_back(&aiunit);
if (aiunit.IsIdle() && aiunit.IsAliveOnMap()) {
idleUnits.push_back(&aiunit);
}
}
}
for (unsigned int i = 0; i != idleUnits.size(); ++i) {
CUnit *const unit = idleUnits[i];
for (unsigned int i = 0; i != idleUnits.size(); ++i) {
CUnit *const unit = idleUnits[i];
if (unit->Container == NULL) {
const int delay = i / 5; // To avoid lot of CPU consuption, send them with a small time difference.
if (unit->Container == NULL) {
const int delay = i / 5; // To avoid lot of CPU consuption, send them with a small time difference.
unit->Wait = delay;
if (unit->Type->CanAttack) {
CommandAttack(*unit, force.GoalPos, NULL, FlushCommands);
} else {
CommandMove(*unit, force.GoalPos, FlushCommands);
unit->Wait = delay;
if (unit->Type->CanAttack) {
CommandAttack(*unit, force.GoalPos, NULL, FlushCommands);
} else {
CommandMove(*unit, force.GoalPos, FlushCommands);
}
}
}
}

View file

@ -940,6 +940,7 @@ void CleanGame()
EndReplayLog();
CleanMessages();
RestoreColorCyclingSurface();
CleanGame_Lua();
CleanTriggers();
CleanAi();
@ -951,7 +952,6 @@ void CleanGame()
Map.Clean();
CleanReplayLog();
FreePathfinder();
RestoreColorCyclingSurface();
CursorBuilding = NULL;
UnitUnderCursor = NULL;
}

View file

@ -97,6 +97,7 @@
class CPlayer;
class CUnitType;
class CUpgrade;
class ButtonAction;
enum {
DependRuleUnitType, /// Kind is an unit-type
@ -128,6 +129,8 @@ extern void InitDependencies();
/// Cleanup dependencies module
extern void CleanDependencies();
/// Print all unit dependencies into string
extern std::string PrintDependencies(const CPlayer &player, const ButtonAction &button);
/// Check a dependency by identifier
extern bool CheckDependByIdent(const CPlayer &player, const std::string &target);
/// Check a dependency by unit type

View file

@ -116,6 +116,8 @@ public:
/// Draw icon
void DrawIcon(const CPlayer &player, const PixelPos &pos) const;
/// Draw grayscale icon
void DrawGrayscaleIcon(const PixelPos &pos) const;
/// Draw icon of a unit
void DrawUnitIcon(const ButtonStyle &style,
unsigned flags, const PixelPos &pos, const std::string &text) const;

View file

@ -86,11 +86,12 @@ typedef bool (*ButtonCheckFunc)(const CUnit &, const ButtonAction &);
class ButtonAction
{
public:
ButtonAction() : Pos(0), Level(0), Action(ButtonMove), Value(0),
ButtonAction() : Pos(0), Level(0), Action(ButtonMove), Value(0), AlwaysShow(false),
Allowed(NULL), Key(0) {}
int Pos; /// button position in the grid
int Level; /// requires button level
bool AlwaysShow; /// button is always shown but drawn grayscale if not available
ButtonCmd Action; /// command on button press
int Value; /// extra value for command
std::string ValueStr; /// keep original value string
@ -261,7 +262,9 @@ extern int AddButton(int pos, int level, const std::string &IconIdent,
ButtonCmd action, const std::string &value, const ButtonCheckFunc func,
const std::string &arg, const std::string &hint, const std::string &descr,
const std::string &sound, const std::string &cursor, const std::string &umask,
const std::string &popup);
const std::string &popup, bool alwaysShow);
// Check if the button is allowed for the unit.
extern bool IsButtonAllowed(const CUnit &unit, const ButtonAction &buttonaction);
//
// in mouse.cpp

View file

@ -132,6 +132,8 @@ public:
CUnitColors UnitColors; /// Unit colors for new units
std::vector<CUnit *> FreeWorkers; /// Container for free workers
// Upgrades/Allows:
CAllow Allow; /// Allowed for player
CUpgradeTimers UpgradeTimers; /// Timer for the upgrades
@ -152,6 +154,7 @@ public:
void AddUnit(CUnit &unit);
void RemoveUnit(CUnit &unit);
void UpdateFreeWorkers();
/// Get a resource of the player
int GetResource(const int resource, const int type);

View file

@ -445,7 +445,8 @@ public:
class PopupConditionPanel
{
public:
PopupConditionPanel() : HasHint(false), HasDescription(false), BoolFlags(NULL), Variables(NULL) {}
PopupConditionPanel() : HasHint(false), HasDescription(false), HasDependencies(false),
ButtonAction(-1), BoolFlags(NULL), Variables(NULL) {}
~PopupConditionPanel() {
delete[] BoolFlags;
delete[] Variables;
@ -453,6 +454,9 @@ public:
bool HasHint; /// check if button has hint.
bool HasDescription; /// check if button has description.
bool HasDependencies; /// check if button has dependencies or restrictions.
int ButtonAction; /// action type of button
std::string ButtonValue; /// value used in ValueStr field of button
char *BoolFlags; /// array of condition about user flags.
char *Variables; /// array of variable to verify (enable and max > 0)
@ -489,13 +493,14 @@ public:
enum PopupButtonInfo_Types {
PopupButtonInfo_Hint,
PopupButtonInfo_Description
PopupButtonInfo_Description,
PopupButtonInfo_Dependencies
};
class CPopupContentTypeButtonInfo : public CPopupContentType
{
public:
CPopupContentTypeButtonInfo() : InfoType(0), MaxWidth(0), Font(NULL), Centered(0) {}
CPopupContentTypeButtonInfo() : InfoType(0), MaxWidth(0), Font(NULL) {}
virtual ~CPopupContentTypeButtonInfo() {}
virtual void Draw(int x, int y, const CPopup *popup, const unsigned int popupWidth, const ButtonAction &button, int *Costs) const;
@ -506,7 +511,22 @@ public:
int InfoType; /// Type of information to show.
unsigned int MaxWidth; /// Maximum width of multilined information.
CFont *Font; /// Font to use.
char Centered; /// if true, center the display.
};
class CPopupContentTypeText : public CPopupContentType
{
public:
CPopupContentTypeText() : MaxWidth(0), Font(NULL) {}
virtual ~CPopupContentTypeText() {}
virtual void Draw(int x, int y, const CPopup *popup, const unsigned int popupWidth, const ButtonAction &button, int *Costs) const;
virtual int GetWidth(const ButtonAction &button, int *Costs) const;
virtual int GetHeight(const ButtonAction &button, int *Costs) const;
std::string Text; /// Text to display
unsigned int MaxWidth; /// Maximum width of multilined text.
CFont *Font; /// Font to use.
};
class CPopupContentTypeCosts : public CPopupContentType
@ -591,7 +611,7 @@ public:
int TextX; /// text X position
int TextY; /// text Y position
};
#define MaxResourceInfo MaxCosts + 3 /// +3 for food and score and mana
#define MaxResourceInfo MaxCosts + 4 /// +4 for food and score and mana and free workers count
class CInfoPanel
{

View file

@ -73,6 +73,7 @@ enum CostType {
#define FoodCost MaxCosts
#define ScoreCost (MaxCosts + 1)
#define ManaResCost (MaxCosts + 2)
#define FreeWorkersCount (MaxCosts + 3)
/**
** Default resources for a new player.
@ -159,6 +160,7 @@ public:
void SetIcon(CIcon *icon);
std::string Ident; /// identifier
std::string Name; /// upgrade label
int ID; /// numerical id
int Costs[MaxCosts]; /// costs for the upgrade
// TODO: not used by buttons

View file

@ -215,9 +215,10 @@ static Target *SelectTargetUnitsOfAutoCast(CUnit &caster, const SpellType &spell
// Check every unit if it is hostile
bool inCombat = false;
for (size_t i = 0; i < table.size(); ++i) {
if (caster.IsEnemy(*table[i]) && !table[i]->Type->Coward) {
inCombat = true;
break;
if (table[i]->IsVisibleAsGoal(*caster.Player) && caster.IsEnemy(*table[i])
&& CanTarget(caster.Type, table[i]->Type)) {
inCombat = true;
break;
}
}

View file

@ -39,6 +39,7 @@
#include "player.h"
#include "actions.h"
#include "ai.h"
#include "iolib.h"
#include "map.h"
@ -583,6 +584,7 @@ void CreatePlayer(int type)
void CPlayer::Init(/* PlayerTypes */ int type)
{
this->Units.resize(0);
this->FreeWorkers.resize(0);
// Take first slot for person on this computer,
// fill other with computer players.
@ -754,6 +756,7 @@ void CPlayer::Clear()
AiEnabled = false;
Ai = 0;
this->Units.resize(0);
this->FreeWorkers.resize(0);
NumBuildings = 0;
Supply = 0;
Demand = 0;
@ -805,6 +808,20 @@ void CPlayer::RemoveUnit(CUnit &unit)
Assert(last == &unit || this->Units[last->PlayerSlot] == last);
}
void CPlayer::UpdateFreeWorkers()
{
FreeWorkers.clear();
const int nunits = this->GetUnitCount();
for (int i = 0; i < nunits; ++i) {
CUnit &unit = this->GetUnit(i);
if (unit.Type->Harvester && unit.Type->ResInfo && !unit.Removed) {
if (unit.CurrentAction() == UnitActionStill) {
FreeWorkers.push_back(&unit);
}
}
}
}
std::vector<CUnit *>::const_iterator CPlayer::UnitBegin() const
@ -1147,6 +1164,8 @@ void PlayersEachSecond(int playerIdx)
if (player.AiEnabled) {
AiEachSecond(player);
}
player.UpdateFreeWorkers();
}
/**

View file

@ -94,6 +94,7 @@ void CPlayer::Load(lua_State *l)
const int args = lua_gettop(l);
this->Units.resize(0);
this->FreeWorkers.resize(0);
// j = 0 represent player Index.
for (int j = 1; j < args; ++j) {
@ -891,7 +892,7 @@ static int CclSetPlayerData(lua_State *l)
} else if (!strcmp(data, "SpeedTrain")) {
p->SpeedTrain = LuaToNumber(l, 3);
} else if (!strcmp(data, "SpeedUpgrade")) {
p->SpeedTrain = LuaToNumber(l, 3);
p->SpeedUpgrade = LuaToNumber(l, 3);
} else if (!strcmp(data, "SpeedResearch")) {
p->SpeedResearch = LuaToNumber(l, 3);
} else {

View file

@ -50,7 +50,8 @@ $]
#define FoodCost MaxCosts
#define ScoreCost MaxCosts + 1
#define ManaResCost MaxCosts + 2
#define MaxResourceInfo MaxCosts + 3
#define FreeWorkersCount MaxCosts + 3
#define MaxResourceInfo MaxCosts + 4
#define PlayerMax 16
#define PlayerNumNeutral (PlayerMax - 1)

View file

@ -3,6 +3,7 @@ class CUpgrade
static CUpgrade *New(const std::string ident);
static CUpgrade *Get(const std::string ident);
std::string Name;
int Costs[MaxCosts];
CIcon *Icon;
};

View file

@ -101,7 +101,8 @@ void InitButtons()
int AddButton(int pos, int level, const std::string &icon_ident,
ButtonCmd action, const std::string &value, const ButtonCheckFunc func,
const std::string &allow, const std::string &hint, const std::string &descr,
const std::string &sound, const std::string &cursor, const std::string &umask, const std::string &popup)
const std::string &sound, const std::string &cursor, const std::string &umask,
const std::string &popup, bool alwaysShow)
{
char buf[2048];
ButtonAction *ba = new ButtonAction;
@ -109,6 +110,7 @@ int AddButton(int pos, int level, const std::string &icon_ident,
ba->Pos = pos;
ba->Level = level;
ba->AlwaysShow = alwaysShow;
ba->Icon.Name = icon_ident;
// FIXME: check if already initited
//ba->Icon.Load();
@ -331,14 +333,28 @@ static int GetButtonStatus(const ButtonAction &button, int UnderCursor)
case PopupButtonInfo_Description:
draw = button.Description;
break;
case PopupButtonInfo_Dependencies:
draw = PrintDependencies(*ThisPlayer, button);
break;
}
return this->MaxWidth ? std::min((unsigned int)font.getWidth(draw), this->MaxWidth) : font.getWidth(draw);
int width = 0;
std::string sub;
if (draw.length()) {
if (this->MaxWidth) {
return std::min((unsigned int)font.getWidth(draw), this->MaxWidth);
}
int i = 1;
while (!(sub = GetLineFont(i++, draw, 0, &font)).empty()) {
width = std::max(width, font.getWidth(sub));
}
}
return width;
}
/* virtual */ int CPopupContentTypeButtonInfo::GetHeight(const ButtonAction &button, int *) const
{
CFont &font = this->Font ? *this->Font : GetSmallFont();
int height = font.Height();
int height = 0;
std::string draw("");
switch (this->InfoType) {
case PopupButtonInfo_Hint:
@ -347,8 +363,11 @@ static int GetButtonStatus(const ButtonAction &button, int UnderCursor)
case PopupButtonInfo_Description:
draw = button.Description;
break;
case PopupButtonInfo_Dependencies:
draw = PrintDependencies(*ThisPlayer, button);
break;
}
if (this->MaxWidth && draw.length()) {
if (draw.length()) {
int i = 1;
while ((GetLineFont(i++, draw, this->MaxWidth, &font)).length()) {
height += font.Height() + 2;
@ -369,19 +388,66 @@ static int GetButtonStatus(const ButtonAction &button, int UnderCursor)
case PopupButtonInfo_Description:
draw = button.Description;
break;
case PopupButtonInfo_Dependencies:
draw = PrintDependencies(*ThisPlayer, button);
break;
}
std::string sub(draw);
if (this->MaxWidth && draw.length()) {
if (draw.length()) {
int i = 0;
int y_off = y;
unsigned int width = std::min(this->MaxWidth, popupWidth - 2 * popup->MarginX);
unsigned int width = this->MaxWidth
? std::min(this->MaxWidth, popupWidth - 2 * popup->MarginX)
: 0;
while ((sub = GetLineFont(++i, draw, width, &font)).length()) {
label.Draw(x, y_off, sub);
y_off += font.Height() + 2;
}
return;
}
label.Draw(x, y, sub);
}
/* virtual */ int CPopupContentTypeText::GetWidth(const ButtonAction &button, int *) const
{
CFont &font = this->Font ? *this->Font : GetSmallFont();
int width = 0;
std::string sub;
if (this->MaxWidth) {
return std::min((unsigned int)font.getWidth(this->Text), this->MaxWidth);
}
int i = 1;
while (!(sub = GetLineFont(i++, this->Text, 0, &font)).empty()) {
width = std::max(width, font.getWidth(sub));
}
return width;
}
/* virtual */ int CPopupContentTypeText::GetHeight(const ButtonAction &button, int *) const
{
CFont &font = this->Font ? *this->Font : GetSmallFont();
int height = 0;
int i = 1;
while ((GetLineFont(i++, this->Text, this->MaxWidth, &font)).length()) {
height += font.Height() + 2;
}
return height;
}
/* virtual */ void CPopupContentTypeText::Draw(int x, int y, const CPopup *popup, const unsigned int popupWidth, const ButtonAction &button, int *) const
{
CFont &font = this->Font ? *this->Font : GetSmallFont();
CLabel label(font, this->TextColor, this->HighlightColor);
std::string sub;
int i = 0;
int y_off = y;
unsigned int width = this->MaxWidth
? std::min(this->MaxWidth, popupWidth - 2 * popup->MarginX)
: 0;
while ((sub = GetLineFont(++i, this->Text, width, &font)).length()) {
label.Draw(x, y_off, sub);
y_off += font.Height() + 2;
}
}
/* virtual */ int CPopupContentTypeCosts::GetWidth(const ButtonAction &button, int *Costs) const
@ -587,6 +653,18 @@ static bool CanShowPopupContent(const PopupConditionPanel *condition,
return false;
}
if (condition->HasDependencies && PrintDependencies(*ThisPlayer, button).empty()) {
return false;
}
if (condition->ButtonAction != -1 && button.Action != condition->ButtonAction) {
return false;
}
if (condition->ButtonValue.empty() == false && button.ValueStr != condition->ButtonValue) {
return false;
}
if (type && condition->BoolFlags && !type->CheckUserBoolFlags(condition->BoolFlags)) {
return false;
}
@ -958,6 +1036,13 @@ void CButtonPanel::Draw()
continue;
}
Assert(buttons[i].Pos == i + 1);
bool gray = false;
for (int j = 0; j < NumSelected; ++j) {
if (!IsButtonAllowed(*Selected[j], buttons[i])) {
gray = true;
break;
}
}
//
// Tutorial show command key in icons
//
@ -976,9 +1061,14 @@ void CButtonPanel::Draw()
// Draw main Icon.
//
const PixelPos pos(UI.ButtonPanel.Buttons[i].X, UI.ButtonPanel.Buttons[i].Y);
buttons[i].Icon.Icon->DrawUnitIcon(*UI.ButtonPanel.Buttons[i].Style,
GetButtonStatus(buttons[i], ButtonUnderCursor),
pos, buf);
if (gray) {
buttons[i].Icon.Icon->DrawGrayscaleIcon(pos);
} else {
buttons[i].Icon.Icon->DrawUnitIcon(*UI.ButtonPanel.Buttons[i].Style,
GetButtonStatus(buttons[i], ButtonUnderCursor),
pos, buf);
}
//
// Update status line for this button
@ -1034,7 +1124,7 @@ void UpdateStatusLineForButton(const ButtonAction &button)
** @todo FIXME: better check. (dependancy, resource, ...)
** @todo FIXME: make difference with impossible and not yet researched.
*/
static bool IsButtonAllowed(const CUnit &unit, const ButtonAction &buttonaction)
bool IsButtonAllowed(const CUnit &unit, const ButtonAction &buttonaction)
{
if (buttonaction.Allowed) {
return buttonaction.Allowed(unit, buttonaction);
@ -1152,13 +1242,17 @@ static ButtonAction *UpdateButtonPanelMultipleUnits()
&& !strstr(UnitButtonTable[z]->UnitMask.c_str(), unit_ident)) {
continue;
}
bool allow = true;
for (int i = 0; i < NumSelected; i++) {
if (!IsButtonAllowed(*Selected[i], *UnitButtonTable[z])) {
allow = false;
break;
if (UnitButtonTable[z]->AlwaysShow == false) {
for (int i = 0; i < NumSelected; i++) {
if (!IsButtonAllowed(*Selected[i], *UnitButtonTable[z])) {
allow = false;
break;
}
}
}
Assert(1 <= UnitButtonTable[z]->Pos);
Assert(UnitButtonTable[z]->Pos <= (int)UI.ButtonPanel.Buttons.size());
@ -1222,8 +1316,15 @@ static ButtonAction *UpdateButtonPanelSingleUnit(const CUnit &unit)
int allow = IsButtonAllowed(unit, buttonaction);
int pos = buttonaction.Pos;
// Special case for researches
int researchCheck = true;
if (buttonaction.AlwaysShow && !allow && buttonaction.Action == ButtonResearch
&& UpgradeIdentAllowed(*unit.Player, buttonaction.ValueStr) == 'R') {
researchCheck = false;
}
// is button allowed after all?
if (allow) {
if ((buttonaction.AlwaysShow && res[pos - 1].Pos == -1 && researchCheck) || allow) {
// OverWrite, So take last valid button.
res[pos - 1] = buttonaction;
}
@ -1281,6 +1382,9 @@ void CButtonPanel::DoClicked(int button)
if (!CurrentButtons.IsValid()) {
return;
}
if (IsButtonAllowed(*Selected[0], CurrentButtons[button]) == false) {
return;
}
//
// Button not available.
// or Not Teamed

View file

@ -132,6 +132,34 @@ void CIcon::DrawIcon(const CPlayer &player, const PixelPos &pos) const
}
}
/**
** Draw icon at pos.
**
** @param player Player pointer used for icon colors
** @param pos display pixel position
*/
void CIcon::DrawGrayscaleIcon(const PixelPos &pos) const
{
SDL_LockSurface(this->G->Surface);
SDL_Color colors[256], backup[256];
SDL_Palette &pal = *this->G->Surface->format->palette;
memcpy(backup, pal.colors, sizeof(SDL_Color) * 256);
for(int i = 0; i < 256; ++i){
int gray = 0.2 * pal.colors[i].r + 0.4 * pal.colors[i].g + 0.12 * pal.colors[i].b;
colors[i].r = colors[i].g = colors[i].b = gray;
}
SDL_SetColors(this->G->Surface, &colors[0], 0, 256);
if (this->G->SurfaceFlip) {
SDL_SetColors(this->G->SurfaceFlip, &colors[0], 0, 256);
}
SDL_UnlockSurface(this->G->Surface);
this->G->DrawFrameClip(this->Frame, pos.x, pos.y);
SDL_LockSurface(this->G->Surface);
SDL_SetColors(this->G->Surface, &backup[0], 0, 256);
SDL_UnlockSurface(this->G->Surface);
}
/**
** Draw unit icon 'icon' with border on x,y
**

View file

@ -440,13 +440,12 @@ static void UiToggleTerrain()
*/
static void UiFindIdleWorker()
{
// FIXME: static variable, is not needed.
static CUnit *LastIdleWorker = NULL;
CUnit *unit = FindIdleWorker(*ThisPlayer, LastIdleWorker);
if (ThisPlayer->FreeWorkers.empty()) {
return;
}
CUnit *unit = ThisPlayer->FreeWorkers[0];
if (unit != NULL) {
LastIdleWorker = unit;
SelectSingleUnit(*unit);
UI.StatusLine.Clear();
ClearCosts();

View file

@ -796,7 +796,7 @@ void DrawResources()
CLabel label(GetGameFont());
// Draw all icons of resource.
for (int i = 0; i <= ManaResCost; ++i) {
for (int i = 0; i <= FreeWorkersCount; ++i) {
if (UI.Resources[i].G) {
UI.Resources[i].G->DrawFrameClip(UI.Resources[i].IconFrame,
UI.Resources[i].IconX, UI.Resources[i].IconY);
@ -836,6 +836,12 @@ void DrawResources()
label.SetFont(score > 99999 ? GetSmallFont() : GetGameFont());
label.Draw(UI.Resources[ScoreCost].TextX, UI.Resources[ScoreCost].TextY + (score > 99999) * 3, score);
}
if (UI.Resources[FreeWorkersCount].TextX != -1) {
const int workers = ThisPlayer->FreeWorkers.size();
label.SetFont(GetGameFont());
label.Draw(UI.Resources[FreeWorkersCount].TextX, UI.Resources[FreeWorkersCount].TextY, workers);
}
}
/*----------------------------------------------------------------------------

View file

@ -815,6 +815,55 @@ static PopupConditionPanel *ParsePopupConditions(lua_State *l)
condition->HasHint = LuaToBoolean(l, -1);
} else if (!strcmp(key, "HasDescription")) {
condition->HasDescription = LuaToBoolean(l, -1);
} else if (!strcmp(key, "HasDependencies")) {
condition->HasDependencies = LuaToBoolean(l, -1);
} else if (!strcmp(key, "ButtonValue")) {
condition->ButtonValue = LuaToString(l, -1);
} else if (!strcmp(key, "ButtonAction")) {
const char *value = LuaToString(l, -1);
if (!strcmp(value, "move")) {
condition->ButtonAction = ButtonMove;
} else if (!strcmp(value, "stop")) {
condition->ButtonAction = ButtonStop;
} else if (!strcmp(value, "attack")) {
condition->ButtonAction = ButtonAttack;
} else if (!strcmp(value, "repair")) {
condition->ButtonAction = ButtonRepair;
} else if (!strcmp(value, "harvest")) {
condition->ButtonAction = ButtonHarvest;
} else if (!strcmp(value, "button")) {
condition->ButtonAction = ButtonButton;
} else if (!strcmp(value, "build")) {
condition->ButtonAction = ButtonBuild;
} else if (!strcmp(value, "train-unit")) {
condition->ButtonAction = ButtonTrain;
} else if (!strcmp(value, "patrol")) {
condition->ButtonAction = ButtonPatrol;
} else if (!strcmp(value, "stand-ground")) {
condition->ButtonAction = ButtonStandGround;
} else if (!strcmp(value, "attack-ground")) {
condition->ButtonAction = ButtonAttackGround;
} else if (!strcmp(value, "return-goods")) {
condition->ButtonAction = ButtonReturn;
} else if (!strcmp(value, "cast-spell")) {
condition->ButtonAction = ButtonSpellCast;
} else if (!strcmp(value, "research")) {
condition->ButtonAction = ButtonResearch;
} else if (!strcmp(value, "upgrade-to")) {
condition->ButtonAction = ButtonUpgradeTo;
} else if (!strcmp(value, "unload")) {
condition->ButtonAction = ButtonUnload;
} else if (!strcmp(value, "cancel")) {
condition->ButtonAction = ButtonCancel;
} else if (!strcmp(value, "cancel-upgrade")) {
condition->ButtonAction = ButtonCancelUpgrade;
} else if (!strcmp(value, "cancel-train-unit")) {
condition->ButtonAction = ButtonCancelTrain;
} else if (!strcmp(value, "cancel-build")) {
condition->ButtonAction = ButtonCancelBuild;
} else {
LuaError(l, "Unsupported button action: %s" _C_ value);
}
} else {
int index = UnitTypeVar.BoolFlagNameLookup[key];
if (index != -1) {
@ -894,18 +943,35 @@ static CPopupContentType *CclParsePopupContent(lua_State *l)
contentbtype->InfoType = PopupButtonInfo_Hint;
} else if (temp == "Description") {
contentbtype->InfoType = PopupButtonInfo_Description;
} else if (temp == "Dependencies") {
contentbtype->InfoType = PopupButtonInfo_Dependencies;
}
} else if (!strcmp(key, "MaxWidth")) {
contentbtype->MaxWidth = LuaToNumber(l, -1);
} else if (!strcmp(key, "Font")) {
contentbtype->Font = CFont::Get(LuaToString(l, -1));
} else if (!strcmp(key, "Centered")) {
contentbtype->Centered = LuaToBoolean(l, -1);
} else {
LuaError(l, "'%s' invalid for method 'Name' in DefinePopups" _C_ key);
}
}
content = contentbtype;
} else if (!strcmp(key, "Text")) {
CPopupContentTypeText *contenttext = new CPopupContentTypeText;
Assert(lua_istable(l, -1));
for (lua_pushnil(l); lua_next(l, -2); lua_pop(l, 1)) {
key = LuaToString(l, -2);
if (!strcmp(key, "Text")) {
contenttext->Text = LuaToString(l, -1);
} else if (!strcmp(key, "MaxWidth")) {
contenttext->MaxWidth = LuaToNumber(l, -1);
} else if (!strcmp(key, "Font")) {
contenttext->Font = CFont::Get(LuaToString(l, -1));
} else {
LuaError(l, "'%s' invalid for method 'Text' in DefinePopups" _C_ key);
}
}
content = contenttext;
} else if (!strcmp(key, "Costs")) {
CPopupContentTypeCosts *contentcosts = new CPopupContentTypeCosts;
@ -1402,6 +1468,8 @@ static int CclDefineButton(lua_State *l)
ba.Pos = LuaToNumber(l, -1);
} else if (!strcmp(value, "Level")) {
ba.Level = LuaToNumber(l, -1);
} else if (!strcmp(value, "AlwaysShow")) {
ba.AlwaysShow = LuaToBoolean(l, -1);
} else if (!strcmp(value, "Icon")) {
ba.Icon.Name = LuaToString(l, -1);
} else if (!strcmp(value, "Action")) {
@ -1547,7 +1615,7 @@ static int CclDefineButton(lua_State *l)
}
AddButton(ba.Pos, ba.Level, ba.Icon.Name, ba.Action, ba.ValueStr,
ba.Allowed, ba.AllowStr, /*ba.Key,*/ ba.Hint, ba.Description, ba.CommentSound.Name,
ba.ButtonCursor, ba.UnitMask, ba.Popup);
ba.ButtonCursor, ba.UnitMask, ba.Popup, ba.AlwaysShow);
return 0;
}

View file

@ -204,7 +204,7 @@ void CUserInterface::Load()
Fillers[i].Load();
}
for (int i = 0; i <= ManaResCost; ++i) {
for (int i = 0; i <= FreeWorkersCount; ++i) {
if (Resources[i].G) {
Resources[i].G->Load();
Resources[i].G->UseDisplayFormat();
@ -297,7 +297,7 @@ void CleanUserInterface()
UI.Fillers.clear();
// Resource Icons
for (int i = 0; i <= ManaResCost; ++i) {
for (int i = 0; i <= FreeWorkersCount; ++i) {
CGraphic::Free(UI.Resources[i].G);
}

View file

@ -38,8 +38,10 @@
#include "depend.h"
#include "interface.h"
#include "player.h"
#include "script.h"
#include "unit.h"
#include "unittype.h"
#include "upgrade_structs.h"
#include "upgrade.h"
@ -151,18 +153,18 @@ static void AddDependency(const std::string &target, const std::string &required
}
#ifdef neverDEBUG
printf("New rules are :");
fprintf(stdout, "New rules are :");
node = node->Rule;
while (node) {
temp = node;
while (temp) {
printf("temp->Kind.UnitType=%p ", temp->Kind.UnitType);
fprintf(stdout, "temp->Kind.UnitType=%s ", temp->Kind.UnitType->Ident.c_str());
temp = temp->Rule;
}
node = node->Next;
printf("\n or ... ");
fprintf(stdout, "\n or ... ");
}
printf("\n");
fprintf(stdout, "\n");
#endif
}
@ -221,6 +223,95 @@ try_or:
return false; // no rule matches
}
/**
** Check if this upgrade or unit is available.
**
** @param player For this player available.
** @param target Unit or Upgrade.
**
** @return True if available, false otherwise.
*/
std::string PrintDependencies(const CPlayer &player, const ButtonAction &button)
{
DependRule rule;
std::string rules("");
//
// first have to check, if target is allowed itself
//
if (!strncmp(button.ValueStr.c_str(), "unit-", 5)) {
// target string refers to unit-XXX
rule.Kind.UnitType = UnitTypeByIdent(button.ValueStr);
rule.Type = DependRuleUnitType;
} else if (!strncmp(button.ValueStr.c_str(), "upgrade-", 8)) {
// target string refers to upgrade-XXX
rule.Kind.Upgrade = CUpgrade::Get(button.ValueStr);
rule.Type = DependRuleUpgrade;
} else if (!strncmp(button.ValueStr.c_str(), "spell-", 6)) {
// Special case for spells
if (button.Allowed && IsButtonAllowed(*Selected[0], button) == false) {
if (!strncmp(button.AllowStr.c_str(), "upgrade-", 8)) {
rules.insert(0, "Requirements:\n");
rules.append("-");
rules.append(AllUpgrades[UpgradeIdByIdent(button.AllowStr)]->Name);
rules.append("\n");
}
}
return rules;
} else {
DebugPrint("target `%s' should be unit-type or upgrade\n" _C_ button.ValueStr.c_str());
return rules;
}
// Find rule
int i = (int)((intptr_t)rule.Kind.UnitType % (sizeof(DependHash) / sizeof(*DependHash)));
const DependRule *node = DependHash[i];
if (node) { // find correct entry
while (node->Type != rule.Type || node->Kind.Upgrade != rule.Kind.Upgrade) {
if (!node->Next) { // end of list
return rules;
}
node = node->Next;
}
} else {
return rules;
}
// Prove the rules
node = node->Rule;
while (node) {
const DependRule *temp = node;
std::string subrules("");
while (temp) {
if (temp->Type == DependRuleUnitType) {
i = player.HaveUnitTypeByType(*temp->Kind.UnitType);
if (temp->Count ? i < temp->Count : i) {
subrules.append("-");
subrules.append(temp->Kind.UnitType->Name.c_str());
subrules.append("\n");
}
} else if (temp->Type == DependRuleUpgrade) {
i = UpgradeIdAllowed(player, temp->Kind.Upgrade->ID) != 'R';
if (temp->Count ? i : !i) {
subrules.append("-");
subrules.append(temp->Kind.Upgrade->Name.c_str());
subrules.append("\n");
}
}
temp = temp->Rule;
}
if (subrules.empty()) {
return subrules;
}
rules.append(subrules);
node = node->Next;
}
rules.insert(0, "Requirements:\n");
return rules;
}
/**
** Check if this upgrade or unit is available.
**

View file

@ -48,6 +48,7 @@
#include "sound.h"
#include "spells.h"
#include "tileset.h"
#include "ui.h"
#include "unit.h"
#include "unitsound.h"
#include "unit_manager.h"
@ -1783,6 +1784,7 @@ void UpdateUnitVariables(CUnit &unit)
#endif
Assert(unit.Variable[i].Value <= unit.Variable[i].Max);
}
UI.ButtonPanel.Update();
}
/**

View file

@ -707,7 +707,7 @@ static int strchrlen(const std::string &s, char c, unsigned int maxlen, CFont *f
return 0;
}
int res = s.find(c);
res = (res == -1) ? s.size() : res - 1;
res = (res == -1) ? s.size() : res;
if (!maxlen || (!font && (unsigned int) res < maxlen) || (font && (unsigned int) font->Width(s.substr(0, res)) < maxlen)) {
return res;