[+] Ability to set specific rules for AI players how to build buildings. Use AiBuildingRules in CUnitType for that (same syntax as in BuildingRules)
[+] Defence forces now can return to base if no more enemy units left. [+] Move CUnitType._Storing to stats, it's possible to use Storing in upgrades. [*] Don't check the builder in CBuildRestrictionDistance [*] Don't restore the saved attack order for dead units. [-] Fixed bug which didn't let the defence force to retaliate.
This commit is contained in:
parent
1944bfa6fb
commit
c0de6fd1f0
15 changed files with 173 additions and 47 deletions
|
@ -330,7 +330,7 @@ bool COrder_Build::StartBuilding(CUnit &unit, CUnit &ontop)
|
|||
if (&ontop != &unit) {
|
||||
CBuildRestrictionOnTop *b;
|
||||
|
||||
b = static_cast<CBuildRestrictionOnTop *>(OnTopDetails(*build, ontop.Type));
|
||||
b = static_cast<CBuildRestrictionOnTop *>(OnTopDetails(unit.Type->BuildingRules, *build, ontop.Type));
|
||||
Assert(b);
|
||||
if (b->ReplaceOnBuild) {
|
||||
build->ResourcesHeld = ontop.ResourcesHeld; // We capture the value of what is beneath.
|
||||
|
|
|
@ -115,7 +115,7 @@ static int TransformUnitIntoType(CUnit &unit, const CUnitType &newtype)
|
|||
// Change resource limit
|
||||
for (int i = 0; i < MaxCosts; ++i) {
|
||||
if (player.MaxResources[i] != -1) {
|
||||
player.MaxResources[i] += newtype._Storing[i] - oldtype._Storing[i];
|
||||
player.MaxResources[i] += newtype.Stats[player.Index].Storing[i] - oldtype.Stats[player.Index].Storing[i];
|
||||
player.SetResource(i, player.StoredResources[i], true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -270,6 +270,12 @@ void AiForce::Attack(const Vec2i &pos)
|
|||
Vec2i goalPos(pos);
|
||||
RemoveDeadUnit();
|
||||
|
||||
// Remember the original force position so we can return there after attack
|
||||
if (this->Size() > 0 && (this->Role == AiForceRoleDefend && !this->Attacking)
|
||||
|| (this->Role == AiForceRoleAttack && !this->Attacking && !this->State)) {
|
||||
this->HomePos = this->Units[0]->tilePos;
|
||||
}
|
||||
|
||||
Attacking = false;
|
||||
if (Units.size() == 0) {
|
||||
return;
|
||||
|
@ -295,6 +301,20 @@ void AiForce::Attack(const Vec2i &pos)
|
|||
}
|
||||
// Send all units in the force to enemy.
|
||||
this->State = AiForceAttackingState_Attacking;
|
||||
for (size_t i = 0; i != this->Units.size(); ++i) {
|
||||
CUnit* const unit = this->Units[i];
|
||||
int delta = 0;
|
||||
if (unit->Container == NULL) {
|
||||
// To avoid lot of CPU consuption, send them with a small time difference.
|
||||
unit->Wait = delta;
|
||||
++delta;
|
||||
if (unit->Type->CanAttack) {
|
||||
CommandAttack(*unit, goalPos, NULL, FlushCommands);
|
||||
} else {
|
||||
CommandMove(*unit, goalPos, FlushCommands);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AiForceManager::AiForceManager()
|
||||
|
@ -706,13 +726,24 @@ void AiForceManager::Update()
|
|||
|
||||
if (force.Defending) {
|
||||
force.RemoveDeadUnit();
|
||||
// Look if still enemies in attack range.
|
||||
const CUnit *dummy = NULL;
|
||||
if (!AiForceEnemyFinder<true>(force, &dummy).found()) {
|
||||
DebugPrint("%d:FIXME: not written, should send force #%d home\n"
|
||||
_C_ AiPlayer->Player->Index _C_ f);
|
||||
force.Defending = false;
|
||||
force.Attacking = false;
|
||||
// Check if some unit from force reached goal point
|
||||
if (Map.Info.IsPointOnMap(force.GoalPos) &&
|
||||
force.Units[0]->MapDistanceTo(force.GoalPos) <= 5) {
|
||||
// Look if still enemies in attack range.
|
||||
const CUnit *dummy = NULL;
|
||||
if (!AiForceEnemyFinder<true>(force, &dummy).found()) {
|
||||
if (Map.Info.IsPointOnMap(force.HomePos)) {
|
||||
const Vec2i invalidPos = { -1, -1};
|
||||
|
||||
for (size_t i = 0; i != force.Units.size(); ++i) {
|
||||
CUnit* const unit = force.Units[i];
|
||||
CommandMove(*unit, force.HomePos, FlushCommands);
|
||||
}
|
||||
force.HomePos = invalidPos;
|
||||
}
|
||||
force.Defending = false;
|
||||
force.Attacking = false;
|
||||
}
|
||||
}
|
||||
} else if (force.Attacking) {
|
||||
force.RemoveDeadUnit();
|
||||
|
|
|
@ -117,7 +117,7 @@ public:
|
|||
AiForce() :
|
||||
Completed(false), Defending(false), Attacking(false),
|
||||
Role(AiForceRoleDefault), State(AiForceAttackingState_Free) {
|
||||
GoalPos.x = GoalPos.y = -1;
|
||||
HomePos.x = HomePos.y = GoalPos.x = GoalPos.y = -1;
|
||||
}
|
||||
|
||||
void Remove(CUnit &unit) {
|
||||
|
@ -141,7 +141,7 @@ public:
|
|||
}
|
||||
Units.for_each(InternalRemoveUnit);
|
||||
Units.clear();
|
||||
GoalPos.x = GoalPos.y = 0;
|
||||
GoalPos.x = GoalPos.y = -1;
|
||||
}
|
||||
inline size_t Size() const { return Units.size(); }
|
||||
|
||||
|
@ -178,6 +178,7 @@ public:
|
|||
// If attacking
|
||||
AiForceAttackingState State; /// Attack state
|
||||
Vec2i GoalPos; /// Attack point tile map position
|
||||
Vec2i HomePos; /// Return after attack tile map position
|
||||
};
|
||||
|
||||
// forces
|
||||
|
|
|
@ -61,15 +61,13 @@ int GetPlayerData(int player, const char *prop, const char *arg)
|
|||
if (!strcmp(prop, "RaceName")) {
|
||||
return Players[player].Race;
|
||||
} else if (!strcmp(prop, "Resources")) {
|
||||
|
||||
const int resId = GetResourceIdByName(arg);
|
||||
if (resId == -1) {
|
||||
fprintf(stderr, "Invalid resource \"%s\"", arg);
|
||||
Exit(1);
|
||||
}
|
||||
return Players[player].Resources[resId];
|
||||
return Players[player].Resources[resId] + Players[player].StoredResources[resId];
|
||||
} else if (!strcmp(prop, "StoredResources")) {
|
||||
|
||||
const int resId = GetResourceIdByName(arg);
|
||||
if (resId == -1) {
|
||||
fprintf(stderr, "Invalid resource \"%s\"", arg);
|
||||
|
|
|
@ -329,7 +329,7 @@ static void EditorActionPlaceUnit(const Vec2i &pos, CUnitType &type, CPlayer *pl
|
|||
return;
|
||||
}
|
||||
|
||||
CBuildRestrictionOnTop *b = OnTopDetails(*unit, NULL);
|
||||
CBuildRestrictionOnTop *b = OnTopDetails(unit->Type->BuildingRules, *unit, NULL);
|
||||
if (b && b->ReplaceOnBuild) {
|
||||
CUnitCache &unitCache = Map.Field(pos)->UnitCache;
|
||||
CUnitCache::iterator it = std::find_if(unitCache.begin(), unitCache.end(), HasSameTypeAs(*b->Parent));
|
||||
|
|
|
@ -915,7 +915,7 @@ extern void DropOutNearest(CUnit &unit, const Vec2i &goalPos, const CUnit *conta
|
|||
extern void DropOutAll(const CUnit &unit);
|
||||
|
||||
/// Return the rule used to build this building.
|
||||
extern CBuildRestrictionOnTop *OnTopDetails(const CUnit &unit, const CUnitType *parent);
|
||||
extern CBuildRestrictionOnTop *OnTopDetails(std::vector<CBuildRestriction *> &restr, const CUnit &unit, const CUnitType *parent);
|
||||
/// @todo more docu
|
||||
extern CUnit *CanBuildHere(const CUnit *unit, const CUnitType &type, const Vec2i &pos);
|
||||
/// @todo more docu
|
||||
|
|
|
@ -801,7 +801,7 @@ class CBuildRestriction
|
|||
public:
|
||||
virtual ~CBuildRestriction() {}
|
||||
virtual void Init() {};
|
||||
virtual bool Check(const CUnitType &type, const Vec2i &pos, CUnit *&ontoptarget) const = 0;
|
||||
virtual bool Check(const CUnit *builder, const CUnitType &type, const Vec2i &pos, CUnit *&ontoptarget) const = 0;
|
||||
};
|
||||
|
||||
|
||||
|
@ -822,7 +822,7 @@ public:
|
|||
(*i)->Init();
|
||||
}
|
||||
}
|
||||
virtual bool Check(const CUnitType &type, const Vec2i &pos, CUnit *&ontoptarget) const;
|
||||
virtual bool Check(const CUnit *builder, const CUnitType &type, const Vec2i &pos, CUnit *&ontoptarget) const;
|
||||
|
||||
void push_back(CBuildRestriction *restriction) { _or_list.push_back(restriction); }
|
||||
public:
|
||||
|
@ -846,7 +846,7 @@ public:
|
|||
CBuildRestrictionAddOn() : Parent(NULL) { Offset.x = Offset.y = 0; };
|
||||
virtual ~CBuildRestrictionAddOn() {};
|
||||
virtual void Init() {this->Parent = UnitTypeByIdent(this->ParentName);};
|
||||
virtual bool Check(const CUnitType &type, const Vec2i &pos, CUnit *&ontoptarget) const;
|
||||
virtual bool Check(const CUnit *builder, const CUnitType &type, const Vec2i &pos, CUnit *&ontoptarget) const;
|
||||
|
||||
Vec2i Offset; /// offset from the main building to place this
|
||||
std::string ParentName; /// building that is unit is an addon too.
|
||||
|
@ -869,7 +869,7 @@ public:
|
|||
CBuildRestrictionOnTop() : Parent(NULL), ReplaceOnDie(0), ReplaceOnBuild(0) {};
|
||||
virtual ~CBuildRestrictionOnTop() {};
|
||||
virtual void Init() {this->Parent = UnitTypeByIdent(this->ParentName);};
|
||||
virtual bool Check(const CUnitType &type, const Vec2i &pos, CUnit *&ontoptarget) const;
|
||||
virtual bool Check(const CUnit *builder, const CUnitType &type, const Vec2i &pos, CUnit *&ontoptarget) const;
|
||||
|
||||
std::string ParentName; /// building that is unit is an addon too.
|
||||
CUnitType *Parent; /// building that is unit is an addon too.
|
||||
|
@ -883,7 +883,7 @@ public:
|
|||
CBuildRestrictionDistance() : Distance(0), RestrictType(NULL) {};
|
||||
virtual ~CBuildRestrictionDistance() {};
|
||||
virtual void Init() {this->RestrictType = UnitTypeByIdent(this->RestrictTypeName);};
|
||||
virtual bool Check(const CUnitType &type, const Vec2i &pos, CUnit *&ontoptarget) const;
|
||||
virtual bool Check(const CUnit *builder, const CUnitType &type, const Vec2i &pos, CUnit *&ontoptarget) const;
|
||||
|
||||
int Distance; /// distance to build (circle)
|
||||
DistanceTypeType DistanceType;
|
||||
|
@ -948,7 +948,6 @@ public:
|
|||
|
||||
CConstruction *Construction; /// What is shown in construction phase
|
||||
|
||||
int _Storing[MaxCosts]; /// How many resources the unit can store
|
||||
int RepairHP; /// Amount of HP per repair
|
||||
int RepairCosts[MaxCosts]; /// How much it costs to repair
|
||||
|
||||
|
@ -1032,6 +1031,7 @@ public:
|
|||
int GivesResource; /// The resource this unit gives.
|
||||
ResourceInfo *ResInfo[MaxCosts]; /// Resource information.
|
||||
std::vector<CBuildRestriction *> BuildingRules; /// Rules list for building a building.
|
||||
std::vector<CBuildRestriction *> AiBuildingRules; /// Rules list for for AI to build a building.
|
||||
SDL_Color NeutralMinimapColorRGB; /// Minimap Color for Neutral Units.
|
||||
|
||||
CUnitSound Sound; /// Sounds for events
|
||||
|
|
|
@ -140,6 +140,7 @@ class CUnitStats
|
|||
public:
|
||||
CUnitStats() : Variables(NULL) {
|
||||
memset(Costs, 0, sizeof(Costs));
|
||||
memset(Storing, 0, sizeof(Storing));
|
||||
}
|
||||
~CUnitStats();
|
||||
|
||||
|
@ -150,6 +151,7 @@ public:
|
|||
public:
|
||||
CVariable *Variables; /// user defined variable.
|
||||
int Costs[MaxCosts]; /// current costs of the unit
|
||||
int Storing[MaxCosts]; /// storage increasing
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -718,7 +718,7 @@ static int CclGetPlayerData(lua_State *l)
|
|||
|
||||
const std::string res = LuaToString(l, 3);
|
||||
const int resId = GetResourceIdByName(l, res.c_str());
|
||||
lua_pushnumber(l, p->Resources[resId]);
|
||||
lua_pushnumber(l, p->Resources[resId] + p->StoredResources[resId]);
|
||||
return 1;
|
||||
} else if (!strcmp(data, "StoredResources")) {
|
||||
LuaCheckArgs(l, 3);
|
||||
|
|
|
@ -55,13 +55,14 @@
|
|||
**
|
||||
** @return the BuildingRestrictionDetails
|
||||
*/
|
||||
CBuildRestrictionOnTop *OnTopDetails(const CUnit &unit, const CUnitType *parent)
|
||||
CBuildRestrictionOnTop *OnTopDetails(std::vector<CBuildRestriction *> &restr,
|
||||
const CUnit &unit, const CUnitType *parent)
|
||||
{
|
||||
CBuildRestrictionAnd *andb;
|
||||
CBuildRestrictionOnTop *ontopb;
|
||||
|
||||
for (std::vector<CBuildRestriction *>::iterator i = unit.Type->BuildingRules.begin();
|
||||
i != unit.Type->BuildingRules.end(); ++i) {
|
||||
for (std::vector<CBuildRestriction *>::const_iterator i = restr.begin();
|
||||
i != restr.end(); ++i) {
|
||||
if ((ontopb = dynamic_cast<CBuildRestrictionOnTop *>(*i))) {
|
||||
if (!parent) {
|
||||
// Guess this is right
|
||||
|
@ -91,10 +92,10 @@ CBuildRestrictionOnTop *OnTopDetails(const CUnit &unit, const CUnitType *parent)
|
|||
/**
|
||||
** Check And Restriction
|
||||
*/
|
||||
bool CBuildRestrictionAnd::Check(const CUnitType &type, const Vec2i &pos, CUnit *&ontoptarget) const
|
||||
bool CBuildRestrictionAnd::Check(const CUnit *builder, const CUnitType &type, const Vec2i &pos, CUnit *&ontoptarget) const
|
||||
{
|
||||
for (std::vector<CBuildRestriction *>::const_iterator i = _or_list.begin(); i != _or_list.end(); ++i) {
|
||||
if (!(*i)->Check(type, pos, ontoptarget)) {
|
||||
if (!(*i)->Check(builder, type, pos, ontoptarget)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -104,7 +105,7 @@ bool CBuildRestrictionAnd::Check(const CUnitType &type, const Vec2i &pos, CUnit
|
|||
/**
|
||||
** Check Distance Restriction
|
||||
*/
|
||||
bool CBuildRestrictionDistance::Check(const CUnitType &type, const Vec2i &pos, CUnit *&) const
|
||||
bool CBuildRestrictionDistance::Check(const CUnit *builder, const CUnitType &type, const Vec2i &pos, CUnit *&) const
|
||||
{
|
||||
Vec2i pos1 = {0, 0};
|
||||
Vec2i pos2 = {0, 0};
|
||||
|
@ -133,7 +134,7 @@ bool CBuildRestrictionDistance::Check(const CUnitType &type, const Vec2i &pos, C
|
|||
case GreaterThan :
|
||||
case GreaterThanEqual :
|
||||
for (size_t i = 0; i != table.size(); ++i) {
|
||||
if (this->RestrictType == table[i]->Type &&
|
||||
if (builder != table[i] && this->RestrictType == table[i]->Type &&
|
||||
MapDistanceBetweenTypes(type, pos, *table[i]->Type, table[i]->tilePos) <= distance) {
|
||||
return false;
|
||||
}
|
||||
|
@ -142,7 +143,7 @@ bool CBuildRestrictionDistance::Check(const CUnitType &type, const Vec2i &pos, C
|
|||
case LessThan :
|
||||
case LessThanEqual :
|
||||
for (size_t i = 0; i != table.size(); ++i) {
|
||||
if (this->RestrictType == table[i]->Type &&
|
||||
if (builder != table[i] && this->RestrictType == table[i]->Type &&
|
||||
MapDistanceBetweenTypes(type, pos, *table[i]->Type, table[i]->tilePos) <= distance) {
|
||||
return true;
|
||||
}
|
||||
|
@ -150,7 +151,7 @@ bool CBuildRestrictionDistance::Check(const CUnitType &type, const Vec2i &pos, C
|
|||
return false;
|
||||
case Equal :
|
||||
for (size_t i = 0; i != table.size(); ++i) {
|
||||
if (this->RestrictType == table[i]->Type &&
|
||||
if (builder != table[i] && this->RestrictType == table[i]->Type &&
|
||||
MapDistanceBetweenTypes(type, pos, *table[i]->Type, table[i]->tilePos) == distance) {
|
||||
return true;
|
||||
}
|
||||
|
@ -158,7 +159,7 @@ bool CBuildRestrictionDistance::Check(const CUnitType &type, const Vec2i &pos, C
|
|||
return false;
|
||||
case NotEqual :
|
||||
for (size_t i = 0; i != table.size(); ++i) {
|
||||
if (this->RestrictType == table[i]->Type &&
|
||||
if (builder != table[i] && this->RestrictType == table[i]->Type &&
|
||||
MapDistanceBetweenTypes(type, pos, *table[i]->Type, table[i]->tilePos) == distance) {
|
||||
return false;
|
||||
}
|
||||
|
@ -176,7 +177,7 @@ inline bool CBuildRestrictionAddOn::functor::operator()(const CUnit *const unit)
|
|||
/**
|
||||
** Check AddOn Restriction
|
||||
*/
|
||||
bool CBuildRestrictionAddOn::Check(const CUnitType &, const Vec2i &pos, CUnit *&) const
|
||||
bool CBuildRestrictionAddOn::Check(const CUnit *, const CUnitType &, const Vec2i &pos, CUnit *&) const
|
||||
{
|
||||
Vec2i pos1 = pos - this->Offset;
|
||||
|
||||
|
@ -218,7 +219,7 @@ private:
|
|||
};
|
||||
|
||||
|
||||
bool CBuildRestrictionOnTop::Check(const CUnitType &, const Vec2i &pos, CUnit *&ontoptarget) const
|
||||
bool CBuildRestrictionOnTop::Check(const CUnit *, const CUnitType &, const Vec2i &pos, CUnit *&ontoptarget) const
|
||||
{
|
||||
Assert(Map.Info.IsPointOnMap(pos));
|
||||
|
||||
|
@ -291,7 +292,7 @@ CUnit *CanBuildHere(const CUnit *unit, const CUnitType &type, const Vec2i &pos)
|
|||
for (unsigned int i = 0; i < count; ++i) {
|
||||
CBuildRestriction *rule = type.BuildingRules[i];
|
||||
// All checks processed, did we really have success
|
||||
if (rule->Check(type, pos, ontoptarget)) {
|
||||
if (rule->Check(unit, type, pos, ontoptarget)) {
|
||||
// We passed a full ruleset return
|
||||
if (unit == NULL) {
|
||||
return ontoptarget ? ontoptarget : (CUnit *)1;
|
||||
|
@ -302,6 +303,27 @@ CUnit *CanBuildHere(const CUnit *unit, const CUnitType &type, const Vec2i &pos)
|
|||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Check special rules for AI players
|
||||
if (unit->Player->AiEnabled) {
|
||||
size_t count = type.AiBuildingRules.size();
|
||||
if (count > 0) {
|
||||
ontoptarget = NULL;
|
||||
for (unsigned int i = 0; i < count; ++i) {
|
||||
CBuildRestriction *rule = type.AiBuildingRules[i];
|
||||
// All checks processed, did we really have success
|
||||
if (rule->Check(unit, type, pos, ontoptarget)) {
|
||||
// We passed a full ruleset return
|
||||
if (unit == NULL) {
|
||||
return ontoptarget ? ontoptarget : (CUnit *)1;
|
||||
} else {
|
||||
return ontoptarget ? ontoptarget : (CUnit *)unit;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return (unit == NULL) ? (CUnit *)1 : const_cast<CUnit *>(unit);
|
||||
}
|
||||
|
||||
|
|
|
@ -489,7 +489,7 @@ static int CclDefineUnitType(lua_State *l)
|
|||
lua_pop(l, 1);
|
||||
++k;
|
||||
lua_rawgeti(l, -1, k + 1);
|
||||
type->_Storing[res] = LuaToNumber(l, -1);
|
||||
type->DefaultStat.Storing[res] = LuaToNumber(l, -1);
|
||||
lua_pop(l, 1);
|
||||
}
|
||||
} else if (!strcmp(value, "ImproveProduction")) {
|
||||
|
@ -745,6 +745,25 @@ static int CclDefineUnitType(lua_State *l)
|
|||
ParseBuildingRules(l, type->BuildingRules);
|
||||
lua_pop(l, 1);
|
||||
}
|
||||
} else if (!strcmp(value, "AiBuildingRules")) {
|
||||
if (!lua_istable(l, -1)) {
|
||||
LuaError(l, "incorrect argument");
|
||||
}
|
||||
subargs = lua_rawlen(l, -1);
|
||||
// Free any old restrictions if they are redefined
|
||||
for (std::vector<CBuildRestriction *>::iterator b = type->AiBuildingRules.begin();
|
||||
b != type->AiBuildingRules.end(); ++b) {
|
||||
delete *b;
|
||||
}
|
||||
type->AiBuildingRules.clear();
|
||||
for (k = 0; k < subargs; ++k) {
|
||||
lua_rawgeti(l, -1, k + 1);
|
||||
if (!lua_istable(l, -1)) {
|
||||
LuaError(l, "incorrect argument");
|
||||
}
|
||||
ParseBuildingRules(l, type->AiBuildingRules);
|
||||
lua_pop(l, 1);
|
||||
}
|
||||
} else if (!strcmp(value, "BuilderOutside")) {
|
||||
type->BuilderOutside = LuaToBoolean(l, -1);
|
||||
} else if (!strcmp(value, "BuilderLost")) {
|
||||
|
@ -1160,6 +1179,22 @@ static int CclDefineUnitStats(lua_State *l)
|
|||
stats->Costs[resId] = LuaToNumber(l, -1);
|
||||
lua_pop(l, 1);
|
||||
}
|
||||
} else if (!strcmp(value, "storing")) {
|
||||
if (!lua_istable(l, j + 1)) {
|
||||
LuaError(l, "incorrect argument");
|
||||
}
|
||||
const int subargs = lua_rawlen(l, j + 1);
|
||||
|
||||
for (int k = 0; k < subargs; ++k) {
|
||||
lua_rawgeti(l, j + 1, k + 1);
|
||||
value = LuaToString(l, -1);
|
||||
lua_pop(l, 1);
|
||||
++k;
|
||||
const int resId = GetResourceIdByName(l, value);
|
||||
lua_rawgeti(l, j + 1, k + 1);
|
||||
stats->Storing[resId] = LuaToNumber(l, -1);
|
||||
lua_pop(l, 1);
|
||||
}
|
||||
} else {
|
||||
int i = UnitTypeVar.VariableNameLookup[value];// User variables
|
||||
if (i != -1) { // valid index
|
||||
|
|
|
@ -367,7 +367,11 @@ void CUnit::Init(CUnitType &type)
|
|||
*/
|
||||
bool CUnit::RestoreOrder()
|
||||
{
|
||||
if (this->SavedOrder == NULL) {
|
||||
COrder *savedOrder = this->SavedOrder;
|
||||
|
||||
if (savedOrder == NULL
|
||||
|| (savedOrder->Action == UnitActionAttack
|
||||
&& (!savedOrder->HasGoal() || savedOrder->GetGoal()->IsAlive()))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -380,7 +384,7 @@ bool CUnit::RestoreOrder()
|
|||
|
||||
|
||||
//copy
|
||||
this->Orders.insert(this->Orders.begin() + 1, this->SavedOrder);
|
||||
this->Orders.insert(this->Orders.begin() + 1, savedOrder);
|
||||
|
||||
this->SavedOrder = NULL;
|
||||
return true;
|
||||
|
@ -966,8 +970,8 @@ void UnitLost(CUnit &unit)
|
|||
player.Supply -= type.Supply;
|
||||
// Decrease resource limit
|
||||
for (int i = 0; i < MaxCosts; ++i) {
|
||||
if (player.MaxResources[i] != -1 && type._Storing[i]) {
|
||||
const int newMaxValue = player.MaxResources[i] - type._Storing[i];
|
||||
if (player.MaxResources[i] != -1 && type.Stats[player.Index].Storing[i]) {
|
||||
const int newMaxValue = player.MaxResources[i] - type.Stats[player.Index].Storing[i];
|
||||
|
||||
player.MaxResources[i] = std::max(0, newMaxValue);
|
||||
player.SetResource(i, player.StoredResources[i], true);
|
||||
|
@ -994,7 +998,7 @@ void UnitLost(CUnit &unit)
|
|||
DebugPrint("%d: Lost %s(%d)\n" _C_ player.Index _C_ type.Ident.c_str() _C_ UnitNumber(unit));
|
||||
|
||||
// Destroy resource-platform, must re-make resource patch.
|
||||
if ((b = OnTopDetails(unit, NULL)) != NULL) {
|
||||
if ((b = OnTopDetails(unit.Type->BuildingRules, unit, NULL)) != NULL) {
|
||||
if (b->ReplaceOnDie && (type.GivesResource && unit.ResourcesHeld != 0)) {
|
||||
temp = MakeUnitAndPlace(unit.tilePos, *b->Parent, &Players[PlayerNumNeutral]);
|
||||
if (temp == NoUnitP) {
|
||||
|
@ -1040,8 +1044,8 @@ void UpdateForNewUnit(const CUnit &unit, int upgrade)
|
|||
if (!upgrade) {
|
||||
player.Supply += type.Supply;
|
||||
for (int i = 0; i < MaxCosts; ++i) {
|
||||
if (player.MaxResources[i] != -1 && type._Storing[i]) {
|
||||
player.MaxResources[i] += type._Storing[i];
|
||||
if (player.MaxResources[i] != -1 && type.Stats[player.Index].Storing[i]) {
|
||||
player.MaxResources[i] += type.Stats[player.Index].Storing[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1559,8 +1563,8 @@ void CUnit::ChangeOwner(CPlayer &newplayer)
|
|||
newplayer.Supply += Type->Supply;
|
||||
// Increase resource limit
|
||||
for (int i = 0; i < MaxCosts; ++i) {
|
||||
if (newplayer.MaxResources[i] != -1 && Type->_Storing[i]) {
|
||||
newplayer.MaxResources[i] += Type->_Storing[i];
|
||||
if (newplayer.MaxResources[i] != -1 && Type->Stats[newplayer.Index].Storing[i]) {
|
||||
newplayer.MaxResources[i] += Type->Stats[newplayer.Index].Storing[i];
|
||||
}
|
||||
}
|
||||
if (Type->Building && !Type->Wall) {
|
||||
|
|
|
@ -163,7 +163,6 @@ CUnitType::CUnitType() :
|
|||
#ifdef USE_MNG
|
||||
memset(&Portrait, 0, sizeof(Portrait));
|
||||
#endif
|
||||
memset(_Storing, 0, sizeof(_Storing));
|
||||
memset(RepairCosts, 0, sizeof(RepairCosts));
|
||||
memset(CanStore, 0, sizeof(CanStore));
|
||||
memset(ResInfo, 0, sizeof(ResInfo));
|
||||
|
@ -184,6 +183,11 @@ CUnitType::~CUnitType()
|
|||
delete *b;
|
||||
}
|
||||
BuildingRules.clear();
|
||||
for (std::vector<CBuildRestriction *>::iterator b = AiBuildingRules.begin();
|
||||
b != AiBuildingRules.end(); ++b) {
|
||||
delete *b;
|
||||
}
|
||||
AiBuildingRules.clear();
|
||||
|
||||
delete[] CanCastSpell;
|
||||
delete[] AutoCastActive;
|
||||
|
@ -378,6 +382,13 @@ static bool SaveUnitStats(const CUnitStats &stats, const CUnitType &type, int pl
|
|||
}
|
||||
file.printf("\"%s\", %d,", DefaultResourceNames[i].c_str(), stats.Costs[i]);
|
||||
}
|
||||
file.printf("\"storing\", {");
|
||||
for (unsigned int i = 0; i < MaxCosts; ++i) {
|
||||
if (i) {
|
||||
file.printf(" ");
|
||||
}
|
||||
file.printf("\"%s\", %d,", DefaultResourceNames[i].c_str(), stats.Storing[i]);
|
||||
}
|
||||
file.printf("})\n");
|
||||
return true;
|
||||
}
|
||||
|
@ -538,6 +549,12 @@ void InitUnitTypes(int reset_player_stats)
|
|||
b < type->BuildingRules.end(); ++b) {
|
||||
(*b)->Init();
|
||||
}
|
||||
|
||||
// Lookup AiBuildingTypes
|
||||
for (std::vector<CBuildRestriction *>::iterator b = type->AiBuildingRules.begin();
|
||||
b < type->AiBuildingRules.end(); ++b) {
|
||||
(*b)->Init();
|
||||
}
|
||||
}
|
||||
|
||||
// LUDO : called after game is loaded -> don't reset stats !
|
||||
|
|
|
@ -91,6 +91,7 @@ const CUnitStats &CUnitStats::operator = (const CUnitStats &rhs)
|
|||
{
|
||||
for (unsigned int i = 0; i < MaxCosts; ++i) {
|
||||
this->Costs[i] = rhs.Costs[i];
|
||||
this->Storing[i] = rhs.Storing[i];
|
||||
}
|
||||
delete [] this->Variables;
|
||||
const unsigned int size = UnitTypeVar.GetNumberVariable();
|
||||
|
@ -106,6 +107,9 @@ bool CUnitStats::operator == (const CUnitStats &rhs) const
|
|||
if (this->Costs[i] != rhs.Costs[i]) {
|
||||
return false;
|
||||
}
|
||||
if (this->Storing[i] != rhs.Storing[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (unsigned int i = 0; i != UnitTypeVar.GetNumberVariable(); ++i) {
|
||||
if (this->Variables[i] != rhs.Variables[i]) {
|
||||
|
@ -295,6 +299,17 @@ static int CclDefineModifier(lua_State *l)
|
|||
lua_rawgeti(l, j + 1, 2);
|
||||
um->Modifier.Costs[resId] = LuaToNumber(l, -1);
|
||||
lua_pop(l, 1);
|
||||
} else if (!strcmp(key, "storing")) {
|
||||
if (!lua_istable(l, j + 1) || lua_rawlen(l, j + 1) != 2) {
|
||||
LuaError(l, "incorrect argument");
|
||||
}
|
||||
lua_rawgeti(l, j + 1, 1);
|
||||
value = LuaToString(l, -1);
|
||||
lua_pop(l, 1);
|
||||
const int resId = GetResourceIdByName(l, value);
|
||||
lua_rawgeti(l, j + 1, 2);
|
||||
um->Modifier.Storing[resId] = LuaToNumber(l, -1);
|
||||
lua_pop(l, 1);
|
||||
} else if (!strcmp(key, "allow-unit")) {
|
||||
lua_rawgeti(l, j + 1, 2);
|
||||
value = LuaToString(l, -1);
|
||||
|
@ -582,6 +597,7 @@ static void ApplyUpgradeModifier(CPlayer &player, const CUpgradeModifier *um)
|
|||
// upgrade costs :)
|
||||
for (unsigned int j = 0; j < MaxCosts; ++j) {
|
||||
UnitTypes[z]->Stats[pn].Costs[j] += um->Modifier.Costs[j];
|
||||
UnitTypes[z]->Stats[pn].Storing[j] += um->Modifier.Storing[j];
|
||||
}
|
||||
|
||||
int varModified = 0;
|
||||
|
|
Loading…
Add table
Reference in a new issue