From de0530e856a3ffb0480d2df2e84c8777afc93d40 Mon Sep 17 00:00:00 2001 From: Joris Dauphin <joris.dauphin@gmail.com> Date: Thu, 7 Jul 2011 12:40:27 +0200 Subject: [PATCH] Some Clean up in Ai Module Fix missing RefDecrease in AiForce Remove unused flag MustTransport remove Big unused Array units_with_resource[MaxCost][UnitMax] in AiCollectResources --- src/ai/ai.cpp | 4 +- src/ai/ai_force.cpp | 338 ++++++++++++++++++----------------------- src/ai/ai_local.h | 101 ++++++------ src/ai/ai_magic.cpp | 12 +- src/ai/ai_plan.cpp | 19 +-- src/ai/ai_resource.cpp | 107 +++++-------- src/ai/script_ai.cpp | 6 +- 7 files changed, 243 insertions(+), 344 deletions(-) diff --git a/src/ai/ai.cpp b/src/ai/ai.cpp index 8151668a1..c3012c115 100644 --- a/src/ai/ai.cpp +++ b/src/ai/ai.cpp @@ -316,8 +316,8 @@ static void SaveAiPlayer(CFile *file, int plynr, PlayerAi *ai) file->printf(" %d, \"%s\",", UnitNumber(aiunit), aiunit.Type->Ident.c_str()); } - file->printf("},\n \"state\", %d, \"goalx\", %d, \"goaly\", %d, \"must-transport\", %d,", - ai->Force[i].State, ai->Force[i].GoalPos.x, ai->Force[i].GoalPos.y, ai->Force[i].MustTransport); + file->printf("},\n \"state\", %d, \"goalx\", %d, \"goaly\", %d,", + ai->Force[i].State, ai->Force[i].GoalPos.x, ai->Force[i].GoalPos.y); file->printf("},\n"); } diff --git a/src/ai/ai_force.cpp b/src/ai/ai_force.cpp index 147bd4594..4b7f61c9f 100644 --- a/src/ai/ai_force.cpp +++ b/src/ai/ai_force.cpp @@ -44,8 +44,6 @@ #include "actions.h" #include "map.h" #include "depend.h" -#include "pathfinder.h" -#include "player.h" /*---------------------------------------------------------------------------- -- Types @@ -78,10 +76,27 @@ struct AiForceEnemyFinder { AiForceEnemyFinder(AiForce *force): enemy(NULL) { force->Units.for_each_if(*this); } - }; -struct AiForceAttackSender { +class AiForceAttackSender { +public: + // Send all units in the force to enemy at pos. + AiForceAttackSender(int force, const Vec2i &pos) : goalPos(pos), delta(0) { + DebugPrint("%d: Attacking with force #%d\n" _C_ AiPlayer->Player->Index _C_ force); + AiForce *fptr = &AiPlayer->Force[force]; + fptr->Attacking = true; + fptr->State = AiForceAttackingState_Attacking; + fptr->Units.for_each(*this); + } + + AiForceAttackSender(AiForce *force, const Vec2i &pos) : + goalPos(pos), delta(0) { + DebugPrint("%d: Attacking with force #%lu\n" _C_ AiPlayer->Player->Index + _C_ (long unsigned int)(force - &(AiPlayer->Force[0]))); + force->Attacking = true; + force->State = AiForceAttackingState_Attacking; + force->Units.for_each(*this); + } inline void operator() (CUnit *const unit) { // this may be problem if units are in bunker and we want sent @@ -94,32 +109,13 @@ struct AiForceAttackSender { CommandUnload(*unit, goalPos, NULL, FlushCommands); } else if (unit->Type->CanAttack) { CommandAttack(*unit, goalPos, NULL, FlushCommands); - } else /*if (force->State == 2) */{ + } else { CommandMove(*unit, goalPos, FlushCommands); } } } - // - // Send all units in the force to enemy at x,y. - // - AiForceAttackSender(int force, const Vec2i &pos) : goalPos(pos), delta(0) { - DebugPrint("%d: Attacking with force #%d\n" _C_ AiPlayer->Player->Index _C_ force); - AiForce *fptr = &AiPlayer->Force[force]; - fptr->Attacking = true; - fptr->State = AI_FORCE_STATE_ATTACKING; - fptr->Units.for_each(*this); - } - - AiForceAttackSender(AiForce *force, const Vec2i &pos) : - goalPos(pos), delta(0) { - DebugPrint("%d: Attacking with force #%lu\n" _C_ AiPlayer->Player->Index - _C_ (long unsigned int)(force - &(AiPlayer->Force[0]))); - force->Attacking = true; - force->State = AI_FORCE_STATE_ATTACKING; - force->Units.for_each(*this); - } - +private: Vec2i goalPos; int delta; }; @@ -154,22 +150,16 @@ void AiResetUnitTypeEquiv() */ void AiNewUnitTypeEquiv(CUnitType *a, CUnitType *b) { - int find; - int replace; - int i; - - find = UnitTypeEquivs[a->Slot]; - replace = UnitTypeEquivs[b->Slot]; + int find = UnitTypeEquivs[a->Slot]; + int replace = UnitTypeEquivs[b->Slot]; // Always record equivalences with the lowest unittype. if (find < replace) { - i = find; - find = replace; - replace = i; + std::swap(find, replace); } // Then just find & replace in UnitTypeEquivs... - for (i = 0; i <= UnitTypeMax; ++i) { + for (unsigned int i = 0; i <= UnitTypeMax; ++i) { if (UnitTypeEquivs[i] == find) { UnitTypeEquivs[i] = replace; } @@ -194,12 +184,21 @@ int AiFindUnitTypeEquiv(const CUnitType &unittype, int *result) if (UnitTypeEquivs[i] == search) { // Found one result[count] = i; - count++; + ++count; } } return count; } +class UnitTypePrioritySorter_Decreasing +{ +public: + bool operator () (int lhs, int rhs) const + { + return UnitTypes[lhs]->Priority > UnitTypes[rhs]->Priority; + } +}; + /** ** Find All unittypes equivalent to a given one, and which are available ** UnitType are returned in the prefered order ( ie palladin >> knight... ) @@ -226,35 +225,26 @@ int AiFindAvailableUnitTypeEquiv(const CUnitType &unittype, int *usableTypes) } // 3 - Sort by level - // We won't have usableTypesCount>4, so simple sort should do it - for (int i = 0; i < usableTypesCount - 1; ++i) { - int bestlevel = UnitTypes[usableTypes[i]]->Priority; - for (int j = i + 1; j < usableTypesCount; ++j) { - const int curlevel = UnitTypes[usableTypes[j]]->Priority; + std::sort(usableTypes, usableTypes + usableTypesCount, UnitTypePrioritySorter_Decreasing()); - if (curlevel > bestlevel) { - std::swap(usableTypes[j], usableTypes[i]); - bestlevel = curlevel; - } - } - } return usableTypesCount; } /* =========================== FORCES ========================== */ -struct AiForceCounter { - unsigned int *data;//[UnitTypeMax + 1]; - - inline void operator() (CUnit *const unit) { - data[UnitTypeEquivs[unit->Type->Slot]]++; - } - - AiForceCounter(CUnitCache &units, unsigned int *d, const size_t len): data(d) +class AiForceCounter +{ +public: + AiForceCounter(CUnitCache &units, unsigned int *d, const size_t len) : data(d) { memset(data, 0, len); units.for_each(*this); } + inline void operator() (CUnit *const unit) { + data[UnitTypeEquivs[unit->Type->Slot]]++; + } +private: + unsigned int *data;//[UnitTypeMax + 1]; }; void AiForce::CountTypes(unsigned int *counter, const size_t len) { @@ -270,9 +260,7 @@ void AiForce::CountTypes(unsigned int *counter, const size_t len) { */ bool AiForce::IsBelongsTo(const CUnitType *type) { - AiUnitType *aitype; bool flag = false; - int slot; unsigned int counter[UnitTypeMax + 1]; // @@ -285,11 +273,12 @@ bool AiForce::IsBelongsTo(const CUnitType *type) // Completed = true; for (unsigned int i = 0; i < UnitTypes.size(); ++i) { - aitype = &UnitTypes[i]; - slot = aitype->Type->Slot; - if (aitype->Want > counter[slot]) { + const AiUnitType &aitype = UnitTypes[i]; + const int slot = aitype.Type->Slot; + + if (counter[slot] < aitype.Want) { if (UnitTypeEquivs[type->Slot] == slot) { - if (aitype->Want - 1 > counter[slot]) { + if (counter[slot] < aitype.Want - 1) { Completed = false; } flag = true; @@ -303,20 +292,17 @@ bool AiForce::IsBelongsTo(const CUnitType *type) /** ** Ai clean units in a force. -** */ -void AiForce::Clean() { - - CUnit *aiunit; +void AiForce::Clean() +{ unsigned int i = 0; - // + // Release all killed units. - // while (i != Units.size()) { - aiunit = Units[i]; + CUnit *aiunit = Units[i]; + if (!aiunit->IsAlive()) { - aiunit->GroupId = 0; - aiunit->RefsDecrease(); + InternalRemoveUnit(aiunit); Units.Remove(i); continue; } @@ -331,34 +317,34 @@ void AiForce::Attack(const Vec2i &pos) Clean(); Attacking = false; - if (Units.size() > 0) { - Attacking = true; + if (Units.size() == 0) { + return; + } + Attacking = true; - if (goalPos.x == -1 || goalPos.y == -1) { - /* Search in entire map */ - const CUnit *enemy = AiForceEnemyFinder<false>(this).enemy; - if (enemy) { - goalPos = enemy->tilePos; - } + if (goalPos.x == -1 || goalPos.y == -1) { + /* Search in entire map */ + const CUnit *enemy = AiForceEnemyFinder<false>(this).enemy; + if (enemy) { + goalPos = enemy->tilePos; } - - this->GoalPos = goalPos; - - if (goalPos.x == -1 || goalPos.y == -1) { - DebugPrint("%d: Need to plan an attack with transporter\n" _C_ AiPlayer->Player->Index); - if (State == AI_FORCE_STATE_WAITING && !PlanAttack()) { - DebugPrint("%d: Can't transport\n" _C_ AiPlayer->Player->Index); - Attacking = false; - } - return; - } - - // - // Send all units in the force to enemy. - // - AiForceAttackSender(this, goalPos); } + this->GoalPos = goalPos; + + if (goalPos.x == -1 || goalPos.y == -1) { + DebugPrint("%d: Need to plan an attack with transporter\n" _C_ AiPlayer->Player->Index); + if (State == AiForceAttackingState_Waiting && !PlanAttack()) { + DebugPrint("%d: Can't transport\n" _C_ AiPlayer->Player->Index); + Attacking = false; + } + return; + } + + // + // Send all units in the force to enemy. + // + AiForceAttackSender(this, goalPos); } AiForceManager::AiForceManager() { @@ -370,13 +356,13 @@ unsigned int AiForceManager::FindFreeForce(int role) { /* find free force */ unsigned int f = 0; - while (f < forces.size() && (forces[f].State > AI_FORCE_STATE_FREE)) { + while (f < forces.size() && (forces[f].State > AiForceAttackingState_Free)) { ++f; }; if (f == forces.size()) { forces.resize(f + 1); } - forces[f].State = AI_FORCE_STATE_WAITING; + forces[f].State = AiForceAttackingState_Waiting; forces[f].Role = role; return f; } @@ -399,18 +385,20 @@ void AiForceManager::Clean() */ bool AiForceManager::Assign(CUnit &unit) { - // + if (unit.GroupId != 0) { + return false; + } + // Check to which force it belongs - // - for(unsigned int i = 0; i < forces.size(); ++i) + for (unsigned int i = 0; i < forces.size(); ++i) { - AiForce *force = &forces[i]; + AiForce &force = forces[i]; // No troops for attacking force - if (force->IsAttacking()) { + if (force.IsAttacking()) { continue; } - if (unit.GroupId == 0 && force->IsBelongsTo(unit.Type)) { - force->Insert(unit); + if (force.IsBelongsTo(unit.Type)) { + force.Insert(unit); unit.GroupId = i + 1; return true; } @@ -428,11 +416,11 @@ void AiForceManager::CheckUnits(int *counter) // Look through the forces what is missing. for (unsigned int i = 0; i < forces.size(); ++i) { - AiForce *force = &forces[i]; + const AiForce &force = forces[i]; - if (force->State > AI_FORCE_STATE_FREE && force->IsAttacking()) { - for (unsigned int j = 0; j < forces[i].Size(); ++j) { - const CUnit *unit = forces[i].Units[j]; + if (force.State > AiForceAttackingState_Free && force.IsAttacking()) { + for (unsigned int j = 0; j < force.Size(); ++j) { + const CUnit *unit = force.Units[j]; attacking[unit->Type->Slot]++; } } @@ -441,24 +429,24 @@ void AiForceManager::CheckUnits(int *counter) // create missing units for (unsigned int i = 0; i < forces.size(); ++i) { - AiForce *force = &forces[i]; + AiForce &force = forces[i]; // No troops for attacking force - if (force->State == AI_FORCE_STATE_FREE || force->IsAttacking()) { + if (force.State == AiForceAttackingState_Free || force.IsAttacking()) { continue; } - for (unsigned int j = 0; j < force->UnitTypes.size(); ++j) { - const AiUnitType *aiut = &force->UnitTypes[j]; - const int t = aiut->Type->Slot; - const int x = aiut->Want; - const int requested = x - (unit_types_count[t] + counter[t] - attacking[t]); + for (unsigned int j = 0; j < force.UnitTypes.size(); ++j) { + const AiUnitType &aiut = force.UnitTypes[j]; + const int t = aiut.Type->Slot; + const int wantedCount = aiut.Want; + const int requested = wantedCount - (unit_types_count[t] + counter[t] - attacking[t]); if (requested > 0) { // Request it. - AiAddUnitTypeRequest(*aiut->Type, requested); + AiAddUnitTypeRequest(*aiut.Type, requested); counter[t] += requested; - force->Completed = false; + force.Completed = false; } - counter[t] -= x; + counter[t] -= wantedCount; } } } @@ -560,7 +548,7 @@ void AiAttackWithForce(unsigned int force) /** ** Attack opponent with forces. -** Merge forces in array into one attack force and attack with it +** Merge forces in array into one attack force and attack with it ** Merge is make because units in one force help each other during attack ** ** @param forces Array with Force numbers to attack with (array should be finished with -1). @@ -611,41 +599,41 @@ void AiAttackWithForces(int *forces) ** ** @param aiForce force to group. */ -static void AiGroupAttackerForTransport(AiForce *aiForce) +static void AiGroupAttackerForTransport(AiForce &aiForce) { - Assert(aiForce->State == AI_FORCE_STATE_BOARDING); + Assert(aiForce.State == AiForceAttackingState_Boarding); unsigned int nbToTransport = 0; unsigned int transporterIndex = 0; bool goNext = true; - for (; transporterIndex < aiForce->Size(); ++transporterIndex) { - const CUnit *unit = aiForce->Units[transporterIndex]; + for (; transporterIndex < aiForce.Size(); ++transporterIndex) { + const CUnit *unit = aiForce.Units[transporterIndex]; if (unit->Type->CanTransport() && unit->Type->MaxOnBoard - unit->BoardCount > 0) { nbToTransport = unit->Type->MaxOnBoard - unit->BoardCount; break; } } - if (transporterIndex == aiForce->Size()) { - aiForce->State++; + if (transporterIndex == aiForce.Size()) { + aiForce.State = AiForceAttackingState_Attacking; return ; } - for (unsigned int i = 0; i < aiForce->Size(); ++i) { - const CUnit &unit = *aiForce->Units[i]; - const CUnit &transporter = *aiForce->Units[transporterIndex]; + for (unsigned int i = 0; i < aiForce.Size(); ++i) { + const CUnit &unit = *aiForce.Units[i]; + const CUnit &transporter = *aiForce.Units[transporterIndex]; if (CanTransport(transporter, unit) && unit.Container == NULL) { goNext = false; } } if (goNext == true) { - aiForce->State++; + aiForce.State = AiForceAttackingState_Attacking; return ; } - for (unsigned int i = 0; i < aiForce->Size(); ++i) { - CUnit &unit = *aiForce->Units[i]; - CUnit &transporter = *aiForce->Units[transporterIndex]; + for (unsigned int i = 0; i < aiForce.Size(); ++i) { + CUnit &unit = *aiForce.Units[i]; + CUnit &transporter = *aiForce.Units[transporterIndex]; if (transporter.IsIdle() && unit.CurrentOrder()->GetGoal() == &transporter) { CommandFollow(transporter, unit, 0); @@ -653,16 +641,16 @@ static void AiGroupAttackerForTransport(AiForce *aiForce) if (CanTransport(transporter, unit) && unit.IsIdle() && unit.Container == NULL) { CommandBoard(unit, transporter, FlushCommands); CommandFollow(transporter, unit, 0); - if (--nbToTransport == 0) { // full : nxt transporter. - for (++transporterIndex; transporterIndex < aiForce->Size(); ++transporterIndex) { - const CUnit &nextTransporter = *aiForce->Units[transporterIndex]; + if (--nbToTransport == 0) { // full : next transporter. + for (++transporterIndex; transporterIndex < aiForce.Size(); ++transporterIndex) { + const CUnit &nextTransporter = *aiForce.Units[transporterIndex]; if (nextTransporter.Type->CanTransport()) { nbToTransport = nextTransporter.Type->MaxOnBoard - nextTransporter.BoardCount; break ; } } - if (transporterIndex == aiForce->Size()) { // No more transporter. + if (transporterIndex == aiForce.Size()) { // No more transporter. break ; } } @@ -681,7 +669,7 @@ void AiForce::Update() if (Size() == 0) { Attacking = false; - if (!Defending && State > 0) { + if (!Defending && State > AiForceAttackingState_Waiting) { DebugPrint("%d: Attack force #%lu was destroyed, giving up\n" _C_ AiPlayer->Player->Index _C_ (long unsigned int)(this - &(AiPlayer->Force[0]))); Reset(true); @@ -698,7 +686,7 @@ void AiForce::Update() } } if (Attacking == false) { - if (!Defending && State > 0) { + if (!Defending && State > AiForceAttackingState_Waiting) { DebugPrint("%d: Attack force #%lu has lost all agresive units, giving up\n" _C_ AiPlayer->Player->Index _C_ (long unsigned int)(this - &(AiPlayer->Force[0]))); Reset(true); @@ -707,31 +695,30 @@ void AiForce::Update() } #if 0 - if (State == AI_FORCE_STATE_WAITING) { - if (!AiPlanAttack(force)) { + if (State == AiForceAttackingState_Waiting) { + if (!this->PlanAttack()) { DebugPrint("Can't transport, look for walls\n"); - if (!AiFindWall(force)) { + if (!AiFindWall(this)) { Attacking = false; return ; } } - State = AI_FORCE_STATE_BOARDING; + State = AiForceAttackingState_Boarding; } #endif - if (State == AI_FORCE_STATE_BOARDING) { - AiGroupAttackerForTransport(this); + if (State == AiForceAttackingState_Boarding) { + AiGroupAttackerForTransport(*this); return ; } - // Find a unit that isn't idle unit = NoUnitP; - if (State == AI_FORCE_STATE_ATTACKING) { + if (State == AiForceAttackingState_Attacking) { for (unsigned int i = 0; i < Size(); ++i) { CUnit *aiunit = Units[i]; if (!aiunit->IsIdle()) { - // Found an idle unit, use it if we find nothing better + // Found an no-idle unit, use it if we find nothing better if (unit == NoUnitP) { unit = aiunit; } @@ -772,44 +759,8 @@ void AiForce::Update() } } else { // Everyone is idle, find a new target Vec2i pos; -//FIXME: rb - I don't know if AI can use transport now -#if 0 - if (State == AI_FORCE_STATE_ATTACKING) { - unit = NULL; - - for (unsigned int i = 0; i < Units.size(); ++i) { - CUnit *aiunit = Units[i]; - if (aiunit->Type->CanAttack) { - unit = AttackUnitsInDistance(aiunit, MaxMapWidth); - break; - } - } - if (!unit) { - // No enemy found, give up - // FIXME: should the force go home or keep trying to attack? - DebugPrint("Attack force can't find a target, giving up\n"); - Attacking = false; - return; - } - pos = unit->tilePos; - } else { - pos = this->GoalPos; - } - for (unsigned int i = 0; i < Units.size(); ++i) { - CUnit *aiunit = Units[i]; - - if (aiunit->Type->CanTransport() && aiunit->BoardCount > 0) { - CommandUnload(aiunit, pos, NULL, FlushCommands); - } else if (aiunit->Type->CanAttack) { - CommandAttack(aiunit, pos, NULL, FlushCommands); - } else if (force->State == 2) { - CommandMove(aiunit, pos, FlushCommands); - } - } - force->State = 3; -#else - if (State == AI_FORCE_STATE_ATTACKING) { + if (State == AiForceAttackingState_Attacking) { unit = AiForceEnemyFinder<false>(this).enemy; if (!unit) { @@ -825,7 +776,6 @@ void AiForce::Update() pos = this->GoalPos; } AiForceAttackSender(this, pos); -#endif } } @@ -833,30 +783,30 @@ void AiForceManager::Update() { for(unsigned int f = 0; f < forces.size(); ++f) { - AiForce *force = &forces[f]; + AiForce &force = forces[f]; // // Look if our defenders still have enemies in range. // - if (force->Defending) { - force->Clean(); + if (force.Defending) { + force.Clean(); // // Look if still enemies in attack range. // - if(!AiForceEnemyFinder<true>(force).found()) { + if(!AiForceEnemyFinder<true>(&force).found()) { DebugPrint("%d:FIXME: not written, should send force #%d home\n" _C_ AiPlayer->Player->Index _C_ f); - force->Defending = false; - force->Attacking = false; + force.Defending = false; + force.Attacking = false; } - } else if (force->Attacking) { - force->Clean(); - force->Update(); + } else if (force.Attacking) { + force.Clean(); + force.Update(); } } } /** -** Entry point of force manager, perodic called. +** Entry point of force manager, periodic called. ** ** @todo FIXME: is this really needed anymore */ diff --git a/src/ai/ai_local.h b/src/ai/ai_local.h index 208506b2d..f3fdd4172 100644 --- a/src/ai/ai_local.h +++ b/src/ai/ai_local.h @@ -60,14 +60,7 @@ public: std::string Name; /// Name of this ai std::string Race; /// for this race std::string Class; /// class of this ai - -#if 0 - // nice flags - unsigned char AllExplored : 1; /// Ai sees unexplored area - unsigned char AllVisbile : 1; /// Ai sees invisibile area -#endif - - std::string Script; /// Main script + std::string Script; /// Main script }; /** @@ -89,7 +82,7 @@ public: AiUnitType() : Want(0), Type(NULL) {} unsigned int Want; /// number of this unit-type wanted - CUnitType *Type; /// unit-type self + CUnitType *Type; /// unit-type self }; /** @@ -100,11 +93,13 @@ enum AiForceRole { AiForceRoleDefend /// Force should defend }; -#define AI_FORCE_STATE_FREE -1 -#define AI_FORCE_STATE_WAITING 0 -#define AI_FORCE_STATE_BOARDING 1 -//#define AI_FORCE_STATE_OERATIONAL 2 -#define AI_FORCE_STATE_ATTACKING 3 +enum AiForceAttackingState +{ + AiForceAttackingState_Free = -1, + AiForceAttackingState_Waiting = 0, + AiForceAttackingState_Boarding, + AiForceAttackingState_Attacking, +}; /** ** Define an AI force. @@ -113,19 +108,10 @@ enum AiForceRole { */ class AiForce { friend class AiForceManager; - - bool IsBelongsTo(const CUnitType *type); - void Insert(CUnit &unit) - { - Units.Insert(&unit); - unit.RefsIncrease(); - } - - void Update(); public: - AiForce() : Completed(false), Defending(false), Attacking(false), - Role(0), State(AI_FORCE_STATE_FREE), - MustTransport(false) + AiForce() : + Completed(false), Defending(false), Attacking(false), + Role(0), State(AiForceAttackingState_Free) { GoalPos.x = GoalPos.y = 0; } @@ -133,8 +119,7 @@ public: void Remove(CUnit &unit) { if (Units.Remove(&unit)) { - unit.GroupId = 0; - unit.RefsDecrease(); + InternalRemoveUnit(&unit); } } @@ -147,13 +132,13 @@ public: Attacking = false; if (types) { UnitTypes.clear(); - State = AI_FORCE_STATE_FREE; + State = AiForceAttackingState_Free; } else { - State = AI_FORCE_STATE_WAITING; + State = AiForceAttackingState_Waiting; } + Units.for_each(InternalRemoveUnit); Units.clear(); GoalPos.x = GoalPos.y = 0; - MustTransport = false; } inline size_t Size() const { @@ -165,39 +150,51 @@ public: return (!Defending && Attacking); } - void CountTypes(unsigned int *counter, const size_t len); + void Attack(const Vec2i &pos); + void Clean(); + int PlanAttack(); +private: + void CountTypes(unsigned int *counter, const size_t len); + bool IsBelongsTo(const CUnitType *type); + void Insert(CUnit &unit) + { + Units.Insert(&unit); + unit.RefsIncrease(); + } + + void Update(); + + static void InternalRemoveUnit(CUnit *unit) { + unit->GroupId = 0; + unit->RefsDecrease(); + } + +public: bool Completed; /// Flag saying force is complete build bool Defending; /// Flag saying force is defending bool Attacking; /// Flag saying force is attacking char Role; /// Role of the force std::vector<AiUnitType> UnitTypes; /// Count and types of unit-type - CUnitCache Units; /// Units in the force + CUnitCache Units; /// Units in the force // // If attacking // - int State;/// Attack state + AiForceAttackingState State; /// Attack state Vec2i GoalPos; /// Attack point tile map position - bool MustTransport;/// Flag must use transporter - - void Attack(const Vec2i &pos); - void Clean(); - int PlanAttack(); }; // forces #define AI_MAX_FORCES 10 /// How many forces are supported -//#define AI_MAX_ATTACKING_FORCES 30 /// Attacking forces (max supported 32) + /** ** AI force manager. ** ** A Forces container for the force manager to handle */ class AiForceManager { - std::vector<AiForce> forces; - char script[AI_MAX_FORCES]; public: AiForceManager(); @@ -217,7 +214,6 @@ public: return -1; } - inline unsigned int getScriptForce(unsigned int index) { if (script[index] == -1) { script[index] = FindFreeForce(); @@ -230,6 +226,9 @@ public: void Update(); unsigned int FindFreeForce(int role = AiForceRoleAttack); void CheckUnits(int *counter); +private: + std::vector<AiForce> forces; + char script[AI_MAX_FORCES]; }; /** @@ -241,12 +240,13 @@ class AiBuildQueue { public: AiBuildQueue() : Want(0), Made(0), Type(NULL), Wait(0), X(-1), Y(-1) {} +public: unsigned int Want; /// requested number unsigned int Made; /// built number CUnitType *Type; /// unit-type unsigned long Wait; /// wait until this cycle - short int X; /// build near x pos on map - short int Y; /// build near y pos on map + short int X; /// build near x pos on map + short int Y; /// build near y pos on map }; /** @@ -256,6 +256,7 @@ class AiExplorationRequest { public: AiExplorationRequest(const Vec2i& pos, int mask) : pos(pos), Mask(mask) { } +public: Vec2i pos; /// pos on map int Mask; /// mask ( ex: MapFieldLandUnit ) }; @@ -267,6 +268,7 @@ class AiTransportRequest { public: AiTransportRequest() : Unit(NULL) {} +public: CUnit *Unit; CUnit::COrder Order; }; @@ -279,7 +281,7 @@ public: PlayerAi() : Player(NULL), AiType(NULL), SleepCycles(0), NeededMask(0), NeedSupply(false), ScriptDebug(false), LastExplorationGameCycle(0), - LastCanNotMoveGameCycle(0), LastRepairBuilding(0) + LastCanNotMoveGameCycle(0), LastRepairBuilding(0) { memset(Reserve, 0, sizeof(Reserve)); memset(Used, 0, sizeof(Used)); @@ -288,13 +290,14 @@ public: memset(TriedRepairWorkers, 0, sizeof(TriedRepairWorkers)); } +public: CPlayer *Player; /// Engine player structure CAiType *AiType; /// AI type of this player AI // controller std::string Script; /// Script executed unsigned long SleepCycles; /// Cycles to sleep - AiForceManager Force; /// Forces controlled by AI + AiForceManager Force; /// Forces controlled by AI // resource manager int Reserve[MaxCosts]; /// Resources to keep in reserve @@ -314,7 +317,7 @@ public: std::vector<CUpgrade *> ResearchRequests; /// Upgrades requested and priority list std::vector<AiBuildQueue> UnitTypeBuilt; /// What the resource manager should build int LastRepairBuilding; /// Last building checked for repair in this turn - unsigned int TriedRepairWorkers[UnitMax]; /// No. workers that failed trying to repair a building + unsigned int TriedRepairWorkers[UnitMax]; /// No. workers that failed trying to repair a building }; /** @@ -373,8 +376,6 @@ public: ** units/buildings/mines which can store this resource. */ std::vector<std::vector<CUnitType *> > Depots; - - }; /*---------------------------------------------------------------------------- diff --git a/src/ai/ai_magic.cpp b/src/ai/ai_magic.cpp index 7c460ea28..4e17eba21 100644 --- a/src/ai/ai_magic.cpp +++ b/src/ai/ai_magic.cpp @@ -33,17 +33,11 @@ -- Includes ----------------------------------------------------------------------------*/ -#include <stdio.h> -#include <stdlib.h> - #include "stratagus.h" #include "unittype.h" #include "unit.h" #include "spells.h" -#include "actions.h" -#include "map.h" #include "ai_local.h" -#include "player.h" /*---------------------------------------------------------------------------- -- Functions @@ -55,9 +49,9 @@ */ void AiCheckMagic() { - const int n = AiPlayer->Player->TotalNumUnits; - CUnit **units = AiPlayer->Player->Units; - const CPlayer &player = *AiPlayer->Player; /*units[0]->Player */ + CPlayer &player = *AiPlayer->Player; + const int n = player.TotalNumUnits; + CUnit **units = player.Units; for (int i = 0; i < n; ++i) { CUnit &unit = *units[i]; diff --git a/src/ai/ai_plan.cpp b/src/ai/ai_plan.cpp index e9adb9e89..1db06be39 100644 --- a/src/ai/ai_plan.cpp +++ b/src/ai/ai_plan.cpp @@ -43,7 +43,6 @@ #include "pathfinder.h" #include "actions.h" #include "ai_local.h" -#include "player.h" /*---------------------------------------------------------------------------- -- Variables @@ -433,7 +432,7 @@ int AiFindWall(AiForce *force) delete[] points; if (dest.x != -1) { - force->State = AI_FORCE_STATE_WAITING; + force->State = AiForceAttackingState_Waiting; for (unsigned int i = 0; i < force->Units.size(); ++i) { CUnit &aiunit = *force->Units[i]; if (aiunit.Type->CanAttack) { @@ -460,20 +459,16 @@ int AiFindWall(AiForce *force) */ int AiForce::PlanAttack() { - unsigned char *watermatrix; - int state; - CUnit *transporter; - DebugPrint("%d: Planning for force #%lu of player #%d\n"_C_ AiPlayer->Player->Index _C_ (long unsigned int)(this - &(AiPlayer->Force[0])) _C_ AiPlayer->Player->Index); - watermatrix = CreateMatrix(); + unsigned char *watermatrix = CreateMatrix(); // // Transporter must be already assigned to the force. - // NOTE: finding free transportes was too much work for me. + // NOTE: finding free transporters was too much work for me. // - state = 1; + int state = 1; for (unsigned int i = 0; i < Size(); ++i) { const CUnit &aiunit = *Units[i]; @@ -487,7 +482,7 @@ int AiForce::PlanAttack() // // No transport that belongs to the force. // - transporter = NULL; + CUnit *transporter = NULL; if (state) { for (int i = 0; i < AiPlayer->Player->TotalNumUnits; ++i) { CUnit &unit = *AiPlayer->Player->Units[i]; @@ -572,9 +567,7 @@ int AiForce::PlanAttack() } DebugPrint("%d: Can attack\n" _C_ AiPlayer->Player->Index); GoalPos = pos; - MustTransport = state == 2; - - State = AI_FORCE_STATE_BOARDING; + State = AiForceAttackingState_Boarding; return 1; } return 0; diff --git a/src/ai/ai_resource.cpp b/src/ai/ai_resource.cpp index 31e2979c9..b4d117e84 100644 --- a/src/ai/ai_resource.cpp +++ b/src/ai/ai_resource.cpp @@ -977,21 +977,13 @@ static int CmpWorkers(const void *w0,const void *w1) { */ static void AiCollectResources() { - CUnit *units_with_resource[MaxCosts][UnitMax]; // Worker with resource CUnit *units_assigned[MaxCosts][UnitMax]; // Worker assigned to resource CUnit *units_unassigned[MaxCosts][UnitMax]; // Unassigned workers int num_units_with_resource[MaxCosts]; int num_units_assigned[MaxCosts]; int num_units_unassigned[MaxCosts]; - int c; - int src_c; - int i; - int j; - int k; - int n; CUnit **units; int percent[MaxCosts]; - int percent_total; int priority_resource[MaxCosts]; int priority_needed[MaxCosts]; @@ -1007,19 +999,17 @@ static void AiCollectResources() // total_harvester = 0; - n = AiPlayer->Player->TotalNumUnits; + const int n = AiPlayer->Player->TotalNumUnits; units = AiPlayer->Player->Units; - for (i = 0; i < n; ++i) { + for (int i = 0; i < n; ++i) { CUnit &unit = *units[i]; if (!unit.Type->Harvester) { continue; } - c = unit.CurrentResource; + const int c = unit.CurrentResource; - // // See if it's assigned already - // if (c && unit.OrderCount == 1 && unit.CurrentAction() == UnitActionResource) { units_assigned[c][num_units_assigned[c]++] = &unit; @@ -1027,27 +1017,21 @@ static void AiCollectResources() continue; } - // // Ignore busy units. ( building, fighting, ... ) - // if (!unit.IsIdle()) { continue; } - // // Send workers with resources back home. - // if (unit.ResourcesHeld && c) { - units_with_resource[c][num_units_with_resource[c]++] = &unit; + num_units_with_resource[c]++; CommandReturnGoods(unit, 0, FlushCommands); total_harvester++; continue; } - // // Look what the unit can do - // - for (c = 1; c < MaxCosts; ++c) { + for (int c = 1; c < MaxCosts; ++c) { if (unit.Type->ResInfo[c]) { units_unassigned[c][num_units_unassigned[c]++] = &unit; } @@ -1055,14 +1039,14 @@ static void AiCollectResources() ++total_harvester; } - if(!total_harvester) { + if (!total_harvester) { return; } memset(wanted, 0, sizeof(wanted)); - percent_total = 100; - for (c = 1; c < MaxCosts; ++c) { + int percent_total = 100; + for (int c = 1; c < MaxCosts; ++c) { percent[c] = AiPlayer->Collect[c]; if ((AiPlayer->NeededMask & (1 << c))) { // Double percent if needed percent_total += percent[c]; @@ -1070,11 +1054,9 @@ static void AiCollectResources() } } - // // Turn percent values into harvester numbers. - // - for (c = 1; c < MaxCosts; ++c ) { - if(percent[c]) { + for (int c = 1; c < MaxCosts; ++c ) { + if (percent[c]) { // Wanted needs to be representative. if (total_harvester < 5) { wanted[c] = 1 + (percent[c] * 5) / percent_total; @@ -1084,67 +1066,55 @@ static void AiCollectResources() } } - // // Initialise priority & mapping - // - for (c = 0; c < MaxCosts; ++c) { + for (int c = 0; c < MaxCosts; ++c) { priority_resource[c] = c; priority_needed[c] = wanted[c] - num_units_assigned[c] - num_units_with_resource[c]; if (c && num_units_assigned[c] > 1) { //first should go workers with lower ResourcesHeld value - qsort(units_assigned[c], num_units_assigned[c], - sizeof(CUnit*), CmpWorkers); + qsort(units_assigned[c], num_units_assigned[c], sizeof(CUnit*), CmpWorkers); } } CUnit* unit; do { - // // sort resources by priority - // - for (i = 0; i < MaxCosts; ++i) { - for (j = i + 1; j < MaxCosts; ++j) { + for (int i = 0; i < MaxCosts; ++i) { + for (int j = i + 1; j < MaxCosts; ++j) { if (priority_needed[j] > priority_needed[i]) { - c = priority_needed[j]; - priority_needed[j] = priority_needed[i]; - priority_needed[i] = c; - c = priority_resource[j]; - priority_resource[j] = priority_resource[i]; - priority_resource[i] = c; + std::swap(priority_needed[i], priority_needed[j]); + std::swap(priority_resource[i], priority_resource[j]); } } } unit = NoUnitP; - // - // Try to complete each ressource in the priority order - // - for (i = 0; i < MaxCosts; ++i) { - c = priority_resource[i]; + // Try to complete each ressource in the priority order + for (int i = 0; i < MaxCosts; ++i) { + int c = priority_resource[i]; // // If there is a free worker for c, take it. // if (num_units_unassigned[c]) { // Take the unit. - j = 0; - while (j < num_units_unassigned[c] && !AiAssignHarvester(*units_unassigned[c][j], c)) { + while (0 < num_units_unassigned[c] && !AiAssignHarvester(*units_unassigned[c][0], c)) { // can't assign to c => remove from units_unassigned ! - units_unassigned[c][j] = units_unassigned[c][--num_units_unassigned[c]]; + units_unassigned[c][0] = units_unassigned[c][--num_units_unassigned[c]]; } // unit is assigned - if (j < num_units_unassigned[c]) { - unit = units_unassigned[c][j]; - units_unassigned[c][j] = units_unassigned[c][--num_units_unassigned[c]]; + if (0 < num_units_unassigned[c]) { + unit = units_unassigned[c][0]; + units_unassigned[c][0] = units_unassigned[c][--num_units_unassigned[c]]; // remove it from other ressources - for (j = 0; j < MaxCosts; ++j) { + for (int j = 0; j < MaxCosts; ++j) { if (j == c || !unit->Type->ResInfo[j]) { continue; } - for (k = 0; k < num_units_unassigned[j]; ++k) { + for (int k = 0; k < num_units_unassigned[j]; ++k) { if (units_unassigned[j][k] == unit) { units_unassigned[j][k] = units_unassigned[j][--num_units_unassigned[j]]; break; @@ -1159,9 +1129,9 @@ static void AiCollectResources() // if (!unit) { // Take from lower priority only (i+1). - for (j = i + 1; j < MaxCosts && !unit; ++j) { + for (int j = i + 1; j < MaxCosts && !unit; ++j) { // Try to move worker from src_c to c - src_c = priority_resource[j]; + const int src_c = priority_resource[j]; // Don't complete with lower priority ones... if (wanted[src_c] > wanted[c] || @@ -1170,7 +1140,7 @@ static void AiCollectResources() continue; } - for (k = num_units_assigned[src_c] - 1; k >= 0 && !unit; --k) { + for (int k = num_units_assigned[src_c] - 1; k >= 0 && !unit; --k) { unit = units_assigned[src_c][k]; if (unit->SubAction >= 65 /* SUB_STOP_GATHERING */ ) { @@ -1334,7 +1304,6 @@ static int AiRepairUnit(CUnit &unit) } } } - return 0; } @@ -1343,25 +1312,20 @@ static int AiRepairUnit(CUnit &unit) */ static void AiCheckRepair() { - int i; - int j; - int k; - int n; - bool repair_flag; + const int n = AiPlayer->Player->TotalNumUnits; + int k = 0; - n = AiPlayer->Player->TotalNumUnits; - k = 0; // Selector for next unit - for (i = n - 1; i >= 0; --i) { + for (int i = n - 1; i >= 0; --i) { CUnit *unit = AiPlayer->Player->Units[i]; if (unit && UnitNumber(*unit) == AiPlayer->LastRepairBuilding) { k = i + 1; } } - for (i = k; i < n; ++i) { + for (int i = k; i < n; ++i) { CUnit &unit = *AiPlayer->Player->Units[i]; - repair_flag = true; + bool repair_flag = true; if (!unit.IsAliveOnMap()) { continue; @@ -1374,7 +1338,6 @@ static void AiCheckRepair() unit.CurrentAction() != UnitActionUpgradeTo && unit.Variable[HP_INDEX].Value < unit.Variable[HP_INDEX].Max && unit.Attacked + 5 * CYCLES_PER_SECOND < GameCycle) { - // // FIXME: Repair only units under control // @@ -1384,7 +1347,7 @@ static void AiCheckRepair() // // Must check, if there are enough resources // - for (j = 1; j < MaxCosts; ++j) { + for (int j = 1; j < MaxCosts; ++j) { if (unit.Stats->Costs[j] && AiPlayer->Player->Resources[j] < 99) { repair_flag = false; diff --git a/src/ai/script_ai.cpp b/src/ai/script_ai.cpp index 4560ef27b..6b3b77607 100644 --- a/src/ai/script_ai.cpp +++ b/src/ai/script_ai.cpp @@ -1420,7 +1420,7 @@ static int CclDefineAiPlayer(lua_State *l) lua_pop(l, 1); } else if (!strcmp(value, "state")) { lua_rawgeti(l, j + 1, k + 1); - ai->Force[i].State = LuaToNumber(l, -1); + ai->Force[i].State = AiForceAttackingState(LuaToNumber(l, -1)); lua_pop(l, 1); } else if (!strcmp(value, "goalx")) { lua_rawgeti(l, j + 1, k + 1); @@ -1431,9 +1431,7 @@ static int CclDefineAiPlayer(lua_State *l) ai->Force[i].GoalPos.y = LuaToNumber(l, -1); lua_pop(l, 1); } else if (!strcmp(value, "must-transport")) { - lua_rawgeti(l, j + 1, k + 1); - ai->Force[i].MustTransport = LuaToNumber(l, -1) ? true : false; - lua_pop(l, 1); + // Keep for backward compatibility } else { LuaError(l, "Unsupported tag: %s" _C_ value); }