[+] 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:
parent
48e338c83b
commit
c7d7ca33d9
22 changed files with 469 additions and 73 deletions
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
**
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------------------
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
**
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue