00001
00002
00003
00004
00005
00006
00007
00008
00009
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00032
00033
00034
00035
00036
00127
00128
00129
00130
00131 #include <string.h>
00132 #include <stdio.h>
00133 #include <stdlib.h>
00134
00135 #include "stratagus.h"
00136
00137 #include "player.h"
00138 #include "unit.h"
00139 #include "unittype.h"
00140 #include "upgrade.h"
00141 #include "script.h"
00142 #include "actions.h"
00143 #include "map.h"
00144 #include "pathfinder.h"
00145 #include "ai_local.h"
00146 #include "iolib.h"
00147
00148
00149
00150
00151
00152 int AiSleepCycles;
00153
00154 std::vector<CAiType *> AiTypes;
00155 AiHelper AiHelpers;
00156
00157 PlayerAi *AiPlayer;
00158
00159
00160
00161
00162
00166 static void AiExecuteScript(void)
00167 {
00168 if (!AiPlayer->Script.empty()) {
00169 lua_pushstring(Lua, "_ai_scripts_");
00170 lua_gettable(Lua, LUA_GLOBALSINDEX);
00171 lua_pushstring(Lua, AiPlayer->Script.c_str());
00172 lua_rawget(Lua, -2);
00173 LuaCall(0, 1);
00174 lua_pop(Lua, 1);
00175 }
00176 }
00177
00181 static void AiCheckUnits(void)
00182 {
00183 int counter[UnitTypeMax];
00184 int attacking[UnitTypeMax];
00185 const int *unit_types_count;
00186 int i;
00187
00188 memset(counter, 0, sizeof(counter));
00189 memset(attacking, 0, sizeof(attacking));
00190
00191
00192
00193
00194 for (i = 0; i < (int)AiPlayer->UnitTypeBuilt.size(); ++i) {
00195 AiBuildQueue *queue = &AiPlayer->UnitTypeBuilt[i];
00196 counter[queue->Type->Slot] += queue->Want;
00197 }
00198
00199 unit_types_count = AiPlayer->Player->UnitTypesCount;
00200
00201
00202
00203
00204 for (i = 0; i < (int)AiPlayer->UnitTypeRequests.size(); ++i) {
00205 int slot = AiPlayer->UnitTypeRequests[i].Type->Slot;
00206 int count = AiPlayer->UnitTypeRequests[i].Count;
00207 int e;
00208
00209
00210
00211
00212 e = unit_types_count[slot];
00213 if (slot < (int)AiHelpers.Equiv.size()) {
00214 for (int j = 0; j < (int)AiHelpers.Equiv[slot].size(); ++j) {
00215 e += unit_types_count[AiHelpers.Equiv[slot][j]->Slot];
00216 }
00217 }
00218
00219 if (count > e + counter[slot]) {
00220 AiAddUnitTypeRequest(AiPlayer->UnitTypeRequests[i].Type,
00221 count - e - counter[slot]);
00222 counter[slot] += count - e - counter[slot];
00223 }
00224 counter[slot] -= count;
00225 }
00226
00227
00228
00229
00230 for (i = AI_MAX_FORCES; i < AI_MAX_ATTACKING_FORCES; ++i) {
00231 for (int j = 0; j < (int)AiPlayer->Force[i].Units.size(); ++j) {
00232 attacking[AiPlayer->Force[i].Units[j]->Type->Slot]++;
00233 }
00234 }
00235
00236
00237
00238
00239 for (i = 0; i < AI_MAX_FORCES; ++i) {
00240
00241 if (!AiPlayer->Force[i].Defending && AiPlayer->Force[i].Attacking) {
00242 continue;
00243 }
00244
00245 for (int j = 0; j < (int)AiPlayer->Force[i].UnitTypes.size(); ++j) {
00246 const AiUnitType *aiut = &AiPlayer->Force[i].UnitTypes[j];
00247 int slot = aiut->Type->Slot;
00248 int want = aiut->Want;
00249 if (want > unit_types_count[slot] + counter[slot] - attacking[slot]) {
00250 AiAddUnitTypeRequest(aiut->Type,
00251 want - (unit_types_count[slot] + counter[slot] - attacking[slot]));
00252 counter[slot] += want - (unit_types_count[slot] + counter[slot] - attacking[slot]);
00253 AiPlayer->Force[i].Completed = false;
00254 }
00255 counter[slot] -= want;
00256 }
00257 }
00258 }
00259
00260
00261
00262
00263
00271 static void SaveAiPlayer(CFile *file, int plynr, PlayerAi *ai)
00272 {
00273 int i;
00274
00275 file->printf("DefineAiPlayer(%d,\n", plynr);
00276 file->printf(" \"ai-type\", \"%s\",\n", ai->AiType->Name.c_str());
00277
00278 file->printf(" \"script\", \"%s\",\n", ai->Script.c_str());
00279 file->printf(" \"script-debug\", %s,\n", ai->ScriptDebug ? "true" : "false");
00280 file->printf(" \"sleep-cycles\", %lu,\n", ai->SleepCycles);
00281
00282
00283
00284
00285 for (i = 0; i < AI_MAX_ATTACKING_FORCES; ++i) {
00286 int j;
00287
00288 file->printf(" \"force\", {%d, %s%s%s", i,
00289 ai->Force[i].Completed ? "\"complete\"," : "\"recruit\",",
00290 ai->Force[i].Attacking ? " \"attack\"," : "",
00291 ai->Force[i].Defending ? " \"defend\"," : "");
00292
00293 file->printf(" \"role\", ");
00294 switch (ai->Force[i].Role) {
00295 case AiForceRoleAttack:
00296 file->printf("\"attack\",");
00297 break;
00298 case AiForceRoleDefend:
00299 file->printf("\"defend\",");
00300 break;
00301 default:
00302 file->printf("\"unknown-%d\",", ai->Force[i].Role);
00303 break;
00304 }
00305
00306 file->printf("\n \"types\", { ");
00307 for (j = 0; j < (int)ai->Force[i].UnitTypes.size(); ++j) {
00308 const AiUnitType *aut = &ai->Force[i].UnitTypes[j];
00309 file->printf("%d, \"%s\", ", aut->Want, aut->Type->Ident.c_str());
00310 }
00311 file->printf("},\n \"units\", {");
00312 for (j = 0; j < (int)ai->Force[i].Units.size(); ++j) {
00313 const CUnit *aiunit = ai->Force[i].Units[j];
00314 file->printf(" %d, \"%s\",", UnitNumber(aiunit),
00315 aiunit->Type->Ident.c_str());
00316 }
00317 file->printf("},\n \"state\", %d, \"goalx\", %d, \"goaly\", %d, \"must-transport\", %d,",
00318 ai->Force[i].State, ai->Force[i].GoalX, ai->Force[i].GoalY, ai->Force[i].MustTransport);
00319 file->printf("},\n");
00320 }
00321
00322 file->printf(" \"needed\", {");
00323 for (i = 0; i < MaxCosts; ++i) {
00324 file->printf("\"%s\", %d, ", DefaultResourceNames[i].c_str(), ai->Needed[i]);
00325 }
00326 file->printf("},\n");
00327
00328 file->printf(" \"need-mask\", {");
00329 for (i = 0; i < MaxCosts; ++i) {
00330 if (ai->NeededMask & (1 << i)) {
00331 file->printf("\"%s\", ", DefaultResourceNames[i].c_str());
00332 }
00333 }
00334 file->printf("},\n");
00335 if (ai->NeedSupply) {
00336 file->printf(" \"need-supply\",\n");
00337 }
00338
00339
00340
00341
00342 if (!ai->FirstExplorationRequest.empty()) {
00343 file->printf(" \"exploration\", {");
00344 for (i = 0; i < (int)ai->FirstExplorationRequest.size(); ++i) {
00345 AiExplorationRequest *ptr = &ai->FirstExplorationRequest[i];
00346 file->printf("{%d, %d, %d}, ", ptr->X, ptr->Y, ptr->Mask);
00347 }
00348 file->printf("},\n");
00349 }
00350 file->printf(" \"last-exploration-cycle\", %lu,\n", ai->LastExplorationGameCycle);
00351 if (!ai->TransportRequests.empty()) {
00352 file->printf(" \"transport\", {");
00353 for (i = 0; i < (int)ai->TransportRequests.size(); ++i) {
00354 AiTransportRequest *ptr = &ai->TransportRequests[i];
00355 file->printf("{%d, ", UnitNumber(ptr->Unit));
00356 SaveOrder(&ptr->Order, file);
00357 file->printf("}, ");
00358 }
00359 file->printf("},\n");
00360 }
00361 file->printf(" \"last-can-not-move-cycle\", %lu,\n", ai->LastCanNotMoveGameCycle);
00362 file->printf(" \"unit-type\", {");
00363 for (i = 0; i < (int)ai->UnitTypeRequests.size(); ++i) {
00364 file->printf("\"%s\", ", ai->UnitTypeRequests[i].Type->Ident.c_str());
00365 file->printf("%d, ", ai->UnitTypeRequests[i].Count);
00366 }
00367 file->printf("},\n");
00368
00369
00370
00371
00372 file->printf(" \"building\", {");
00373 for (i = 0; i < (int)ai->UnitTypeBuilt.size(); ++i) {
00374 const AiBuildQueue *queue = &ai->UnitTypeBuilt[i];
00375 file->printf("\"%s\", %d, %d, ", queue->Type->Ident.c_str(), queue->Made, queue->Want);
00376 }
00377 file->printf("},\n");
00378
00379 file->printf(" \"repair-building\", %u,\n", ai->LastRepairBuilding);
00380
00381 file->printf(" \"repair-workers\", {");
00382 for (i = 0; i < UnitMax; ++i) {
00383 if (ai->TriedRepairWorkers[i]) {
00384 file->printf("%d, %d, ", i, ai->TriedRepairWorkers[i]);
00385 }
00386 }
00387 file->printf("})\n\n");
00388 }
00389
00395 static void SaveAiPlayers(CFile *file)
00396 {
00397 for (int p = 0; p < PlayerMax; ++p) {
00398 if (Players[p].Ai) {
00399 SaveAiPlayer(file, p, Players[p].Ai);
00400 }
00401 }
00402 }
00403
00409 void SaveAi(CFile *file)
00410 {
00411 file->printf("\n--- -----------------------------------------\n");
00412
00413 SaveAiPlayers(file);
00414
00415 DebugPrint("FIXME: Saving lua function definition isn't supported\n");
00416 }
00417
00423 void AiInit(CPlayer *player)
00424 {
00425 PlayerAi *pai;
00426 CAiType *ait;
00427 int i;
00428
00429 pai = new PlayerAi;
00430 if (!pai) {
00431 fprintf(stderr, "Out of memory.\n");
00432 exit(0);
00433 }
00434
00435 pai->Player = player;
00436 ait = NULL;
00437
00438 DebugPrint("%d - %p - looking for class %s\n" _C_
00439 player->Index _C_ player _C_ player->AiName.c_str());
00440
00441
00442
00443
00444
00445 if (AiTypes.empty()) {
00446 DebugPrint("AI: Got no scripts at all! You need at least one dummy fallback script.\n");
00447 DebugPrint("AI: Look at the DefineAi() documentation.\n");
00448 Exit(0);
00449 }
00450 for (i = 0; i < (int)AiTypes.size(); ++i) {
00451 ait = AiTypes[i];
00452 if (!player->AiName.empty() && ait->Class != player->AiName) {
00453 continue;
00454 }
00455 break;
00456 }
00457 if (i == (int)AiTypes.size()) {
00458 DebugPrint("AI: Found no matching ai scripts at all!\n");
00459
00460 exit(0);
00461 }
00462 if (player->AiName.empty()) {
00463 DebugPrint("AI: not found!!!!!!!!!!\n");
00464 DebugPrint("AI: Using fallback:\n");
00465 }
00466 DebugPrint("AI: %s:%s\n" _C_ player->AiName.c_str() _C_ ait->Class.c_str());
00467
00468 pai->AiType = ait;
00469 pai->Script = ait->Script;
00470
00471 player->Ai = pai;
00472 }
00473
00477 void InitAiModule(void)
00478 {
00479 AiResetUnitTypeEquiv();
00480 }
00481
00482
00486 void CleanAi(void)
00487 {
00488 for (int p = 0; p < PlayerMax; ++p) {
00489 if (Players[p].Ai) {
00490 delete Players[p].Ai;
00491 Players[p].Ai = NULL;
00492 }
00493 }
00494 }
00495
00496
00500 void FreeAi()
00501 {
00502 CleanAi();
00503
00504
00505
00506
00507 for (int i = 0; i < (int)AiTypes.size(); ++i) {
00508 CAiType *aitype = AiTypes[i];
00509
00510 delete aitype;
00511 }
00512 AiTypes.clear();
00513
00514
00515
00516
00517 AiHelpers.Train.clear();
00518 AiHelpers.Build.clear();
00519 AiHelpers.Repair.clear();
00520 AiHelpers.UnitLimit.clear();
00521 AiHelpers.Equiv.clear();
00522
00523 AiResetUnitTypeEquiv();
00524 }
00525
00526
00527
00528
00529
00537 static int AiRemoveFromBuilt2(PlayerAi *pai, const CUnitType *type)
00538 {
00539 std::vector<AiBuildQueue>::iterator i;
00540
00541 for (i = pai->UnitTypeBuilt.begin(); i != pai->UnitTypeBuilt.end(); ++i) {
00542 Assert((*i).Want);
00543 if (type == (*i).Type && (*i).Made) {
00544 --(*i).Made;
00545 if (!--(*i).Want) {
00546 pai->UnitTypeBuilt.erase(i);
00547 }
00548 return 1;
00549 }
00550 }
00551 return 0;
00552 }
00553
00560 static void AiRemoveFromBuilt(PlayerAi *pai, const CUnitType *type)
00561 {
00562 int equivalents[UnitTypeMax + 1];
00563 int equivalentsCount;
00564
00565 if (AiRemoveFromBuilt2(pai, type)) {
00566 return;
00567 }
00568
00569
00570
00571
00572 equivalentsCount = AiFindUnitTypeEquiv(type, equivalents);
00573 for (int i = 0; i < equivalentsCount; ++i) {
00574 if (AiRemoveFromBuilt2(pai, UnitTypes[equivalents[i]])) {
00575 return;
00576 }
00577 }
00578
00579 if (pai->Player == ThisPlayer) {
00580 DebugPrint
00581 ("My guess is that you built something under ai me. naughty boy!\n");
00582 return;
00583 }
00584
00585 Assert(0);
00586 }
00587
00595 static int AiReduceMadeInBuilt2(PlayerAi *pai, const CUnitType *type)
00596 {
00597 std::vector<AiBuildQueue>::iterator i;
00598
00599 for (i = pai->UnitTypeBuilt.begin(); i != pai->UnitTypeBuilt.end(); ++i) {
00600 if (type == (*i).Type && (*i).Made) {
00601 (*i).Made--;
00602 return 1;
00603 }
00604 }
00605 return 0;
00606 }
00607
00614 static void AiReduceMadeInBuilt(PlayerAi *pai, const CUnitType *type)
00615 {
00616 int equivs[UnitTypeMax + 1];
00617 int equivnb;
00618
00619 if (AiReduceMadeInBuilt2(pai, type)) {
00620 return;
00621 }
00622
00623
00624
00625 equivnb = AiFindUnitTypeEquiv(type, equivs);
00626
00627 for (int i = 0; i < (int)AiHelpers.Equiv[type->Slot].size(); ++i) {
00628 if (AiReduceMadeInBuilt2(pai, UnitTypes[equivs[i]])) {
00629 return;
00630 }
00631 }
00632
00633 Assert(0);
00634 }
00635
00636
00637
00638
00639
00646 void AiHelpMe(const CUnit *attacker, CUnit *defender)
00647 {
00648 PlayerAi *pai;
00649 CUnit *aiunit;
00650 int force;
00651
00652 DebugPrint("%d: %d(%s) attacked at %d,%d\n" _C_
00653 defender->Player->Index _C_ UnitNumber(defender) _C_
00654 defender->Type->Ident.c_str() _C_ defender->X _C_ defender->Y);
00655
00656
00657
00658
00659 if (!defender->Type->CanAttack && defender->Type->UnitType == UnitTypeFly) {
00660 return;
00661 }
00662
00663 AiPlayer = pai = defender->Player->Ai;
00664 if (pai->Force[0].Attacking) {
00665 return;
00666 }
00667
00668
00669
00670
00671 for (force = 0; force < AI_MAX_ATTACKING_FORCES; ++force) {
00672 if (!pai->Force[force].Attacking) {
00673
00674 continue;
00675 }
00676 for (int i = 0; i < (int)pai->Force[force].Units.size(); ++i) {
00677 aiunit = pai->Force[force].Units[i];
00678 if (defender == aiunit) {
00679 return;
00680 }
00681 }
00682 }
00683
00684
00685
00686
00687 if (attacker) {
00688 AiAttackWithForceAt(0, attacker->X, attacker->Y);
00689 if (!pai->Force[1].Attacking) {
00690 pai->Force[1].Defending = true;
00691 AiAttackWithForceAt(1, attacker->X, attacker->Y);
00692 }
00693 } else {
00694 AiAttackWithForceAt(0, defender->X, defender->Y);
00695 if (!pai->Force[1].Attacking) {
00696 pai->Force[1].Defending = true;
00697 AiAttackWithForceAt(1, defender->X, defender->Y);
00698 }
00699 }
00700 pai->Force[0].Defending = true;
00701 }
00702
00708 void AiUnitKilled(CUnit *unit)
00709 {
00710 DebugPrint("%d: %d(%s) killed\n" _C_
00711 unit->Player->Index _C_ UnitNumber(unit) _C_ unit->Type->Ident.c_str());
00712
00713 Assert(unit->Player->Type != PlayerPerson);
00714
00715
00716 switch (unit->Orders[0]->Action) {
00717 case UnitActionStill:
00718 case UnitActionAttack:
00719 case UnitActionMove:
00720 break;
00721 case UnitActionBuilt:
00722 DebugPrint("%d: %d(%s) killed, under construction!\n" _C_
00723 unit->Player->Index _C_ UnitNumber(unit) _C_ unit->Type->Ident.c_str());
00724 AiReduceMadeInBuilt(unit->Player->Ai, unit->Type);
00725 break;
00726 case UnitActionBuild:
00727 DebugPrint("%d: %d(%s) killed, with order %s!\n" _C_
00728 unit->Player->Index _C_ UnitNumber(unit) _C_
00729 unit->Type->Ident.c_str() _C_ unit->Orders[0]->Type->Ident.c_str());
00730 if (!unit->Orders[0]->Goal) {
00731 AiReduceMadeInBuilt(unit->Player->Ai, unit->Orders[0]->Type);
00732 }
00733 break;
00734 default:
00735 DebugPrint("FIXME: %d: %d(%s) killed, with order %d!\n" _C_
00736 unit->Player->Index _C_ UnitNumber(unit) _C_
00737 unit->Type->Ident.c_str() _C_ unit->Orders[0]->Action);
00738 break;
00739 }
00740 }
00741
00748 void AiWorkComplete(CUnit *unit, CUnit *what)
00749 {
00750 if (unit) {
00751 DebugPrint("%d: %d(%s) build %s at %d,%d completed\n" _C_
00752 what->Player->Index _C_ UnitNumber(unit) _C_ unit->Type->Ident.c_str() _C_
00753 what->Type->Ident.c_str() _C_ unit->X _C_ unit->Y);
00754 } else {
00755 DebugPrint("%d: building %s at %d,%d completed\n" _C_
00756 what->Player->Index _C_ what->Type->Ident.c_str() _C_ what->X _C_ what->Y);
00757 }
00758
00759 Assert(what->Player->Type != PlayerPerson);
00760 AiRemoveFromBuilt(what->Player->Ai, what->Type);
00761 }
00762
00769 void AiCanNotBuild(CUnit *unit, const CUnitType *what)
00770 {
00771 DebugPrint("%d: %d(%s) Can't build %s at %d,%d\n" _C_
00772 unit->Player->Index _C_ UnitNumber(unit) _C_ unit->Type->Ident.c_str() _C_
00773 what->Ident.c_str() _C_ unit->X _C_ unit->Y);
00774
00775 Assert(unit->Player->Type != PlayerPerson);
00776 AiReduceMadeInBuilt(unit->Player->Ai, what);
00777 }
00778
00785 void AiCanNotReach(CUnit *unit, const CUnitType *what)
00786 {
00787 Assert(unit->Player->Type != PlayerPerson);
00788 AiReduceMadeInBuilt(unit->Player->Ai, what);
00789 }
00790
00794 static void AiMoveUnitInTheWay(CUnit *unit)
00795 {
00796 static int dirs[8][2] = {{-1,-1},{-1,0},{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1}};
00797 int ux0;
00798 int uy0;
00799 int ux1;
00800 int uy1;
00801 int bx0;
00802 int by0;
00803 int bx1;
00804 int by1;
00805 int x;
00806 int y;
00807 int trycount,i;
00808 CUnit *blocker;
00809 CUnitType *unittype;
00810 CUnitType *blockertype;
00811 CUnit *movableunits[16];
00812 int movablepos[16][2];
00813 int movablenb;
00814
00815 AiPlayer = unit->Player->Ai;
00816
00817
00818 if (GameCycle == AiPlayer->LastCanNotMoveGameCycle) {
00819 return;
00820 }
00821
00822 unittype = unit->Type;
00823
00824 ux0 = unit->X;
00825 uy0 = unit->Y;
00826 ux1 = ux0 + unittype->TileWidth - 1;
00827 uy1 = uy0 + unittype->TileHeight - 1;
00828
00829 movablenb = 0;
00830
00831
00832
00833 for (i = 0; i < NumUnits; ++i) {
00834 blocker = Units[i];
00835
00836 if (blocker->IsUnusable()) {
00837 continue;
00838 }
00839
00840 if (!blocker->IsIdle()) {
00841 continue;
00842 }
00843
00844 if (blocker->Player != unit->Player) {
00845
00846 if (!(blocker->Player->Allied & (1 << unit->Player->Index))) {
00847 continue;
00848 }
00849 }
00850
00851 blockertype = blocker->Type;
00852
00853 if (blockertype->UnitType != unittype->UnitType) {
00854 continue;
00855 }
00856
00857 if (!CanMove(blocker)) {
00858 continue;
00859 }
00860
00861 bx0 = blocker->X;
00862 by0 = blocker->Y;
00863 bx1 = bx0 + blocker->Type->TileWidth - 1;
00864 by1 = by0 + blocker->Type->TileHeight - 1;;
00865
00866
00867 if (!((ux0 == bx1 + 1 || ux1 == bx0 - 1) &&
00868 (std::max(by0, uy0) <= std::min(by1, uy1))) &&
00869 !((uy0 == by1 + 1 || uy1 == by0 - 1) &&
00870 (std::max(bx0, ux0) <= std::min(bx1, ux1))))
00871 {
00872 continue;
00873 }
00874
00875 if (unit == blocker) {
00876 continue;
00877 }
00878
00879
00880 i = SyncRand() & 7;
00881 trycount = 8;
00882 while (trycount > 0) {
00883 i = (i + 1) & 7;
00884 --trycount;
00885
00886 x = blocker->X + dirs[i][0];
00887 y = blocker->Y + dirs[i][1];
00888
00889
00890 if (x < 0 || y < 0 || x >= Map.Info.MapWidth || y >= Map.Info.MapHeight) {
00891 continue;
00892 }
00893
00894 if (x == ux0 && y == uy0) {
00895 continue;
00896 }
00897
00898 movableunits[movablenb] = blocker;
00899 movablepos[movablenb][0] = x;
00900 movablepos[movablenb][1] = y;
00901
00902 ++movablenb;
00903 trycount = 0;
00904 }
00905 if (movablenb >= 16) {
00906 break;
00907 }
00908 }
00909
00910
00911 if (movablenb) {
00912 i = SyncRand() % movablenb;
00913 CommandMove(movableunits[i], movablepos[i][0], movablepos[i][1],
00914 FlushCommands);
00915 AiPlayer->LastCanNotMoveGameCycle = GameCycle;
00916 }
00917 }
00918
00924 void AiCanNotMove(CUnit *unit)
00925 {
00926 int gx, gy, gw, gh;
00927 int minrange, maxrange;
00928
00929 AiPlayer = unit->Player->Ai;
00930
00931 if (unit->Orders[0]->Goal) {
00932 gw = unit->Orders[0]->Goal->Type->TileWidth;
00933 gh = unit->Orders[0]->Goal->Type->TileHeight;
00934 gx = unit->Orders[0]->Goal->X;
00935 gy = unit->Orders[0]->Goal->Y;
00936 maxrange = unit->Orders[0]->Range;
00937 minrange = unit->Orders[0]->MinRange;
00938 } else {
00939
00940
00941
00942 gw = unit->Orders[0]->Width;
00943 gh = unit->Orders[0]->Height;
00944 maxrange = unit->Orders[0]->Range;
00945 minrange = unit->Orders[0]->MinRange;
00946 gx = unit->Orders[0]->X;
00947 gy = unit->Orders[0]->Y;
00948 }
00949
00950 if (unit->Type->UnitType == UnitTypeFly ||
00951 PlaceReachable(unit, gx, gy, gw, gh, minrange, maxrange)) {
00952
00953 AiMoveUnitInTheWay(unit);
00954 return;
00955 }
00956 }
00957
00964 void AiNeedMoreSupply(const CUnit *unit, const CUnitType *what)
00965 {
00966 Assert(unit->Player->Type != PlayerPerson);
00967 unit->Player->Ai->NeedSupply = true;
00968 }
00969
00976 void AiTrainingComplete(CUnit *unit, CUnit *what)
00977 {
00978 DebugPrint("%d: %d(%s) training %s at %d,%d completed\n" _C_
00979 unit->Player->Index _C_ UnitNumber(unit) _C_ unit->Type->Ident.c_str() _C_
00980 what->Type->Ident.c_str() _C_ unit->X _C_ unit->Y);
00981
00982 Assert(unit->Player->Type != PlayerPerson);
00983
00984 AiRemoveFromBuilt(unit->Player->Ai, what->Type);
00985
00986 AiPlayer = unit->Player->Ai;
00987 AiCleanForces();
00988 AiAssignToForce(what);
00989 }
00990
00996 void AiEachCycle(CPlayer *player)
00997 {
00998 AiPlayer = player->Ai;
00999
01000 for (int i = 0; i < (int)AiPlayer->TransportRequests.size(); ++i) {
01001 AiTransportRequest *aitr = &AiPlayer->TransportRequests[i];
01002 aitr->Unit->RefsDecrease();
01003 if (aitr->Order.Goal) {
01004 aitr->Order.Goal->RefsDecrease();
01005 }
01006 }
01007 AiPlayer->TransportRequests.clear();
01008 }
01009
01015 void AiEachSecond(CPlayer *player)
01016 {
01017 AiPlayer = player->Ai;
01018 #ifdef DEBUG
01019 if (!AiPlayer) {
01020 return;
01021 }
01022 #endif
01023
01024
01025
01026
01027 AiExecuteScript();
01028
01029
01030
01031
01032 AiCheckUnits();
01033
01034
01035
01036 AiResourceManager();
01037
01038
01039
01040 AiForceManager();
01041
01042
01043
01044 AiCheckMagic();
01045
01046
01047 if (GameCycle > AiPlayer->LastExplorationGameCycle + 5 * CYCLES_PER_SECOND) {
01048 AiSendExplorers();
01049 }
01050 }
01051