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 "unittype.h"
00040 #include "player.h"
00041 #include "unit.h"
00042 #include "actions.h"
00043 #include "map.h"
00044 #include "interface.h"
00045 #include "pathfinder.h"
00046
00047
00048
00049
00050
00051
00052
00053 #define LandUnitMask ( \
00054 MapFieldLandUnit | \
00055 MapFieldBuilding | \
00056 MapFieldCoastAllowed | \
00057 MapFieldWaterAllowed | \
00058 MapFieldUnpassable)
00059
00060 #define NavalUnitMask ( \
00061 MapFieldLandUnit | \
00062 MapFieldBuilding | \
00063 MapFieldCoastAllowed | \
00064 MapFieldLandAllowed | \
00065 MapFieldUnpassable)
00066
00067
00083 static int FindUnloadPosition(int x, int y, int *resx, int *resy, int mask)
00084 {
00085 int i;
00086 int n;
00087 int addx;
00088 int addy;
00089
00090 addx = addy = 1;
00091 --x;
00092 for (n = 0; n < 2; ++n) {
00093
00094
00095 for (i = addy; i--; ++y) {
00096 if (CheckedCanMoveToMask(x, y, mask)) {
00097 *resx = x;
00098 *resy = y;
00099 return 1;
00100 }
00101 }
00102 ++addx;
00103 for (i = addx; i--; ++x) {
00104 if (CheckedCanMoveToMask(x, y, mask)) {
00105 *resx = x;
00106 *resy = y;
00107 return 1;
00108 }
00109 }
00110 ++addy;
00111 for (i = addy; i--; --y) {
00112 if (CheckedCanMoveToMask(x, y, mask)) {
00113 *resx = x;
00114 *resy = y;
00115 return 1;
00116 }
00117 }
00118 ++addx;
00119 for (i = addx; i--; --x) {
00120 if (CheckedCanMoveToMask(x, y, mask)) {
00121 *resx = x;
00122 *resy = y;
00123 return 1;
00124 }
00125 }
00126 ++addy;
00127 }
00128 return 0;
00129 }
00130
00140 int UnloadUnit(CUnit *unit)
00141 {
00142 int x;
00143 int y;
00144
00145 Assert(unit->Removed);
00146 if (!FindUnloadPosition(unit->X, unit->Y, &x, &y, unit->Type->MovementMask)) {
00147 return 0;
00148 }
00149 unit->Boarded = 0;
00150 unit->Place(x, y);
00151 return 1;
00152 }
00153
00164 static int ClosestFreeCoast(int x, int y, int *resx, int *resy)
00165 {
00166 int i;
00167 int addx;
00168 int addy;
00169 int nullx;
00170 int nully;
00171 int n;
00172
00173 addx = addy = 1;
00174 if (Map.CoastOnMap(x, y) &&
00175 FindUnloadPosition(x, y, &nullx, &nully, LandUnitMask)) {
00176 *resx = x;
00177 *resy = y;
00178 return 1;
00179 }
00180 --x;
00181
00182 n = 20;
00183 while (n--) {
00184 for (i = addy; i--; ++y) {
00185 if (x >= 0 && y >= 0 && x < Map.Info.MapWidth && y < Map.Info.MapHeight &&
00186 Map.CoastOnMap(x, y) && !UnitOnMapTile(x, y) &&
00187 FindUnloadPosition(x, y, &nullx, &nully, LandUnitMask)) {
00188 *resx = x;
00189 *resy = y;
00190 return 1;
00191 }
00192 }
00193 ++addx;
00194 for (i = addx; i--; ++x) {
00195 if (x >= 0 && y >= 0 && x < Map.Info.MapWidth && y < Map.Info.MapHeight &&
00196 Map.CoastOnMap(x, y) && !UnitOnMapTile(x ,y) &&
00197 FindUnloadPosition(x, y, &nullx, &nully, LandUnitMask)) {
00198 *resx = x;
00199 *resy = y;
00200 return 1;
00201 }
00202 }
00203 ++addy;
00204 for (i = addy; i--; --y) {
00205 if (x >= 0 && y >= 0 && x < Map.Info.MapWidth && y < Map.Info.MapHeight &&
00206 Map.CoastOnMap(x, y) && !UnitOnMapTile(x, y) &&
00207 FindUnloadPosition(x, y, &nullx, &nully, LandUnitMask)) {
00208 *resx = x;
00209 *resy = y;
00210 return 1;
00211 }
00212 }
00213 ++addx;
00214 for (i = addx; i--; --x) {
00215 if (x >= 0 && y >= 0 && x < Map.Info.MapWidth && y < Map.Info.MapHeight &&
00216 Map.CoastOnMap(x, y) && !UnitOnMapTile(x, y) &&
00217 FindUnloadPosition(x, y, &nullx, &nully, LandUnitMask)) {
00218 *resx = x;
00219 *resy = y;
00220 return 1;
00221 }
00222 }
00223 ++addy;
00224 }
00225 DebugPrint("Try clicking closer to an actual coast.\n");
00226 return 0;
00227 }
00228
00242 static int ClosestFreeDropZone(CUnit *transporter, int x, int y, int *resx, int *resy)
00243 {
00244
00245 int transporterType;
00246
00247 int loadedType;
00248
00249
00250 if (!transporter->UnitInside) {
00251 return 0;
00252 }
00253
00254 transporterType = transporter->Type->UnitType;
00255
00256 loadedType = transporter->UnitInside->Type->UnitType;
00257
00258
00259 if ((transporterType == loadedType) || (loadedType == UnitTypeFly)) {
00260 *resx = x;
00261 *resy = y;
00262 return 1;
00263 }
00264
00265 switch (transporterType) {
00266 case UnitTypeLand:
00267
00268 return ClosestFreeCoast(x, y, resx, resy);
00269 case UnitTypeNaval:
00270
00271 return ClosestFreeCoast(x, y, resx, resy);
00272 case UnitTypeFly:
00273
00274 if (loadedType == UnitTypeLand) {
00275 return FindUnloadPosition(x, y, resx, resy, LandUnitMask);
00276 } else {
00277 return FindUnloadPosition(x, y, resx, resy, NavalUnitMask);
00278 }
00279 }
00280
00281 return 0;
00282 }
00283
00291 static int MoveToDropZone(CUnit *unit)
00292 {
00293 switch (DoActionMove(unit)) {
00294 case PF_UNREACHABLE:
00295 return -1;
00296 case PF_REACHED:
00297 break;
00298 default:
00299 return 0;
00300 }
00301
00302 Assert(unit->Orders[0]->Action == UnitActionUnload);
00303 return 1;
00304 }
00305
00311 static void LeaveTransporter(CUnit *unit)
00312 {
00313 int i;
00314 int stillonboard;
00315 CUnit *goal;
00316
00317 stillonboard = 0;
00318 goal = unit->Orders[0]->Goal;
00319
00320
00321
00322
00323 if (goal) {
00324 unit->Orders[0]->Goal = NoUnitP;
00325 if (goal->Destroyed) {
00326 DebugPrint("destroyed unit unloading?\n");
00327 goal->RefsDecrease();
00328 return;
00329 }
00330 goal->RefsDecrease();
00331 goal->X = unit->X;
00332 goal->Y = unit->Y;
00333
00334 if (UnloadUnit(goal)) {
00335 unit->BoardCount--;
00336 }
00337 } else {
00338
00339 goal = unit->UnitInside;
00340 for (i = unit->InsideCount; i; --i, goal = goal->NextContained) {
00341 if (goal->Boarded) {
00342 goal->X = unit->X;
00343 goal->Y = unit->Y;
00344 if (!UnloadUnit(goal)) {
00345 ++stillonboard;
00346 } else {
00347 unit->BoardCount--;
00348 }
00349 }
00350 }
00351 }
00352 if (IsOnlySelected(unit)) {
00353 SelectedUnitChanged();
00354 }
00355
00356
00357 if (stillonboard) {
00358
00359
00360 unit->Orders[0]->Action = UnitActionUnload;
00361 unit->Orders[0]->Goal = NoUnitP;
00362 unit->Orders[0]->X = unit->X;
00363 unit->Orders[0]->Y = unit->Y;
00364 unit->SubAction = 0;
00365 } else {
00366 unit->ClearAction();
00367 }
00368 }
00369
00375 void HandleActionUnload(CUnit *unit)
00376 {
00377 int i;
00378 int x;
00379 int y;
00380
00381 if (!CanMove(unit)) {
00382 unit->SubAction = 2;
00383 }
00384 switch (unit->SubAction) {
00385
00386
00387
00388 case 0:
00389 if (!unit->Orders[0]->Goal) {
00390 if (!ClosestFreeDropZone(unit, unit->Orders[0]->X, unit->Orders[0]->Y,
00391 &x, &y)) {
00392
00393 unit->ClearAction();
00394 return;
00395 }
00396 unit->Orders[0]->X = x;
00397 unit->Orders[0]->Y = y;
00398 }
00399
00400 NewResetPath(unit);
00401 unit->SubAction = 1;
00402 case 1:
00403
00404 if (!unit->Orders[0]->Goal) {
00405
00406 if ((i = MoveToDropZone(unit))) {
00407 if (i == PF_REACHED) {
00408 if (++unit->SubAction == 1) {
00409 unit->ClearAction();
00410 }
00411 } else {
00412 unit->SubAction = 2;
00413 }
00414 }
00415 break;
00416 }
00417
00418
00419
00420 case 2:
00421
00422 LeaveTransporter(unit);
00423 if (CanMove(unit) && unit->Orders[0]->Action != UnitActionStill) {
00424 HandleActionUnload(unit);
00425 }
00426 break;
00427 }
00428 }
00429