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
00037 #include "stratagus.h"
00038 #include "map.h"
00039 #include "unittype.h"
00040 #include "unit.h"
00041 #include "pathfinder.h"
00042
00043
00044
00045
00046
00055 static unsigned char Matrix[(MaxMapWidth + 2) * (MaxMapHeight + 3) + 2];
00056
00057 static int STDCALL CostMoveTo(int x, int y, void *data);
00058
00059
00060
00061
00062
00066 void InitPathfinder()
00067 {
00068 InitAStar(Map.Info.MapWidth, Map.Info.MapHeight, CostMoveTo);
00069 }
00070
00074 void FreePathfinder()
00075 {
00076 FreeAStar();
00077 }
00078
00090 static void InitMatrix(unsigned char *matrix)
00091 {
00092 unsigned i;
00093 unsigned w;
00094 unsigned h;
00095 unsigned e;
00096
00097 w = Map.Info.MapWidth + 2;
00098 h = Map.Info.MapHeight;
00099
00100 i = w + w + 1;
00101 memset(matrix, 98, i);
00102 memset(matrix + i, 0, w * h);
00103
00104 for (e = i + w * h; i < e;) {
00105 matrix[i] = 98;
00106 i += w;
00107 matrix[i - 1] = 98;
00108 }
00109 memset(matrix + i, 98, w + 1);
00110 }
00111
00115 unsigned char *CreateMatrix(void)
00116 {
00117 InitMatrix(Matrix);
00118 return Matrix;
00119 }
00120
00124 unsigned char *MakeMatrix(void)
00125 {
00126 unsigned char *matrix;
00127
00128 matrix = new unsigned char[(Map.Info.MapWidth + 2) * (Map.Info.MapHeight + 3) + 2];
00129 InitMatrix(matrix);
00130
00131 return matrix;
00132 }
00133
00134
00135
00136
00137
00151 int PlaceReachable(const CUnit *src, int x, int y, int w, int h, int minrange, int range)
00152 {
00153 int i = AStarFindPath(src->X, src->Y, x, y, w, h,
00154 src->Type->TileWidth, src->Type->TileHeight, minrange, range, NULL, 0, (void *)src);
00155
00156 switch (i) {
00157 case PF_FAILED:
00158 case PF_UNREACHABLE:
00159 case PF_REACHED:
00160 i = 0;
00161 break;
00162 case PF_WAIT:
00163 Assert(0);
00164 i = 0;
00165 break;
00166 case PF_MOVE:
00167 break;
00168 default:
00169 break;
00170 }
00171
00172 return i;
00173 }
00174
00184 int UnitReachable(const CUnit *src, const CUnit *dst, int range)
00185 {
00186 int depth;
00187
00188
00189
00190
00191 depth = PlaceReachable(src, dst->X, dst->Y, dst->Type->TileWidth, dst->Type->TileHeight, 0, range);
00192 if (depth <= 0) {
00193 return 0;
00194 }
00195
00196 return depth;
00197 }
00198
00210 static int STDCALL CostMoveTo(int x, int y, void *data)
00211 {
00212 int i;
00213 int j;
00214 int flag;
00215 int cost = 0;
00216 CUnit *goal;
00217 const CUnit *unit = (const CUnit *)data;
00218 int mask = unit->Type->MovementMask;
00219
00220 cost = 0;
00221
00222
00223
00224 if (unit->X == x && unit->Y == y) {
00225 return 0;
00226 }
00227
00228
00229 for (i = x; i < x + unit->Type->TileWidth; ++i) {
00230 for (j = y; j < y + unit->Type->TileHeight; ++j) {
00231 flag = Map.Field(i, j)->Flags & mask;
00232 if (flag && (AStarKnowUnseenTerrain || Map.IsFieldExplored(unit->Player, i, j))) {
00233 if (flag & ~(MapFieldLandUnit | MapFieldAirUnit | MapFieldSeaUnit)) {
00234
00235 return -1;
00236 }
00237 goal = UnitOnMapTile(i, j, unit->Type->UnitType);
00238 if (!goal) {
00239
00240 Assert(0);
00241 return -1;
00242 }
00243 if (goal->Moving) {
00244
00245 cost += AStarMovingUnitCrossingCost;
00246 } else {
00247
00248
00249 return -1;
00250
00251 }
00252 }
00253
00254 if (!AStarKnowUnseenTerrain && !Map.IsFieldExplored(unit->Player, i, j)) {
00255
00256 cost += AStarUnknownTerrainCost;
00257 }
00258
00259 cost += Map.Field(i, j)->Cost;
00260 }
00261 }
00262 return cost;
00263 }
00264
00265
00266
00267
00268
00282 int NewPath(CUnit *unit)
00283 {
00284 int i;
00285 int gw;
00286 int gh;
00287 int gx;
00288 int gy;
00289 int minrange;
00290 int maxrange;
00291 char *path;
00292
00293 if (unit->Orders[0]->Goal) {
00294 gw = unit->Orders[0]->Goal->Type->TileWidth;
00295 gh = unit->Orders[0]->Goal->Type->TileHeight;
00296 gx = unit->Orders[0]->Goal->X;
00297 gy = unit->Orders[0]->Goal->Y;
00298 maxrange = unit->Orders[0]->Range;
00299 minrange = unit->Orders[0]->MinRange;
00300 } else {
00301
00302
00303
00304 gw = unit->Orders[0]->Width;
00305 gh = unit->Orders[0]->Height;
00306 maxrange = unit->Orders[0]->Range;
00307 minrange = unit->Orders[0]->MinRange;
00308
00309 if (unit->Orders[0]->X + unit->Type->TileWidth - 1 >= Map.Info.MapWidth) {
00310 unit->Orders[0]->X = Map.Info.MapWidth - unit->Type->TileWidth;
00311 }
00312 if (unit->Orders[0]->Y + unit->Type->TileHeight - 1 >= Map.Info.MapHeight) {
00313 unit->Orders[0]->Y = Map.Info.MapHeight - unit->Type->TileHeight;
00314 }
00315 gx = unit->Orders[0]->X;
00316 gy = unit->Orders[0]->Y;
00317 }
00318 path = unit->Data.Move.Path;
00319 i = AStarFindPath(unit->X, unit->Y, gx, gy, gw, gh,
00320 unit->Type->TileWidth, unit->Type->TileHeight, minrange, maxrange, path, MAX_PATH_LENGTH, unit);
00321 if (i == PF_FAILED) {
00322 i = PF_UNREACHABLE;
00323 }
00324
00325
00326
00327
00328 if (path != NULL) {
00329 if (i >= MAX_PATH_LENGTH) {
00330 unit->Data.Move.Length = MAX_PATH_LENGTH;
00331 } else {
00332 unit->Data.Move.Length = i;
00333 }
00334 if (unit->Data.Move.Length == 0) {
00335 ++unit->Data.Move.Length;
00336 }
00337 }
00338 return i;
00339 }
00340
00351 int NextPathElement(CUnit *unit, int *pxd, int *pyd)
00352 {
00353 int result;
00354
00355
00356
00357 *pxd = 0;
00358 *pyd = 0;
00359
00360
00361 if (unit->Data.Move.Length <= 0 ||
00362 (unit->Orders[0]->Goal && (unit->Orders[0]->Goal->X != unit->Orders[0]->X ||
00363 unit->Orders[0]->Goal->Y != unit->Orders[0]->Y))) {
00364 result = NewPath(unit);
00365
00366 if (result == PF_UNREACHABLE) {
00367 unit->Data.Move.Length = 0;
00368 return result;
00369 }
00370 if (result == PF_REACHED) {
00371 return result;
00372 }
00373 if (unit->Goal) {
00374
00375 unit->Orders[0]->X = unit->Goal->X;
00376 unit->Orders[0]->Y = unit->Goal->Y;
00377 }
00378 }
00379
00380 *pxd = Heading2X[(int)unit->Data.Move.Path[(int)unit->Data.Move.Length - 1]];
00381 *pyd = Heading2Y[(int)unit->Data.Move.Path[(int)unit->Data.Move.Length - 1]];
00382 result = unit->Data.Move.Length;
00383 unit->Data.Move.Length--;
00384 if (!UnitCanBeAt(unit, *pxd + unit->X, *pyd + unit->Y)) {
00385
00386 if (unit->Data.Move.Fast) {
00387 unit->Data.Move.Fast--;
00388 AstarDebugPrint("WAIT at %d\n" _C_ unit->Data.Move.Fast);
00389 result = PF_WAIT;
00390 } else {
00391 unit->Data.Move.Fast = 10;
00392 AstarDebugPrint("SET WAIT to 10\n");
00393 result = PF_WAIT;
00394 }
00395 if (unit->Data.Move.Fast == 0 && result != 0) {
00396 AstarDebugPrint("WAIT expired\n");
00397 result = NewPath(unit);
00398 if (result > 0) {
00399 *pxd = Heading2X[(int)unit->Data.Move.Path[(int)unit->Data.Move.Length - 1]];
00400 *pyd = Heading2Y[(int)unit->Data.Move.Path[(int)unit->Data.Move.Length - 1]];
00401 if (!UnitCanBeAt(unit, *pxd + unit->X, *pyd + unit->Y)) {
00402
00403 result = PF_UNREACHABLE;
00404 *pxd = 0;
00405 *pyd = 0;
00406 } else {
00407 result = unit->Data.Move.Length;
00408 unit->Data.Move.Length--;
00409 }
00410 }
00411 }
00412 }
00413 if (result != PF_WAIT) {
00414 unit->Data.Move.Fast = 0;
00415 }
00416 return result;
00417 }
00418