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
00030
00031
00032
00033
00034
00035 #include <stdio.h>
00036 #include <stdlib.h>
00037 #include <string.h>
00038
00039 #include "stratagus.h"
00040 #include "unittype.h"
00041 #include "unit.h"
00042 #include "ai_local.h"
00043 #include "actions.h"
00044 #include "map.h"
00045 #include "pathfinder.h"
00046 #include "player.h"
00047
00048
00049
00050
00051
00052 int UnitTypeEquivs[UnitTypeMax + 1];
00053
00054
00055
00056
00057
00058
00062 void AiResetUnitTypeEquiv(void)
00063 {
00064 for (int i = 0; i <= UnitTypeMax; ++i) {
00065 UnitTypeEquivs[i] = i;
00066 }
00067 }
00068
00075 void AiNewUnitTypeEquiv(CUnitType *a, CUnitType *b)
00076 {
00077 int find;
00078 int replace;
00079 int i;
00080
00081 find = UnitTypeEquivs[a->Slot];
00082 replace = UnitTypeEquivs[b->Slot];
00083
00084
00085 if (find < replace) {
00086 i = find;
00087 find = replace;
00088 replace = i;
00089 }
00090
00091
00092 for (i = 0; i <= UnitTypeMax; ++i) {
00093 if (UnitTypeEquivs[i] == find) {
00094 UnitTypeEquivs[i] = replace;
00095 }
00096 }
00097 }
00098
00099
00108 int AiFindUnitTypeEquiv(const CUnitType *unittype, int *result)
00109 {
00110 int i;
00111 int search;
00112 int count;
00113
00114 search = UnitTypeEquivs[unittype->Slot];
00115 count = 0;
00116
00117 for (i = 0; i < UnitTypeMax + 1; ++i) {
00118 if (UnitTypeEquivs[i] == search) {
00119
00120 result[count] = i;
00121 count++;
00122 }
00123 }
00124
00125 return count;
00126 }
00127
00137 int AiFindAvailableUnitTypeEquiv(const CUnitType *unittype, int *usableTypes)
00138 {
00139 int usableTypesCount;
00140 int i;
00141 int j;
00142 int tmp;
00143 int playerid;
00144 int bestlevel;
00145 int curlevel;
00146
00147
00148 usableTypesCount = AiFindUnitTypeEquiv(unittype, usableTypes);
00149
00150
00151 playerid = AiPlayer->Player->Index;
00152
00153
00154 for (i = 0; i < usableTypesCount - 1; ++i) {
00155 bestlevel = UnitTypes[usableTypes[i]]->Priority;
00156 for (j = i + 1; j < usableTypesCount; ++j) {
00157 curlevel = UnitTypes[usableTypes[j]]->Priority;
00158
00159 if (curlevel > bestlevel) {
00160
00161 tmp = usableTypes[j];
00162 usableTypes[j] = usableTypes[i];
00163 usableTypes[i] = tmp;
00164
00165 bestlevel = curlevel;
00166 }
00167 }
00168 }
00169
00170 return usableTypesCount;
00171 }
00172
00178 static void AiCleanForce(int force)
00179 {
00180 CUnit *aiunit;
00181 const AiUnitType *aitype;
00182 int counter[UnitTypeMax + 1];
00183 int i;
00184
00185
00186
00187
00188 i = 0;
00189 while (i != (int)AiPlayer->Force[force].Units.size()) {
00190 aiunit = AiPlayer->Force[force].Units[i];
00191 if (aiunit->Destroyed) {
00192 aiunit->RefsDecrease();
00193 AiPlayer->Force[force].Units.erase(
00194 AiPlayer->Force[force].Units.begin() + i);
00195 continue;
00196 } else if (aiunit->Orders[0]->Action == UnitActionDie) {
00197 aiunit->RefsDecrease();
00198 AiPlayer->Force[force].Units.erase(
00199 AiPlayer->Force[force].Units.begin() + i);
00200 continue;
00201 }
00202 ++i;
00203 }
00204
00205
00206
00207
00208 memset(counter, 0, sizeof(counter));
00209 for (i = 0; i < (int)AiPlayer->Force[force].Units.size(); ++i) {
00210 aiunit = AiPlayer->Force[force].Units[i];
00211
00212 counter[UnitTypeEquivs[aiunit->Type->Slot]]++;
00213 }
00214
00215
00216
00217
00218 AiPlayer->Force[force].Completed = true;
00219 for (i = 0; i < (int)AiPlayer->Force[force].UnitTypes.size(); ++i) {
00220 aitype = &AiPlayer->Force[force].UnitTypes[i];
00221 if (aitype->Want > counter[aitype->Type->Slot]) {
00222 AiPlayer->Force[force].Completed = false;
00223 }
00224 counter[aitype->Type->Slot] -= aitype->Want;
00225 }
00226
00227
00228
00229
00230 if (!AiPlayer->Force[force].Attacking) {
00231 i = 0;
00232 while (i != (int)AiPlayer->Force[force].Units.size()) {
00233 aiunit = AiPlayer->Force[force].Units[i];
00234 if (counter[aiunit->Type->Slot] > 0) {
00235 counter[UnitTypeEquivs[aiunit->Type->Slot]]--;
00236 aiunit->RefsDecrease();
00237 AiPlayer->Force[force].Units.erase(
00238 AiPlayer->Force[force].Units.begin() + i);
00239 continue;
00240 }
00241 ++i;
00242 }
00243 }
00244 }
00245
00249 void AiCleanForces(void)
00250 {
00251
00252
00253
00254 for (int force = 0; force < AI_MAX_ATTACKING_FORCES; ++force) {
00255 AiCleanForce(force);
00256 }
00257 }
00258
00267 static int AiCheckBelongsToForce(int force, const CUnitType *type)
00268 {
00269 CUnit *aiunit;
00270 AiUnitType *aitype;
00271 int counter[UnitTypeMax + 1];
00272 int flag;
00273 int i;
00274
00275 memset(counter, 0, sizeof(counter));
00276
00277
00278
00279 for (i = 0; i < (int)AiPlayer->Force[force].Units.size(); ++i) {
00280 aiunit = AiPlayer->Force[force].Units[i];
00281 counter[UnitTypeEquivs[aiunit->Type->Slot]]++;
00282 }
00283
00284
00285
00286
00287 flag = 0;
00288 AiPlayer->Force[force].Completed = true;
00289 for (i = 0; i < (int)AiPlayer->Force[force].UnitTypes.size(); ++i) {
00290 aitype = &AiPlayer->Force[force].UnitTypes[i];
00291 if (aitype->Want > counter[aitype->Type->Slot]) {
00292 if (UnitTypeEquivs[type->Slot] == aitype->Type->Slot) {
00293 if (aitype->Want - 1 > counter[aitype->Type->Slot]) {
00294 AiPlayer->Force[force].Completed = false;
00295 }
00296 flag = 1;
00297 } else {
00298 AiPlayer->Force[force].Completed = false;
00299 }
00300 }
00301 }
00302 return flag;
00303 }
00304
00310 void AiAssignToForce(CUnit *unit)
00311 {
00312
00313
00314
00315 for (int force = 0; force < AI_MAX_FORCES; ++force) {
00316
00317 if (!AiPlayer->Force[force].Defending &&
00318 AiPlayer->Force[force].Attacking) {
00319 continue;
00320 }
00321
00322 if (AiCheckBelongsToForce(force, unit->Type)) {
00323 AiPlayer->Force[force].Units.insert(
00324 AiPlayer->Force[force].Units.begin(), unit);
00325 unit->RefsIncrease();
00326 break;
00327 }
00328 }
00329 }
00330
00334 void AiAssignFreeUnitsToForce(void)
00335 {
00336 const CUnit *aiunit;
00337 CUnit *table[UnitMax];
00338 int n;
00339 int f;
00340 int i;
00341
00342 AiCleanForces();
00343
00344 n = AiPlayer->Player->TotalNumUnits;
00345 memcpy(table, AiPlayer->Player->Units, sizeof(*AiPlayer->Player->Units) * n);
00346
00347
00348
00349
00350 for (f = 0; f < AI_MAX_ATTACKING_FORCES; ++f) {
00351 for (int j = 0; j < (int)AiPlayer->Force[f].Units.size(); ++j) {
00352 aiunit = AiPlayer->Force[f].Units[j];
00353 for (i = 0; i < n; ++i) {
00354 if (table[i] == aiunit) {
00355 table[i] = table[--n];
00356 }
00357 }
00358 }
00359 }
00360
00361
00362
00363
00364 for (i = 0; i < n; ++i) {
00365 AiAssignToForce(table[i]);
00366 }
00367 }
00368
00376 void AiAttackWithForceAt(int force, int x, int y)
00377 {
00378 AiCleanForce(force);
00379
00380 if (!AiPlayer->Force[force].Units.empty()) {
00381 AiPlayer->Force[force].Attacking = true;
00382
00383
00384
00385
00386 for (int i = 0; i < (int)AiPlayer->Force[force].Units.size(); ++i) {
00387 CUnit *aiunit = AiPlayer->Force[force].Units[i];
00388 aiunit->Wait = i;
00389 if (aiunit->Type->CanAttack) {
00390 CommandAttack(aiunit, x, y, NULL, FlushCommands);
00391 } else {
00392 CommandMove(aiunit, x, y, FlushCommands);
00393 }
00394 }
00395 }
00396 }
00397
00403 void AiAttackWithForce(int force)
00404 {
00405 CUnit *aiunit;
00406 const CUnit *enemy;
00407 int x;
00408 int y;
00409 int f;
00410 int i;
00411
00412
00413
00414 if (force < AI_MAX_FORCES) {
00415 f = AI_MAX_FORCES;
00416 while (AiPlayer->Force[f].Attacking) {
00417 ++f;
00418 if (f == AI_MAX_ATTACKING_FORCES) {
00419 DebugPrint("No free attacking forces\n");
00420 f = force;
00421 break;
00422 }
00423 }
00424 if (f != AI_MAX_ATTACKING_FORCES) {
00425 AiPlayer->Force[f] = AiPlayer->Force[force];
00426 AiPlayer->Force[force].Reset();
00427 }
00428
00429 force = f;
00430 }
00431
00432 AiCleanForce(force);
00433
00434 AiPlayer->Force[force].Attacking = false;
00435 if (!AiPlayer->Force[force].Units.empty()) {
00436 AiPlayer->Force[force].Attacking = true;
00437
00438 enemy = NULL;
00439 for (i = 0; !enemy && i < (int)AiPlayer->Force[force].Units.size(); ++i) {
00440 aiunit = AiPlayer->Force[force].Units[i];
00441 if (aiunit->Type->CanAttack) {
00442 enemy = AttackUnitsInDistance(aiunit, MaxMapWidth);
00443 }
00444 }
00445
00446 if (!enemy) {
00447 DebugPrint("Need to plan an attack with transporter\n");
00448 if (!AiPlayer->Force[force].State &&
00449 !AiPlanAttack(&AiPlayer->Force[force])) {
00450 DebugPrint("Can't transport\n");
00451 AiPlayer->Force[force].Attacking = false;
00452 }
00453 return;
00454 }
00455 AiPlayer->Force[force].State = 0;
00456 x = enemy->X;
00457 y = enemy->Y;
00458
00459
00460
00461
00462 for (i = 0; i < (int)AiPlayer->Force[force].Units.size(); ++i) {
00463 aiunit = AiPlayer->Force[force].Units[i];
00464 aiunit->Wait = i;
00465 if (aiunit->Type->CanAttack) {
00466 CommandAttack(aiunit, enemy->X, enemy->Y, NULL, FlushCommands);
00467 } else {
00468 CommandMove(aiunit, enemy->X, enemy->Y, FlushCommands);
00469 }
00470 }
00471 }
00472 }
00473
00479 static void AiForceAttacks(AiForce *force)
00480 {
00481 CUnit *aiunit;
00482 int x;
00483 int y;
00484 const CUnit *unit;
00485 int i;
00486
00487 if (force->Units.empty()) {
00488 force->Attacking = false;
00489 return;
00490 }
00491
00492
00493 unit = NoUnitP;
00494 for (i = 0; i < (int)force->Units.size(); ++i) {
00495 aiunit = force->Units[i];
00496 if (!aiunit->IsIdle()) {
00497
00498 if (unit == NoUnitP) {
00499 unit = aiunit;
00500 }
00501
00502 if (aiunit->Orders[0]->Goal != NoUnitP) {
00503 unit = aiunit;
00504 break;
00505 }
00506 }
00507 }
00508
00509 if (unit != NoUnitP) {
00510
00511
00512 for (i = 0; i < (int)force->Units.size(); ++i) {
00513 aiunit = force->Units[i];
00514 if (aiunit->IsIdle()) {
00515 if (unit->Orders[0]->Goal) {
00516 x = unit->Orders[0]->Goal->X;
00517 y = unit->Orders[0]->Goal->Y;
00518 } else if (unit->Orders[0]->X != -1 && unit->Orders[0]->Y != -1) {
00519 x = unit->Orders[0]->X;
00520 y = unit->Orders[0]->Y;
00521 } else {
00522 x = unit->X;
00523 y = unit->Y;
00524 }
00525 if (aiunit->Type->CanAttack) {
00526 CommandAttack(aiunit, x, y, NULL, FlushCommands);
00527 } else {
00528 CommandMove(aiunit, x, y, FlushCommands);
00529 }
00530 }
00531 }
00532 } else {
00533
00534 unit = NULL;
00535 for (i = 0; i < (int)force->Units.size(); ++i) {
00536 aiunit = force->Units[i];
00537 if (aiunit->Type->CanAttack) {
00538 unit = AttackUnitsInDistance(aiunit, MaxMapWidth);
00539 break;
00540 }
00541 }
00542 if (!unit) {
00543
00544
00545 DebugPrint("Attack force can't find a target, giving up\n");
00546 force->Attacking = false;
00547 return;
00548 }
00549 for (i = 0; i < (int)force->Units.size(); ++i) {
00550 aiunit = force->Units[i];
00551 if (aiunit->Type->CanAttack) {
00552 CommandAttack(aiunit, unit->X, unit->Y, NULL, FlushCommands);
00553 } else {
00554 CommandMove(aiunit, unit->X, unit->Y, FlushCommands);
00555 }
00556 }
00557 }
00558 }
00559
00565 void AiForceManager(void)
00566 {
00567
00568
00569
00570 for (int force = 0; force < AI_MAX_ATTACKING_FORCES; ++force) {
00571 if (AiPlayer->Force[force].Defending) {
00572 const CUnit *aiunit;
00573 int i;
00574
00575 AiCleanForce(force);
00576
00577
00578
00579 for (i = 0; i < (int)AiPlayer->Force[force].Units.size(); ++i) {
00580 aiunit = AiPlayer->Force[force].Units[i];
00581 if (aiunit->Type->CanAttack &&
00582 AttackUnitsInReactRange(aiunit)) {
00583 break;
00584 }
00585 }
00586 if (i == (int)AiPlayer->Force[force].Units.size()) {
00587 DebugPrint("FIXME: not written, should send force home\n");
00588 AiPlayer->Force[force].Defending = false;
00589 AiPlayer->Force[force].Attacking = false;
00590 }
00591 }
00592 if (AiPlayer->Force[force].Attacking) {
00593 AiCleanForce(force);
00594 AiForceAttacks(&AiPlayer->Force[force]);
00595 }
00596 }
00597 AiAssignFreeUnitsToForce();
00598 }
00599