Fix some action with big units (TileSize > (1;1))
Fix regression whan AI should attack with transporter.
This commit is contained in:
parent
de0530e856
commit
2a313e217b
14 changed files with 275 additions and 305 deletions
|
@ -500,7 +500,7 @@ void HandleActionBuilt(CUnit &unit)
|
|||
unit.Data.Built.Worker = NoUnitP;
|
||||
// HACK: make sure the sight is updated correctly
|
||||
unit.CurrentSightRange = 1;
|
||||
DropOutOnSide(*worker, LookingW, type->TileWidth, type->TileHeight);
|
||||
DropOutOnSide(*worker, LookingW, &unit);
|
||||
unit.CurrentSightRange = 0;
|
||||
}
|
||||
|
||||
|
@ -544,7 +544,7 @@ void HandleActionBuilt(CUnit &unit)
|
|||
worker->SubAction = 0;//may be 40
|
||||
// HACK: make sure the sight is updated correctly
|
||||
unit.CurrentSightRange = 1;
|
||||
DropOutOnSide(*worker, LookingW, type->TileWidth, type->TileHeight);
|
||||
DropOutOnSide(*worker, LookingW, &unit);
|
||||
|
||||
worker->CurrentOrder()->ClearGoal();
|
||||
|
||||
|
|
|
@ -55,9 +55,7 @@
|
|||
*/
|
||||
void HandleActionDie(CUnit &unit)
|
||||
{
|
||||
//
|
||||
// Show death animation
|
||||
//
|
||||
if (unit.Type->Animations && unit.Type->Animations->Death[unit.DamagedType]) {
|
||||
UnitShowAnimation(unit, unit.Type->Animations->Death[unit.DamagedType]);
|
||||
}
|
||||
|
@ -68,43 +66,41 @@ void HandleActionDie(CUnit &unit)
|
|||
unit.Anim.Unbreakable = 0;
|
||||
}
|
||||
|
||||
//
|
||||
if (unit.Anim.Unbreakable) {
|
||||
return;
|
||||
}
|
||||
// Die sequence terminated, generate corpse.
|
||||
//
|
||||
if (!unit.Anim.Unbreakable) {
|
||||
if (!unit.Type->CorpseType) {
|
||||
// We may be in the cache if we just finished out death animation
|
||||
// even though there is no corpse.
|
||||
// (unit.Type->Animations && unit.Type->Animations->Death)
|
||||
// Remove us from the map to be safe
|
||||
unit.Remove(NULL);
|
||||
unit.Release();
|
||||
return;
|
||||
}
|
||||
if (!unit.Type->CorpseType) {
|
||||
// We may be in the cache if we just finished out death animation
|
||||
// even though there is no corpse.
|
||||
// (unit.Type->Animations && unit.Type->Animations->Death)
|
||||
// Remove us from the map to be safe
|
||||
unit.Remove(NULL);
|
||||
unit.Release();
|
||||
return;
|
||||
}
|
||||
|
||||
Assert(unit.Type->TileWidth == unit.Type->CorpseType->TileWidth &&
|
||||
unit.Type->TileHeight == unit.Type->CorpseType->TileHeight);
|
||||
Assert(unit.Type->TileWidth >= unit.Type->CorpseType->TileWidth &&
|
||||
unit.Type->TileHeight >= unit.Type->CorpseType->TileHeight);
|
||||
|
||||
// Update sight for new corpse
|
||||
// We have to unmark BEFORE changing the type.
|
||||
// Always do that, since types can have different vision properties.
|
||||
MapUnmarkUnitGuard(unit);
|
||||
MapUnmarkUnitSight(unit);
|
||||
unit.Type = unit.Type->CorpseType;
|
||||
unit.CurrentSightRange =
|
||||
unit.Type->Stats[unit.Player->Index].Variables[SIGHTRANGE_INDEX].Max;
|
||||
MapMarkUnitSight(unit);
|
||||
// Update sight for new corpse
|
||||
// We have to unmark BEFORE changing the type.
|
||||
// Always do that, since types can have different vision properties.
|
||||
|
||||
// We must be dead to get here, it we aren't we need to know why
|
||||
// This assert replaces and old DEBUG message "Reset to die is really needed"
|
||||
Assert(unit.CurrentAction() == UnitActionDie);
|
||||
unit.Remove(NULL);
|
||||
unit.Type = unit.Type->CorpseType;
|
||||
unit.Stats = &unit.Type->Stats[unit.Player->Index];
|
||||
unit.Place(unit.tilePos);
|
||||
|
||||
unit.SubAction = 0;
|
||||
unit.Frame = 0;
|
||||
UnitUpdateHeading(unit);
|
||||
if (unit.Type->Animations && unit.Type->Animations->Death[ANIMATIONS_DEATHTYPES]) {
|
||||
UnitShowAnimation(unit, unit.Type->Animations->Death[ANIMATIONS_DEATHTYPES]);
|
||||
}
|
||||
// We must be dead to get here, it we aren't we need to know why
|
||||
// This assert replaces and old DEBUG message "Reset to die is really needed"
|
||||
Assert(unit.CurrentAction() == UnitActionDie);
|
||||
|
||||
unit.SubAction = 0;
|
||||
unit.Frame = 0;
|
||||
UnitUpdateHeading(unit);
|
||||
if (unit.Type->Animations && unit.Type->Animations->Death[ANIMATIONS_DEATHTYPES]) {
|
||||
UnitShowAnimation(unit, unit.Type->Animations->Death[ANIMATIONS_DEATHTYPES]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -132,7 +132,7 @@ void HandleActionFollow(CUnit &unit)
|
|||
// Teleport the unit
|
||||
unit.Remove(NULL);
|
||||
unit.tilePos = goal->Goal->tilePos;
|
||||
DropOutOnSide(unit, unit.Direction, 1, 1);
|
||||
DropOutOnSide(unit, unit.Direction, NULL);
|
||||
#if 0
|
||||
// FIXME: SoundForName() should be called once
|
||||
PlayGameSound(SoundForName("invisibility"), MaxSampleVolume);
|
||||
|
|
|
@ -275,7 +275,7 @@ static void LoseResource(CUnit &unit, const CUnit &source)
|
|||
CUnit *depot;
|
||||
ResourceInfo *resinfo = unit.Type->ResInfo[unit.CurrentResource];
|
||||
|
||||
Assert((unit.Container && !resinfo->HarvestFromOutside) ||
|
||||
Assert((unit.Container == &source && !resinfo->HarvestFromOutside) ||
|
||||
(!unit.Container && resinfo->HarvestFromOutside));
|
||||
|
||||
if (resinfo->HarvestFromOutside) {
|
||||
|
@ -287,8 +287,7 @@ static void LoseResource(CUnit &unit, const CUnit &source)
|
|||
//
|
||||
if (unit.ResourcesHeld && (depot = FindDeposit(unit, 1000, unit.CurrentResource))) {
|
||||
if (unit.Container) {
|
||||
DropOutNearest(unit, depot->tilePos + depot->Type->GetHalfTileSize(),
|
||||
source.Type->TileWidth, source.Type->TileHeight);
|
||||
DropOutNearest(unit, depot->tilePos + depot->Type->GetHalfTileSize(), &source);
|
||||
}
|
||||
//
|
||||
// Remember were it mined, so it can look around for another resource.
|
||||
|
@ -306,8 +305,7 @@ static void LoseResource(CUnit &unit, const CUnit &source)
|
|||
//
|
||||
if (unit.Container) {
|
||||
Assert(!resinfo->HarvestFromOutside);
|
||||
DropOutOnSide(unit, LookingW, source.Type->TileWidth,
|
||||
source.Type->TileHeight);
|
||||
DropOutOnSide(unit, LookingW, &source);
|
||||
}
|
||||
unit.CurrentOrder()->goalPos.x = unit.CurrentOrder()->goalPos.y = -1;
|
||||
//use depot as goal
|
||||
|
@ -593,8 +591,7 @@ static int StopGathering(CUnit &unit)
|
|||
!unit.ResourcesHeld) {
|
||||
if (!(resinfo->HarvestFromOutside || resinfo->TerrainHarvester)) {
|
||||
Assert(unit.Container);
|
||||
DropOutOnSide(unit, LookingW, source->Type->TileWidth,
|
||||
source->Type->TileHeight);
|
||||
DropOutOnSide(unit, LookingW, source);
|
||||
}
|
||||
DebugPrint("%d: Worker %d report: Can't find a resource [%d] deposit.\n"
|
||||
_C_ unit.Player->Index _C_ unit.Slot _C_ unit.CurrentResource);
|
||||
|
@ -605,8 +602,7 @@ static int StopGathering(CUnit &unit)
|
|||
} else {
|
||||
if (!(resinfo->HarvestFromOutside || resinfo->TerrainHarvester)) {
|
||||
Assert(unit.Container);
|
||||
DropOutNearest(unit, depot->tilePos + depot->Type->GetHalfTileSize(),
|
||||
source->Type->TileWidth, source->Type->TileHeight);
|
||||
DropOutNearest(unit, depot->tilePos + depot->Type->GetHalfTileSize(), source);
|
||||
}
|
||||
UnitGotoGoal(unit, depot, SUB_MOVE_TO_DEPOT);
|
||||
}
|
||||
|
@ -733,14 +729,14 @@ static int WaitInDepot(CUnit &unit)
|
|||
pos = unit.CurrentOrder()->Arg1.Resource.Pos;
|
||||
|
||||
if (FindTerrainType(unit.Type->MovementMask, MapFieldForest, 0, 10, unit.Player, pos, &pos)) {
|
||||
if(depot)
|
||||
DropOutNearest(unit, pos, depot->Type->TileWidth,
|
||||
depot->Type->TileHeight);
|
||||
if (depot) {
|
||||
DropOutNearest(unit, pos, depot);
|
||||
}
|
||||
unit.CurrentOrder()->goalPos = pos;
|
||||
} else {
|
||||
if(depot)
|
||||
DropOutOnSide(unit, LookingW, depot->Type->TileWidth,
|
||||
depot->Type->TileHeight);
|
||||
if (depot) {
|
||||
DropOutOnSide(unit, LookingW, depot);
|
||||
}
|
||||
unit.ClearAction();
|
||||
}
|
||||
} else {
|
||||
|
@ -752,12 +748,12 @@ static int WaitInDepot(CUnit &unit)
|
|||
goal = UnitFindResource(unit, pos.x, pos.y, range,
|
||||
unit.CurrentResource, unit.Player->AiEnabled, depot);
|
||||
if (goal) {
|
||||
if(depot)
|
||||
DropOutNearest(unit, goal->tilePos + goal->Type->GetHalfTileSize(),
|
||||
depot->Type->TileWidth, depot->Type->TileHeight);
|
||||
if (depot) {
|
||||
DropOutNearest(unit, goal->tilePos + goal->Type->GetHalfTileSize(), depot);
|
||||
}
|
||||
|
||||
if(goal != mine) {
|
||||
if(mine) {
|
||||
if (goal != mine) {
|
||||
if (mine) {
|
||||
unit.DeAssignWorkerFromMine(*mine);
|
||||
mine->RefsDecrease();
|
||||
}
|
||||
|
@ -774,20 +770,17 @@ static int WaitInDepot(CUnit &unit)
|
|||
_C_ unit.Player->Index _C_ unit.Slot
|
||||
_C_ unit.tilePos.x _C_ unit.tilePos.y
|
||||
_C_ pos.x _C_ pos.y _C_ range);
|
||||
if(depot)
|
||||
DropOutOnSide(unit,
|
||||
LookingW, depot->Type->TileWidth, depot->Type->TileHeight);
|
||||
|
||||
if(mine) {
|
||||
if (depot) {
|
||||
DropOutOnSide(unit, LookingW, depot);
|
||||
}
|
||||
if (mine) {
|
||||
unit.DeAssignWorkerFromMine(*mine);
|
||||
mine->RefsDecrease();
|
||||
unit.CurrentOrder()->Arg1.Resource.Mine = NULL;
|
||||
}
|
||||
|
||||
unit.ClearAction();
|
||||
}
|
||||
}
|
||||
|
||||
return unit.CurrentAction() != UnitActionStill;
|
||||
}
|
||||
|
||||
|
|
|
@ -161,7 +161,7 @@ void HandleActionTrain(CUnit &unit)
|
|||
AddToGroup(&nunit, 1, num);
|
||||
}
|
||||
|
||||
DropOutOnSide(*nunit, LookingW, type->TileWidth, type->TileHeight);
|
||||
DropOutOnSide(*nunit, LookingW, &unit);
|
||||
|
||||
// Set life span
|
||||
if (type->DecayRate) {
|
||||
|
|
|
@ -49,84 +49,64 @@
|
|||
-- Functions
|
||||
----------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
// Flag for searching a valid tileset for unloading
|
||||
#define LandUnitMask ( \
|
||||
MapFieldLandUnit | \
|
||||
MapFieldBuilding | \
|
||||
MapFieldWall | \
|
||||
MapFieldRocks | \
|
||||
MapFieldForest | \
|
||||
MapFieldCoastAllowed | \
|
||||
MapFieldWaterAllowed | \
|
||||
MapFieldUnpassable)
|
||||
|
||||
#define NavalUnitMask ( \
|
||||
MapFieldLandUnit | \
|
||||
MapFieldBuilding | \
|
||||
MapFieldWall | \
|
||||
MapFieldRocks | \
|
||||
MapFieldForest | \
|
||||
MapFieldCoastAllowed | \
|
||||
MapFieldLandAllowed | \
|
||||
MapFieldUnpassable)
|
||||
|
||||
|
||||
/**
|
||||
** Find a free position close to startPos
|
||||
**
|
||||
** @param transporter
|
||||
** @param unit Unit to unload.
|
||||
** @param startPos Original search position
|
||||
** @param res Unload position.
|
||||
** @param mask Movement mask for the unit to be droped.
|
||||
** @param maxrange maximal range to unload.
|
||||
** @param res Unload position.
|
||||
**
|
||||
** @return True if a position was found, False otherwise.
|
||||
** @note resx and resy are undefined if a position is not found.
|
||||
** @note res is undefined if a position is not found.
|
||||
**
|
||||
** @bug FIXME: Place unit only on fields reachable from the transporter
|
||||
** @bug FIXME: This function fails for units larger than 1x1.
|
||||
*/
|
||||
static int FindUnloadPosition(const Vec2i startPos, Vec2i *res, int mask)
|
||||
static bool FindUnloadPosition(const CUnit &transporter, const CUnit &unit, const Vec2i startPos, int maxRange, Vec2i *res)
|
||||
{
|
||||
int i;
|
||||
int n;
|
||||
int addx;
|
||||
int addy;
|
||||
Vec2i pos = startPos;
|
||||
addx = addy = 1;
|
||||
|
||||
pos.x -= unit.Type->TileWidth - 1;
|
||||
pos.y -= unit.Type->TileHeight - 1;
|
||||
int addx = transporter.Type->TileWidth + unit.Type->TileWidth - 1;
|
||||
int addy = transporter.Type->TileHeight + unit.Type->TileHeight - 1;
|
||||
|
||||
--pos.x;
|
||||
for (n = 0; n < 2; ++n) {
|
||||
// Nobody: There was some code here to check for unloading units that can
|
||||
// only go on even tiles. It's useless, since we can only unload land units.
|
||||
for (i = addy; i--; ++pos.y) {
|
||||
if (CheckedCanMoveToMask(pos, mask)) {
|
||||
for (int range = 0; range < maxRange; ++range) {
|
||||
for (int i = addy; i--; ++pos.y) {
|
||||
if (UnitCanBeAt(unit, pos)) {
|
||||
*res = pos;
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
++addx;
|
||||
for (i = addx; i--; ++pos.x) {
|
||||
if (CheckedCanMoveToMask(pos, mask)) {
|
||||
|
||||
for (int i = addx; i--; ++pos.x) {
|
||||
if (UnitCanBeAt(unit, pos)) {
|
||||
*res = pos;
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
++addy;
|
||||
for (i = addy; i--; --pos.y) {
|
||||
if (CheckedCanMoveToMask(pos, mask)) {
|
||||
|
||||
for (int i = addy; i--; --pos.y) {
|
||||
if (UnitCanBeAt(unit, pos)) {
|
||||
*res = pos;
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
++addx;
|
||||
for (i = addx; i--; --pos.x) {
|
||||
if (CheckedCanMoveToMask(pos, mask)) {
|
||||
|
||||
for (int i = addx; i--; --pos.x) {
|
||||
if (UnitCanBeAt(unit, pos)) {
|
||||
*res = pos;
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
++addy;
|
||||
}
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -138,12 +118,13 @@ static int FindUnloadPosition(const Vec2i startPos, Vec2i *res, int mask)
|
|||
**
|
||||
** @bug FIXME: Place unit only on fields reachable from the transporter
|
||||
*/
|
||||
int UnloadUnit(CUnit &unit)
|
||||
static int UnloadUnit(CUnit &transporter, CUnit &unit)
|
||||
{
|
||||
const int maxRange = 1;
|
||||
Vec2i pos;
|
||||
|
||||
Assert(unit.Removed);
|
||||
if (!FindUnloadPosition(unit.tilePos, &pos, unit.Type->MovementMask)) {
|
||||
if (!FindUnloadPosition(transporter, unit, transporter.tilePos, maxRange, &pos)) {
|
||||
return 0;
|
||||
}
|
||||
unit.Boarded = 0;
|
||||
|
@ -152,72 +133,80 @@ int UnloadUnit(CUnit &unit)
|
|||
}
|
||||
|
||||
/**
|
||||
** Find the closest piece of coast you can unload units on
|
||||
** Return true is possition is a correct place to drop out units.
|
||||
**
|
||||
** @param x start location for the search
|
||||
** @param y start location for the search
|
||||
** @param resPos coast position
|
||||
**
|
||||
** @return 1 if a location was found, 0 otherwise
|
||||
** @param transporter Transporter unit.
|
||||
** @param pos position to drop out units.
|
||||
*/
|
||||
static int ClosestFreeCoast(const Vec2i &startPos, Vec2i *resPos)
|
||||
static bool IsDropZonePossible(const CUnit &transporter, const Vec2i &pos)
|
||||
{
|
||||
int i;
|
||||
int addx;
|
||||
int addy;
|
||||
Vec2i nullpos;
|
||||
Vec2i pos = startPos;
|
||||
int n;
|
||||
const int maxUnloadRange = 1;
|
||||
|
||||
addx = addy = 1;
|
||||
if (Map.CoastOnMap(pos) &&
|
||||
FindUnloadPosition(pos, &nullpos, LandUnitMask)) {
|
||||
*resPos = pos;
|
||||
return 1;
|
||||
if (!UnitCanBeAt(transporter, pos)) {
|
||||
return false;
|
||||
}
|
||||
--pos.x;
|
||||
// The maximum distance to the coast. We have to stop somewhere...
|
||||
n = 20;
|
||||
while (n--) {
|
||||
for (i = addy; i--; ++pos.y) {
|
||||
if (Map.Info.IsPointOnMap(pos) &&
|
||||
Map.CoastOnMap(pos) && !UnitOnMapTile(pos, -1) &&
|
||||
FindUnloadPosition(pos, &nullpos, LandUnitMask)) {
|
||||
Vec2i dummyPos;
|
||||
CUnit* unit = transporter.UnitInside;
|
||||
for (int i = 0; i < transporter.InsideCount; ++i, unit = unit->NextContained) {
|
||||
if (FindUnloadPosition(transporter, *unit, pos, maxUnloadRange, &dummyPos)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Check unit can be droped from here.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
** Find the closest available drop zone for a transporter.
|
||||
** Fail if transporter don't transport any unit..
|
||||
**
|
||||
** @param transporter the transporter
|
||||
** @param startPos start location for the search
|
||||
** @param maxRange The maximum distance from initial position to search...
|
||||
** @param resPos drop zone position
|
||||
**
|
||||
** @return true if a location was found, false otherwise
|
||||
** @note to be called only from ClosestFreeDropZone.
|
||||
*/
|
||||
static bool ClosestFreeDropZone_internal(const CUnit &transporter, const Vec2i &startPos, int maxRange, Vec2i *resPos)
|
||||
{
|
||||
int addx = 0;
|
||||
int addy = 1;
|
||||
Vec2i pos = startPos;
|
||||
|
||||
for (int range = 0; range < maxRange; ++range) {
|
||||
for (int i = addy; i--; ++pos.y) {
|
||||
if (IsDropZonePossible(transporter, pos)) {
|
||||
*resPos = pos;
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
++addx;
|
||||
for (i = addx; i--; ++pos.x) {
|
||||
if (Map.Info.IsPointOnMap(pos) &&
|
||||
Map.CoastOnMap(pos) && !UnitOnMapTile(pos, -1) &&
|
||||
FindUnloadPosition(pos, &nullpos, LandUnitMask)) {
|
||||
for (int i = addx; i--; ++pos.x) {
|
||||
if (IsDropZonePossible(transporter, pos)) {
|
||||
*resPos = pos;
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
++addy;
|
||||
for (i = addy; i--; --pos.y) {
|
||||
if (Map.Info.IsPointOnMap(pos) &&
|
||||
Map.CoastOnMap(pos) && !UnitOnMapTile(pos, -1) &&
|
||||
FindUnloadPosition(pos, &nullpos, LandUnitMask)) {
|
||||
for (int i = addy; i--; --pos.y) {
|
||||
if (IsDropZonePossible(transporter, pos)) {
|
||||
*resPos = pos;
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
++addx;
|
||||
for (i = addx; i--; --pos.x) {
|
||||
if (Map.Info.IsPointOnMap(pos) &&
|
||||
Map.CoastOnMap(pos) && !UnitOnMapTile(pos, -1) &&
|
||||
FindUnloadPosition(pos, &nullpos, LandUnitMask)) {
|
||||
for (int i = addx; i--; --pos.x) {
|
||||
if (IsDropZonePossible(transporter, pos)) {
|
||||
*resPos = pos;
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
++addy;
|
||||
}
|
||||
DebugPrint("Try clicking closer to an actual coast.\n");
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -226,52 +215,31 @@ static int ClosestFreeCoast(const Vec2i &startPos, Vec2i *resPos)
|
|||
**
|
||||
** @param transporter the transporter
|
||||
** @param startPos start location for the search
|
||||
** @param resPos coast position
|
||||
** @param maxRange The maximum distance from initial position to search...
|
||||
** @param resPos drop zone position
|
||||
**
|
||||
** @return 1 if a location was found, 0 otherwise
|
||||
**
|
||||
*/
|
||||
static int ClosestFreeDropZone(CUnit &transporter, const Vec2i& startPos, Vec2i *resPos)
|
||||
static int ClosestFreeDropZone(CUnit &transporter, const Vec2i &startPos, int maxRange, Vec2i *resPos)
|
||||
{
|
||||
// Type (land/fly/naval) of the transporter
|
||||
int transporterType;
|
||||
// Type (land/fly/naval) of the units to unload
|
||||
int loadedType;
|
||||
|
||||
// Check there are units onboard
|
||||
if (!transporter.UnitInside) {
|
||||
return 0;
|
||||
}
|
||||
const bool isTransporterRemoved = transporter.Removed;
|
||||
|
||||
transporterType = transporter.Type->UnitType;
|
||||
// Take the type of the onboard unit
|
||||
loadedType = transporter.UnitInside->Type->UnitType;
|
||||
|
||||
// Don't move in thoses cases
|
||||
if ((transporterType == loadedType) || (loadedType == UnitTypeFly)) {
|
||||
*resPos = startPos;
|
||||
return 1;
|
||||
if (!isTransporterRemoved) {
|
||||
// Remove transporter to avoid "collision" with itself.
|
||||
transporter.Remove(NULL);
|
||||
}
|
||||
|
||||
switch (transporterType) {
|
||||
case UnitTypeLand:
|
||||
// in this case, loadedType == UnitTypeSea
|
||||
return ClosestFreeCoast(startPos, resPos);
|
||||
case UnitTypeNaval:
|
||||
// Same ( but reversed... )
|
||||
return ClosestFreeCoast(startPos, resPos);
|
||||
case UnitTypeFly:
|
||||
// Here we have loadedType in [ UnitTypeLand,UnitTypeNaval ]
|
||||
if (loadedType == UnitTypeLand) {
|
||||
return FindUnloadPosition(startPos, resPos, LandUnitMask);
|
||||
} else {
|
||||
return FindUnloadPosition(startPos, resPos, NavalUnitMask);
|
||||
}
|
||||
const bool res = ClosestFreeDropZone_internal(transporter, startPos, maxRange, resPos);
|
||||
if (!isTransporterRemoved) {
|
||||
transporter.Place(transporter.tilePos);
|
||||
}
|
||||
// Just to avoid a warning
|
||||
return 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
** Move to dropzone.
|
||||
**
|
||||
|
@ -299,14 +267,10 @@ static int MoveToDropZone(CUnit &unit)
|
|||
**
|
||||
** @param unit Pointer to unit.
|
||||
*/
|
||||
static void LeaveTransporter(CUnit &unit)
|
||||
static void LeaveTransporter(CUnit &transporter)
|
||||
{
|
||||
int i;
|
||||
int stillonboard;
|
||||
CUnit *goal;
|
||||
|
||||
stillonboard = 0;
|
||||
goal = unit.CurrentOrder()->GetGoal();
|
||||
int stillonboard = 0;
|
||||
CUnit *goal = transporter.CurrentOrder()->GetGoal();
|
||||
//
|
||||
// Goal is the specific unit unit that you want to unload.
|
||||
// This can be NULL, in case you want to unload everything.
|
||||
|
@ -314,30 +278,30 @@ static void LeaveTransporter(CUnit &unit)
|
|||
if (goal) {
|
||||
if (goal->Destroyed) {
|
||||
DebugPrint("destroyed unit unloading?\n");
|
||||
unit.CurrentOrder()->ClearGoal();
|
||||
transporter.CurrentOrder()->ClearGoal();
|
||||
return;
|
||||
}
|
||||
unit.CurrentOrder()->ClearGoal();
|
||||
goal->tilePos = unit.tilePos;
|
||||
transporter.CurrentOrder()->ClearGoal();
|
||||
goal->tilePos = transporter.tilePos;
|
||||
// Try to unload the unit. If it doesn't work there is no problem.
|
||||
if (UnloadUnit(*goal)) {
|
||||
unit.BoardCount--;
|
||||
if (UnloadUnit(transporter, *goal)) {
|
||||
transporter.BoardCount--;
|
||||
}
|
||||
} else {
|
||||
// Unload all units.
|
||||
goal = unit.UnitInside;
|
||||
for (i = unit.InsideCount; i; --i, goal = goal->NextContained) {
|
||||
goal = transporter.UnitInside;
|
||||
for (int i = transporter.InsideCount; i; --i, goal = goal->NextContained) {
|
||||
if (goal->Boarded) {
|
||||
goal->tilePos = unit.tilePos;
|
||||
if (!UnloadUnit(*goal)) {
|
||||
goal->tilePos = transporter.tilePos;
|
||||
if (!UnloadUnit(transporter, *goal)) {
|
||||
++stillonboard;
|
||||
} else {
|
||||
unit.BoardCount--;
|
||||
transporter.BoardCount--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (IsOnlySelected(unit)) {
|
||||
if (IsOnlySelected(transporter)) {
|
||||
SelectedUnitChanged();
|
||||
}
|
||||
|
||||
|
@ -345,12 +309,12 @@ static void LeaveTransporter(CUnit &unit)
|
|||
if (stillonboard) {
|
||||
// We tell it to unload at it's current position. This can't be done,
|
||||
// so it will search for a piece of free coast nearby.
|
||||
unit.CurrentOrder()->Action = UnitActionUnload;
|
||||
unit.CurrentOrder()->ClearGoal();
|
||||
unit.CurrentOrder()->goalPos = unit.tilePos;
|
||||
unit.SubAction = 0;
|
||||
transporter.CurrentOrder()->Action = UnitActionUnload;
|
||||
transporter.CurrentOrder()->ClearGoal();
|
||||
transporter.CurrentOrder()->goalPos = transporter.tilePos;
|
||||
transporter.SubAction = 0;
|
||||
} else {
|
||||
unit.ClearAction();
|
||||
transporter.ClearAction();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -361,19 +325,17 @@ static void LeaveTransporter(CUnit &unit)
|
|||
*/
|
||||
void HandleActionUnload(CUnit &unit)
|
||||
{
|
||||
int i;
|
||||
Vec2i pos;
|
||||
const int maxSearchRange = 20;
|
||||
|
||||
if (!unit.CanMove()) {
|
||||
unit.SubAction = 2;
|
||||
}
|
||||
switch (unit.SubAction) {
|
||||
//
|
||||
// Move the transporter
|
||||
//
|
||||
case 0:
|
||||
case 0: // Choose destination
|
||||
if (!unit.CurrentOrder()->HasGoal()) {
|
||||
if (!ClosestFreeDropZone(unit, unit.CurrentOrder()->goalPos, &pos)) {
|
||||
Vec2i pos;
|
||||
|
||||
if (!ClosestFreeDropZone(unit, unit.CurrentOrder()->goalPos, maxSearchRange, &pos)) {
|
||||
// Sorry... I give up.
|
||||
unit.ClearAction();
|
||||
return;
|
||||
|
@ -383,12 +345,15 @@ void HandleActionUnload(CUnit &unit)
|
|||
|
||||
NewResetPath(unit);
|
||||
unit.SubAction = 1;
|
||||
case 1:
|
||||
// follow on next case
|
||||
case 1: // Move unit to destination
|
||||
// The Goal is the unit that we have to unload.
|
||||
if (!unit.CurrentOrder()->HasGoal()) {
|
||||
const int moveResult = MoveToDropZone(unit);
|
||||
|
||||
// We have to unload everything
|
||||
if ((i = MoveToDropZone(unit))) {
|
||||
if (i == PF_REACHED) {
|
||||
if (moveResult) {
|
||||
if (moveResult == PF_REACHED) {
|
||||
if (++unit.SubAction == 1) {
|
||||
unit.ClearAction();
|
||||
}
|
||||
|
@ -398,10 +363,7 @@ void HandleActionUnload(CUnit &unit)
|
|||
}
|
||||
break;
|
||||
}
|
||||
//
|
||||
// Leave the transporter
|
||||
//
|
||||
case 2:
|
||||
case 2: // Leave the transporter
|
||||
// FIXME: show still animations ?
|
||||
LeaveTransporter(unit);
|
||||
if (unit.CanMove() && unit.CurrentAction() != UnitActionStill) {
|
||||
|
|
|
@ -616,7 +616,7 @@ static void AiGroupAttackerForTransport(AiForce &aiForce)
|
|||
}
|
||||
}
|
||||
if (transporterIndex == aiForce.Size()) {
|
||||
aiForce.State = AiForceAttackingState_Attacking;
|
||||
aiForce.State = AiForceAttackingState_AttackingWithTransporter;
|
||||
return ;
|
||||
}
|
||||
for (unsigned int i = 0; i < aiForce.Size(); ++i) {
|
||||
|
@ -628,7 +628,7 @@ static void AiGroupAttackerForTransport(AiForce &aiForce)
|
|||
}
|
||||
}
|
||||
if (goNext == true) {
|
||||
aiForce.State = AiForceAttackingState_Attacking;
|
||||
aiForce.State = AiForceAttackingState_AttackingWithTransporter;
|
||||
return ;
|
||||
}
|
||||
for (unsigned int i = 0; i < aiForce.Size(); ++i) {
|
||||
|
|
|
@ -98,6 +98,7 @@ enum AiForceAttackingState
|
|||
AiForceAttackingState_Free = -1,
|
||||
AiForceAttackingState_Waiting = 0,
|
||||
AiForceAttackingState_Boarding,
|
||||
AiForceAttackingState_AttackingWithTransporter,
|
||||
AiForceAttackingState_Attacking,
|
||||
};
|
||||
|
||||
|
|
|
@ -208,8 +208,7 @@ extern int UnitShowAnimationScaled(CUnit &unit, const CAnimation *anim, int scal
|
|||
extern int UnitShowAnimation(CUnit &unit, const CAnimation *anim);
|
||||
/// Handle the actions of all units each game cycle
|
||||
extern void UnitActions();
|
||||
/// Unload a unit.
|
||||
extern int UnloadUnit(CUnit &unit);
|
||||
|
||||
//@}
|
||||
|
||||
#endif // !__ACTIONS_H__
|
||||
|
|
|
@ -1221,7 +1221,7 @@ struct CResourceDepositFinder {
|
|||
class CPreference {
|
||||
public:
|
||||
CPreference() : ShowSightRange(false), ShowReactionRange(false),
|
||||
ShowAttackRange(false), ShowMessages(false),
|
||||
ShowAttackRange(false), ShowMessages(false),
|
||||
BigScreen(false),ShowOrders(0) {};
|
||||
|
||||
bool ShowSightRange; /// Show sight range.
|
||||
|
@ -1311,9 +1311,9 @@ extern void UnitHeadingFromDeltaXY(CUnit &unit, const Vec2i &delta);
|
|||
|
||||
|
||||
/// @todo more docu
|
||||
extern void DropOutOnSide(CUnit &unit, int heading, int addx, int addy);
|
||||
extern void DropOutOnSide(CUnit &unit, int heading, const CUnit *container);
|
||||
/// @todo more docu
|
||||
extern void DropOutNearest(CUnit &unit, const Vec2i &goalPos, int addx, int addy);
|
||||
extern void DropOutNearest(CUnit &unit, const Vec2i &goalPos, const CUnit *container);
|
||||
|
||||
/// Drop out all units in the unit
|
||||
extern void DropOutAll(const CUnit &unit);
|
||||
|
|
|
@ -615,12 +615,13 @@ static int AStarMarkGoal(int gx, int gy, int gw, int gh,
|
|||
bool goal_reachable = false;
|
||||
|
||||
const Vec2i goal = {gx, gy};
|
||||
const Vec2i extratilesize = {tilesizex - 1, tilesizey - 1};
|
||||
|
||||
// top hemi cycle
|
||||
const int miny = std::max(-maxrange, 0 - goal.y);
|
||||
for (int offsety = miny; offsety < -minrange; ++offsety) {
|
||||
const int miny = std::max(-maxrange - extratilesize.y, 0 - goal.y);
|
||||
for (int offsety = miny; offsety < -minrange - extratilesize.y; ++offsety) {
|
||||
const int offsetx = isqrt(square(maxrange + 1) - square(-offsety) - 1);
|
||||
const int minx = std::max(0, goal.x - offsetx);
|
||||
const int minx = std::max(0, goal.x - offsetx - extratilesize.x);
|
||||
const int maxx = std::min(Map.Info.MapWidth, goal.x + gw + offsetx);
|
||||
Vec2i mpos = {minx, goal.y + offsety};
|
||||
const unsigned int offset = mpos.y * Map.Info.MapWidth;
|
||||
|
@ -635,8 +636,8 @@ static int AStarMarkGoal(int gx, int gy, int gw, int gh,
|
|||
}
|
||||
if (minrange == 0) {
|
||||
// center
|
||||
for (int offsety = 0; offsety < gh; ++offsety) {
|
||||
const int minx = std::max(0, goal.x - maxrange);
|
||||
for (int offsety = -extratilesize.y; offsety < gh; ++offsety) {
|
||||
const int minx = std::max(0, goal.x - maxrange - extratilesize.x);
|
||||
const int maxx = std::min(Map.Info.MapWidth, goal.x + gw + maxrange);
|
||||
Vec2i mpos = {minx, goal.y + offsety};
|
||||
const unsigned int offset = mpos.y * Map.Info.MapWidth;
|
||||
|
@ -651,12 +652,12 @@ static int AStarMarkGoal(int gx, int gy, int gw, int gh,
|
|||
}
|
||||
} else {
|
||||
// top hemi cycle
|
||||
const int miny = std::max(-minrange, 0 - goal.y);
|
||||
const int miny = std::max(-minrange - extratilesize.y, 0 - goal.y);
|
||||
for (int offsety = miny; offsety < 0; ++offsety) {
|
||||
const int offsetx1 = isqrt(square(maxrange + 1) - square(-offsety) - 1);
|
||||
const int offsetx2 = isqrt(square(minrange + 1) - square(-offsety) - 1);
|
||||
const int minxs[2] = {std::max(0, goal.x - offsetx1), std::min(Map.Info.MapWidth, goal.x + gw + offsetx2)};
|
||||
const int maxxs[2] = {std::max(0, goal.x - offsetx2), std::min(Map.Info.MapWidth, goal.x + gw + offsetx1)};
|
||||
const int minxs[2] = {std::max(0, goal.x - offsetx1 - extratilesize.x), std::min(Map.Info.MapWidth, goal.x + gw + offsetx2)};
|
||||
const int maxxs[2] = {std::max(0, goal.x - offsetx2 - extratilesize.x), std::min(Map.Info.MapWidth, goal.x + gw + offsetx1)};
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
|
@ -676,11 +677,11 @@ static int AStarMarkGoal(int gx, int gy, int gw, int gh,
|
|||
}
|
||||
|
||||
// center
|
||||
const int mincenters[] = {std::max(0, goal.x - maxrange), 0, std::min(Map.Info.MapWidth, goal.x + gw + minrange)};
|
||||
const int maxcenters[] = {std::max(0, goal.x - minrange), gw, std::min(Map.Info.MapWidth, goal.x + gw + maxrange)};
|
||||
const int mincenters[] = {std::max(0, goal.x - maxrange - extratilesize.x), -extratilesize.x, std::min(Map.Info.MapWidth, goal.x + gw + minrange)};
|
||||
const int maxcenters[] = {std::max(0, goal.x - minrange - extratilesize.x), gw, std::min(Map.Info.MapWidth, goal.x + gw + maxrange)};
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
for (int offsety = 0; offsety < gh; ++offsety) {
|
||||
for (int offsety = -extratilesize.y; offsety < gh; ++offsety) {
|
||||
const int minx = mincenters[i];
|
||||
const int maxx = maxcenters[i];
|
||||
Vec2i mpos = {minx, goal.y + offsety};
|
||||
|
@ -701,8 +702,8 @@ static int AStarMarkGoal(int gx, int gy, int gw, int gh,
|
|||
for (int offsety = 0; offsety < maxy; ++offsety) {
|
||||
const int offsetx1 = isqrt(square(maxrange + 1) - square(offsety) - 1);
|
||||
const int offsetx2 = isqrt(square(minrange + 1) - square(offsety) - 1);
|
||||
const int minxs[2] = {std::max(0, goal.x - offsetx1), std::min(Map.Info.MapWidth, goal.x + gw + offsetx2)};
|
||||
const int maxxs[2] = {std::max(0, goal.x - offsetx2), std::min(Map.Info.MapWidth, goal.x + gw + offsetx1)};
|
||||
const int minxs[2] = {std::max(0, goal.x - offsetx1) - extratilesize.x, std::min(Map.Info.MapWidth, goal.x + gw + offsetx2)};
|
||||
const int maxxs[2] = {std::max(0, goal.x - offsetx2) - extratilesize.x, std::min(Map.Info.MapWidth, goal.x + gw + offsetx1)};
|
||||
|
||||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
|
@ -726,7 +727,7 @@ static int AStarMarkGoal(int gx, int gy, int gw, int gh,
|
|||
const int maxy = std::min(maxrange, Map.Info.MapHeight - goal.y - gh);
|
||||
for (int offsety = minrange; offsety < maxy; ++offsety) {
|
||||
const int offsetx = isqrt(square(maxrange + 1) - square(offsety) - 1);
|
||||
const int minx = std::max(0, goal.x - offsetx);
|
||||
const int minx = std::max(0, goal.x - offsetx - extratilesize.x);
|
||||
const int maxx = std::min(Map.Info.MapWidth, goal.x + gw + offsetx);
|
||||
Vec2i mpos = {minx, goal.y + gh + offsety};
|
||||
const unsigned int offset = mpos.y * Map.Info.MapWidth;
|
||||
|
|
|
@ -676,10 +676,9 @@ int Summon::Cast(CUnit &caster, const SpellType *spell,
|
|||
//
|
||||
target = MakeUnit(unittype, caster.Player);
|
||||
if (target != NoUnitP) {
|
||||
// This is a hack to walk around behaviour of DropOutOnSide
|
||||
target->tilePos.x = x + 1;
|
||||
target->tilePos.x = x;
|
||||
target->tilePos.y = y;
|
||||
DropOutOnSide(*target, LookingW, 0, 0); // FIXME : 0,0) : good parameter ?
|
||||
DropOutOnSide(*target, LookingW, NULL);
|
||||
//
|
||||
// set life span. ttl=0 results in a permanent unit.
|
||||
//
|
||||
|
|
|
@ -940,14 +940,12 @@ static int CclUnit(lua_State *l)
|
|||
*/
|
||||
static int CclMoveUnit(lua_State *l)
|
||||
{
|
||||
CUnit *unit;
|
||||
int heading;
|
||||
Vec2i ipos;
|
||||
|
||||
LuaCheckArgs(l, 2);
|
||||
|
||||
lua_pushvalue(l, 1);
|
||||
unit = CclGetUnit(l);
|
||||
CUnit *unit = CclGetUnit(l);
|
||||
lua_pop(l, 1);
|
||||
|
||||
lua_rawgeti(l, 2, 1);
|
||||
|
@ -957,14 +955,14 @@ static int CclMoveUnit(lua_State *l)
|
|||
ipos.y = LuaToNumber(l, -1);
|
||||
lua_pop(l, 1);
|
||||
|
||||
heading = SyncRand() % 256;
|
||||
if (UnitCanBeAt(*unit, ipos)) {
|
||||
unit->Place(ipos);
|
||||
} else {
|
||||
const int heading = SyncRand() % 256;
|
||||
|
||||
unit->tilePos = ipos;
|
||||
DropOutOnSide(*unit, heading, 1, 1);
|
||||
DropOutOnSide(*unit, heading, NULL);
|
||||
}
|
||||
// PlaceUnit(unit, ipos.x, ipos.y);
|
||||
lua_pushvalue(l, 1);
|
||||
return 1;
|
||||
}
|
||||
|
@ -980,7 +978,6 @@ static int CclCreateUnit(lua_State *l)
|
|||
{
|
||||
CUnitType *unittype;
|
||||
CUnit *unit;
|
||||
int heading;
|
||||
int playerno;
|
||||
Vec2i ipos;
|
||||
|
||||
|
@ -999,7 +996,6 @@ static int CclCreateUnit(lua_State *l)
|
|||
ipos.y = LuaToNumber(l, -1);
|
||||
lua_pop(l, 1);
|
||||
|
||||
heading = SyncRand() % 256;
|
||||
lua_pushvalue(l, 2);
|
||||
playerno = TriggerGetPlayer(l);
|
||||
lua_pop(l, 1);
|
||||
|
@ -1023,8 +1019,10 @@ static int CclCreateUnit(lua_State *l)
|
|||
(unit->Type->Building && CanBuildUnitType(NULL, *unit->Type, ipos, 0))) {
|
||||
unit->Place(ipos);
|
||||
} else {
|
||||
const int heading = SyncRand() % 256;
|
||||
|
||||
unit->tilePos = ipos;
|
||||
DropOutOnSide(*unit, heading, 1, 1);
|
||||
DropOutOnSide(*unit, heading, NULL);
|
||||
}
|
||||
UpdateForNewUnit(*unit, 0);
|
||||
|
||||
|
@ -1344,9 +1342,9 @@ static int CclSetUnitVariable(lua_State *l)
|
|||
if (!strcmp(name, "RegenerationRate"))
|
||||
{
|
||||
value = LuaToNumber(l, 3);
|
||||
if (value > unit->Variable[HP_INDEX].Max)
|
||||
if (value > unit->Variable[HP_INDEX].Max)
|
||||
unit->Stats->Variables[HP_INDEX].Increase = unit->Variable[HP_INDEX].Max;
|
||||
else
|
||||
else
|
||||
unit->Stats->Variables[HP_INDEX].Increase = value;
|
||||
}
|
||||
else
|
||||
|
|
|
@ -634,6 +634,10 @@ void MarkUnitFieldFlags(const CUnit &unit)
|
|||
int w, h = unit.Type->TileHeight; // Tile height of the unit.
|
||||
const int width = unit.Type->TileWidth; // Tile width of the unit.
|
||||
unsigned int index = unit.Offset;
|
||||
|
||||
if (unit.Type->Vanishes) {
|
||||
return ;
|
||||
}
|
||||
do {
|
||||
mf = Map.Field(index);
|
||||
w = width;
|
||||
|
@ -671,6 +675,10 @@ void UnmarkUnitFieldFlags(const CUnit &unit)
|
|||
const int width = unit.Type->TileWidth; // Tile width of the unit.
|
||||
unsigned int index = unit.Offset;
|
||||
|
||||
if (unit.Type->Vanishes) {
|
||||
return ;
|
||||
}
|
||||
|
||||
_UnmarkUnitFieldFlags funct(unit);
|
||||
|
||||
do {
|
||||
|
@ -1814,62 +1822,74 @@ void UnitHeadingFromDeltaXY(CUnit &unit, const Vec2i &delta)
|
|||
**
|
||||
** @param unit Unit to drop out.
|
||||
** @param heading Direction in which the unit should appear.
|
||||
** @param addx Tile width of unit it's dropping out of.
|
||||
** @param addy Tile height of unit it's dropping out of.
|
||||
** @param container Unit "containing" unit to drop (may be different of unit.Container).
|
||||
*/
|
||||
void DropOutOnSide(CUnit &unit, int heading, int addx, int addy)
|
||||
void DropOutOnSide(CUnit &unit, int heading, const CUnit *container)
|
||||
{
|
||||
Vec2i pos;
|
||||
int i;
|
||||
int addx = 0;
|
||||
int addy = 0;
|
||||
|
||||
if (unit.Container) {
|
||||
pos = unit.Container->tilePos;
|
||||
if (container) {
|
||||
pos = container->tilePos;
|
||||
pos.x -= unit.Type->TileWidth - 1;
|
||||
pos.y -= unit.Type->TileHeight - 1;
|
||||
addx = container->Type->TileWidth + unit.Type->TileWidth - 1;
|
||||
addy = container->Type->TileHeight + unit.Type->TileHeight - 1;
|
||||
|
||||
if (heading < LookingNE || heading > LookingNW) {
|
||||
pos.x += addx - 1;
|
||||
--pos.y;
|
||||
goto startn;
|
||||
} else if (heading < LookingSE) {
|
||||
pos.x += addx;
|
||||
pos.y += addy - 1;
|
||||
goto starte;
|
||||
} else if (heading < LookingSW) {
|
||||
pos.y += addy;
|
||||
goto starts;
|
||||
} else {
|
||||
--pos.x;
|
||||
goto startw;
|
||||
}
|
||||
} else {
|
||||
pos = unit.tilePos;
|
||||
}
|
||||
|
||||
if (heading < LookingNE || heading > LookingNW) {
|
||||
pos.x += addx - 1;
|
||||
--pos.y;
|
||||
goto startn;
|
||||
if (heading < LookingNE || heading > LookingNW) {
|
||||
goto starts;
|
||||
} else if (heading < LookingSE) {
|
||||
goto startw;
|
||||
} else if (heading < LookingSW) {
|
||||
goto startn;
|
||||
} else {
|
||||
goto starte;
|
||||
}
|
||||
}
|
||||
if (heading < LookingSE) {
|
||||
pos.x += addx;
|
||||
pos.y += addy - 1;
|
||||
goto starte;
|
||||
}
|
||||
if (heading < LookingSW) {
|
||||
pos.y += addy;
|
||||
goto starts;
|
||||
}
|
||||
--pos.x;
|
||||
goto startw;
|
||||
|
||||
// FIXME: don't search outside of the map
|
||||
for (;;) {
|
||||
startw:
|
||||
for (i = addy; i--; ++pos.y) {
|
||||
for (int i = addy; i--; ++pos.y) {
|
||||
if (UnitCanBeAt(unit, pos)) {
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
++addx;
|
||||
starts:
|
||||
for (i = addx; i--; ++pos.x) {
|
||||
for (int i = addx; i--; ++pos.x) {
|
||||
if (UnitCanBeAt(unit, pos)) {
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
++addy;
|
||||
starte:
|
||||
for (i = addy; i--; --pos.y) {
|
||||
for (int i = addy; i--; --pos.y) {
|
||||
if (UnitCanBeAt(unit, pos)) {
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
++addx;
|
||||
startn:
|
||||
for (i = addx; i--; --pos.x) {
|
||||
for (int i = addx; i--; --pos.x) {
|
||||
if (UnitCanBeAt(unit, pos)) {
|
||||
goto found;
|
||||
}
|
||||
|
@ -1882,29 +1902,34 @@ found:
|
|||
}
|
||||
|
||||
/**
|
||||
** Place a unit on the map nearest to x, y.
|
||||
** Place a unit on the map nearest to goalPos.
|
||||
**
|
||||
** @param unit Unit to drop out.
|
||||
** @param goalPos Goal map tile position.
|
||||
** @param addx Tile width of unit it's dropping out of.
|
||||
** @param addy Tile height of unit it's dropping out of.
|
||||
*/
|
||||
void DropOutNearest(CUnit &unit, const Vec2i &goalPos, int addx, int addy)
|
||||
void DropOutNearest(CUnit &unit, const Vec2i &goalPos, const CUnit *container)
|
||||
{
|
||||
Vec2i pos;
|
||||
Vec2i bestPos = {0, 0};
|
||||
int bestd = 99999;
|
||||
|
||||
int addx = 0;
|
||||
int addy = 0;
|
||||
Assert(unit.Removed);
|
||||
|
||||
if (unit.Container) {
|
||||
pos = unit.Container->tilePos;
|
||||
if (container) {
|
||||
pos = container->tilePos;
|
||||
pos.x -= unit.Type->TileWidth - 1;
|
||||
pos.y -= unit.Type->TileHeight - 1;
|
||||
addx = container->Type->TileWidth + unit.Type->TileWidth - 1;
|
||||
addy = container->Type->TileHeight + unit.Type->TileHeight - 1;
|
||||
--pos.x;
|
||||
} else {
|
||||
pos = unit.tilePos;
|
||||
}
|
||||
|
||||
// FIXME: if we reach the map borders we can go fast up, left, ...
|
||||
--pos.x;
|
||||
|
||||
for (;;) {
|
||||
for (int i = addy; i--; ++pos.y) { // go down
|
||||
if (UnitCanBeAt(unit, pos)) {
|
||||
|
@ -1964,18 +1989,14 @@ void DropOutNearest(CUnit &unit, const Vec2i &goalPos, int addx, int addy)
|
|||
*/
|
||||
void DropOutAll(const CUnit &source)
|
||||
{
|
||||
CUnit *unit;
|
||||
int i;
|
||||
CUnit *unit = source.UnitInside;
|
||||
|
||||
unit = source.UnitInside;
|
||||
for (i = source.InsideCount; i; --i, unit = unit->NextContained) {
|
||||
DropOutOnSide(*unit, LookingW,
|
||||
source.Type->TileWidth, source.Type->TileHeight);
|
||||
for (int i = source.InsideCount; i; --i, unit = unit->NextContained) {
|
||||
DropOutOnSide(*unit, LookingW, &source);
|
||||
Assert(!unit->CurrentOrder()->HasGoal());
|
||||
unit->CurrentOrder()->Action = UnitActionStill;
|
||||
unit->SubAction = 0;
|
||||
}
|
||||
DebugPrint("Drop out %d of %d\n" _C_ i _C_ source.Data.Resource.Active);
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue