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
00038 #include "stratagus.h"
00039 #include "unit.h"
00040 #include "unittype.h"
00041 #include "map.h"
00042 #include "pathfinder.h"
00043 #include "ai_local.h"
00044 #include "player.h"
00045
00046
00047
00048
00049
00050
00051
00052
00053
00069 static int AiCheckSurrounding(const CUnit *worker, const CUnitType *type, int x, int y, bool &backupok)
00070 {
00071 static int dirs[5][2] = {{1,0},{0,1},{-1,0},{0,-1},{0,0}};
00072 int surrounding[1024];
00073 int surroundingnb;
00074 int x0, y0, x1, y1;
00075 int i;
00076 int lastval;
00077 int dir;
00078 int obstacle;
00079
00080 x0 = x - 1;
00081 y0 = y - 1;
00082 x1 = x0 + type->TileWidth + 1;
00083 y1 = y0 + type->TileWidth + 1;
00084
00085
00086 x = x0;
00087 y = y0;
00088 dir = -1;
00089 surroundingnb = 0;
00090 while (dir < 4) {
00091 if ((unsigned)x < (unsigned)Map.Info.MapWidth && (unsigned)y < (unsigned)Map.Info.MapHeight) {
00092 if (worker && x == worker->X && y == worker->Y) {
00093 surrounding[surroundingnb++] = 1;
00094 } else if (Map.Field(x, y)->Flags & (MapFieldUnpassable | MapFieldBuilding)) {
00095 surrounding[surroundingnb++] = 0;
00096 } else{
00097
00098 surrounding[surroundingnb++] = (Map.Field(x, y)->Flags &
00099 (MapFieldWaterAllowed + MapFieldCoastAllowed + MapFieldLandAllowed)) != 0;;
00100 }
00101 } else {
00102 surrounding[surroundingnb++] = 0;
00103 }
00104
00105 if ((x == x0 || x == x1) && (y == y0 || y == y1)) {
00106 dir++;
00107 }
00108
00109 x += dirs[dir][0];
00110 y += dirs[dir][1];
00111 }
00112
00113 lastval = surrounding[surroundingnb - 1];
00114 obstacle = 0;
00115 for (i = 0 ; i < surroundingnb; ++i) {
00116 if (lastval && !surrounding[i]) {
00117 ++obstacle;
00118 }
00119 lastval = surrounding[i];
00120 }
00121
00122 if (obstacle == 0) {
00123 obstacle = !surrounding[0];
00124 }
00125
00126 if (!type->ShoreBuilding) {
00127 backupok = obstacle < 5;
00128 } else {
00129
00130 backupok = obstacle < 3;
00131 }
00132 return obstacle == 0;
00133 }
00134
00147 static int AiFindBuildingPlace2(const CUnit *worker, const CUnitType *type,
00148 int ox, int oy, int *dx, int *dy)
00149 {
00150 static const int xoffset[] = { 0, -1, +1, 0, -1, +1, -1, +1 };
00151 static const int yoffset[] = { -1, 0, 0, +1, -1, -1, +1, +1 };
00152 struct p {
00153 unsigned short X;
00154 unsigned short Y;
00155 } *points;
00156 int size;
00157 int x;
00158 int y;
00159 int rx;
00160 int ry;
00161 int mask;
00162 int wp;
00163 int rp;
00164 int ep;
00165 int i;
00166 int w;
00167 unsigned char *m;
00168 unsigned char *matrix;
00169 int backupx = -1;
00170 int backupy = -1;
00171 bool backupok;
00172
00173 size = Map.Info.MapWidth * Map.Info.MapHeight / 4;
00174 points = new p[size];
00175
00176 x = ox;
00177 y = oy;
00178
00179
00180
00181 if (CanBuildUnitType(worker, type, x, y, 1)) {
00182 if (AiCheckSurrounding(worker, type, x, y, backupok)) {
00183 *dx = x;
00184 *dy = y;
00185 delete[] points;
00186 return 1;
00187 } else if (backupok) {
00188 backupx = x;
00189 backupy = y;
00190 }
00191 }
00192
00193
00194
00195 matrix = CreateMatrix();
00196 w = Map.Info.MapWidth + 2;
00197
00198 mask = worker->Type->MovementMask;
00199
00200 mask &= ~(MapFieldLandUnit | MapFieldAirUnit | MapFieldSeaUnit);
00201
00202 points[0].X = x;
00203 points[0].Y = y;
00204
00205 if ((type->TileWidth > 1 || type->TileHeight > 1) &&
00206 x + type->TileWidth - 1 < Map.Info.MapWidth &&
00207 y + type->TileHeight - 1 < Map.Info.MapHeight) {
00208 points[1].X = x + type->TileWidth - 1;
00209 points[1].Y = y + type->TileHeight - 1;
00210 ep = wp = 2;
00211 } else {
00212 ep = wp = 1;
00213 }
00214 matrix += w + w + 2;
00215 rp = 0;
00216 matrix[x + y * w] = 1;
00217
00218
00219
00220
00221 for (;;) {
00222 while (rp != ep) {
00223 rx = points[rp].X;
00224 ry = points[rp].Y;
00225 for (i = 0; i < 8; ++i) {
00226 x = rx + xoffset[i];
00227 y = ry + yoffset[i];
00228 m = matrix + x + y * w;
00229 if (*m) {
00230 continue;
00231 }
00232
00233
00234
00235
00236 if (CanBuildUnitType(worker, type, x, y, 1) &&
00237 !AiEnemyUnitsInDistance(worker->Player, NULL, x, y, 8)) {
00238 if (AiCheckSurrounding(worker, type, x, y, backupok)) {
00239 *dx = x;
00240 *dy = y;
00241 delete[] points;
00242 return 1;
00243 } else if (backupok && backupx == -1) {
00244 backupx = x;
00245 backupy = y;
00246 }
00247 }
00248
00249 if (CanMoveToMask(x, y, mask)) {
00250 *m = 1;
00251 points[wp].X = x;
00252 points[wp].Y = y;
00253 if (++wp >= size) {
00254 wp = 0;
00255 }
00256 } else {
00257 *m = 99;
00258 }
00259 }
00260
00261 if (++rp >= size) {
00262 rp = 0;
00263 }
00264 }
00265
00266
00267
00268
00269 if (rp == wp) {
00270 break;
00271 }
00272 ep = wp;
00273 }
00274
00275 delete[] points;
00276
00277 if (backupx != -1) {
00278 *dx = backupx;
00279 *dy = backupy;
00280 return 1;
00281 }
00282 return 0;
00283 }
00284
00298 int AiFindBuildingPlace(const CUnit *worker, const CUnitType *type, int *dx, int *dy)
00299 {
00300 DebugPrint("Want to build a %s(%s)\n" _C_ type->Ident.c_str() _C_ type->Name.c_str());
00301
00302 return AiFindBuildingPlace2(worker, type, worker->X, worker->Y, dx, dy);
00303 }
00304