NxN unit could move

This commit is contained in:
jarod42 2004-07-09 17:00:58 +00:00
parent d4ca70e473
commit 0a6ef2d1ac
8 changed files with 107 additions and 137 deletions

View file

@ -152,7 +152,7 @@ void ActionStillGeneric(Unit* unit, int ground)
y = TheMap.Height - 1;
}
if (x != unit->X || y != unit->Y) {
if (CheckedCanMoveToMask(x, y, TypeMovementMask(type))) {
if (UnitCanMoveTo(unit, x, y)) {
// FIXME: Don't use pathfinder for this, costs too much cpu.
unit->Orders[0].Action = UnitActionMove;
Assert(!unit->Orders[0].Goal);

View file

@ -50,44 +50,21 @@
-- 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 x, y
** Find a free position close to x, y for unit.
**
** @unit Unit to unload.
** @param x Original x search position
** @param y Original y search position
** @param resx Unload x position.
** @param resy Unload y position.
** @param mask Movement mask for the unit to be droped.
**
** @return True if a position was found, False otherwise.
** @note resx and resy are undefined if a position is not found.
**
** @bug FIXME: Place unit only on fields reachable from the transporter
*/
static int FindUnloadPosition(int x, int y, int* resx, int* resy, int mask)
static int FindUnloadPositionForUnit(const Unit* unit, int x, int y, int* resx, int* resy)
{
int i;
int n;
@ -100,7 +77,7 @@ static int FindUnloadPosition(int x, int y, int* resx, int* resy, int mask)
// 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--; ++y) {
if (CheckedCanMoveToMask(x, y, mask)) {
if (UnitCanMoveTo(unit, x, y)) {
*resx = x;
*resy = y;
return 1;
@ -108,7 +85,7 @@ static int FindUnloadPosition(int x, int y, int* resx, int* resy, int mask)
}
++addx;
for (i = addx; i--; ++x) {
if (CheckedCanMoveToMask(x, y, mask)) {
if (UnitCanMoveTo(unit, x, y)) {
*resx = x;
*resy = y;
return 1;
@ -116,7 +93,7 @@ static int FindUnloadPosition(int x, int y, int* resx, int* resy, int mask)
}
++addy;
for (i = addy; i--; --y) {
if (CheckedCanMoveToMask(x, y, mask)) {
if (UnitCanMoveTo(unit, x, y)) {
*resx = x;
*resy = y;
return 1;
@ -124,7 +101,7 @@ static int FindUnloadPosition(int x, int y, int* resx, int* resy, int mask)
}
++addx;
for (i = addx; i--; --x) {
if (CheckedCanMoveToMask(x, y, mask)) {
if (UnitCanMoveTo(unit, x, y)) {
*resx = x;
*resy = y;
return 1;
@ -135,6 +112,7 @@ static int FindUnloadPosition(int x, int y, int* resx, int* resy, int mask)
return 0;
}
/**
** Reappear unit on map.
**
@ -150,7 +128,7 @@ int UnloadUnit(Unit* unit)
int y;
Assert(unit->Removed);
if (!FindUnloadPosition(unit->X, unit->Y, &x, &y, UnitMovementMask(unit))) {
if (!FindUnloadPositionForUnit(unit, unit->X, unit->Y, &x, &y)) {
return 0;
}
unit->Wait = 1; // should be correct unit has still action
@ -168,8 +146,9 @@ int UnloadUnit(Unit* unit)
** @param resy coast y position
**
** @return 1 if a location was found, 0 otherwise
** @todo Only know area.
*/
static int ClosestFreeCoast(int x, int y, int* resx, int* resy)
static int ClosestFreeCoast(const Unit* unit, int x, int y, int* resx, int* resy, int mask)
{
int i;
int addx;
@ -179,54 +158,42 @@ static int ClosestFreeCoast(int x, int y, int* resx, int* resy)
int n;
addx = addy = 1;
if (CoastOnMap(x, y) &&
FindUnloadPosition(x, y, &nullx, &nully, LandUnitMask)) {
if ((~TheMap.Fields[x + y * TheMap.Width].Flags & mask) &&
FindUnloadPositionForUnit(unit, x, y, &nullx, &nully)) {
*resx = x;
*resy = y;
return 1;
}
#ifdef shortalias
#warning // rename this define.
#endif
#define shortalias \
if (x >= 0 && y >= 0 && x < TheMap.Width && y < TheMap.Height && \
(~TheMap.Fields[x + y * TheMap.Width].Flags & mask) && !UnitOnMapTile(x, y) && \
FindUnloadPositionForUnit(unit, x, y, &nullx, &nully)) { \
*resx = x; \
*resy = y; \
return 1; \
}
--x;
// The maximum distance to the coast. We have to stop somewhere...
n = 20;
while (n--) {
for (i = addy; i--; ++y) {
if (x >= 0 && y >= 0 && x < TheMap.Width && y < TheMap.Height &&
CoastOnMap(x, y) && !UnitOnMapTile(x, y) &&
FindUnloadPosition(x, y, &nullx, &nully, LandUnitMask)) {
*resx = x;
*resy = y;
return 1;
}
shortalias;
}
++addx;
for (i = addx; i--; ++x) {
if (x >= 0 && y >= 0 && x < TheMap.Width && y < TheMap.Height &&
CoastOnMap(x, y) && !UnitOnMapTile(x ,y) &&
FindUnloadPosition(x, y, &nullx, &nully, LandUnitMask)) {
*resx = x;
*resy = y;
return 1;
}
shortalias;
}
++addy;
for (i = addy; i--; --y) {
if (x >= 0 && y >= 0 && x < TheMap.Width && y < TheMap.Height &&
CoastOnMap(x, y) && !UnitOnMapTile(x, y) &&
FindUnloadPosition(x, y, &nullx, &nully, LandUnitMask)) {
*resx = x;
*resy = y;
return 1;
}
shortalias;
}
++addx;
for (i = addx; i--; --x) {
if (x >= 0 && y >= 0 && x < TheMap.Width && y < TheMap.Height &&
CoastOnMap(x, y) && !UnitOnMapTile(x, y) &&
FindUnloadPosition(x, y, &nullx, &nully, LandUnitMask)) {
*resx = x;
*resy = y;
return 1;
}
shortalias;
}
++addy;
}
@ -273,20 +240,20 @@ static int ClosestFreeDropZone(Unit* transporter, int x, int y, int* resx, int*
switch (transporterType) {
case UnitTypeLand:
// in this case, loadedType == UnitTypeSea
return ClosestFreeCoast(x, y, resx, resy);
return ClosestFreeCoast(transporter->UnitInside, x, y, resx, resy, MapFieldCoastAllowed);
case UnitTypeNaval:
// Same ( but reversed... )
return ClosestFreeCoast(x, y, resx, resy);
return ClosestFreeCoast(transporter, x, y, resx, resy, MapFieldCoastAllowed);
case UnitTypeFly:
// Here we have loadedType in [ UnitTypeLand,UnitTypeNaval ]
if (loadedType == UnitTypeLand) {
return FindUnloadPosition(x, y, resx, resy, LandUnitMask);
} else {
return FindUnloadPosition(x, y, resx, resy, NavalUnitMask);
}
// Now, depend of unit inside.
return ClosestFreeCoast(transporter->UnitInside, x, y, resx, resy,
MapFieldCoastAllowed | (loadedType == UnitTypeNaval) ?
MapFieldWaterAllowed : MapFieldLandAllowed);
default :
DebugPrint("unknow type for transporter\n");
abort();
return 0;
}
// Just to avoid a warning
return 0;
}
/**

View file

@ -473,12 +473,12 @@ extern int ForestOnMap(int x, int y);
/// Returns true, if rock on the map tile field
extern int RockOnMap(int x, int y);
/// Returns true, if the unit-type(mask can enter field with bounds check
extern int CheckedCanMoveToMask(int x, int y, int mask);
/// Returns true, if the unit-type can enter the field
extern int UnitTypeCanMoveTo(int x, int y, const UnitType* type);
/// Returns true, if the unit can enter the field
extern int UnitCanMoveTo(int x, int y, const Unit* unit);
extern int UnitCanMoveTo(const Unit* unit, int x, int y);
/// Returns true, if the unittype can enter the field
extern int UnitTypeCanMoveTo(const UnitType* type, int x, int y);
/// Preprocess map, for internal use.
extern void PreprocessMap(void);

View file

@ -380,7 +380,7 @@ int RockOnMap(int tx, int ty)
**
** @return True if could be entered, false otherwise.
*/
int CheckedCanMoveToMask(int x, int y, int mask)
static int CheckedCanMoveToMask(int x, int y, int mask)
{
if (x < 0 || y < 0 || x >= TheMap.Width || y >= TheMap.Height) {
return 0;
@ -390,31 +390,45 @@ int CheckedCanMoveToMask(int x, int y, int mask)
}
/**
** Can a unit of unit-type move to this point.
** Can an unittype move to this point.
**
** @param unit unit to be checked.
** @param x X map tile position.
** @param y Y map tile position.
** @param type unit-type to be checked.
**
** @return True if could be entered, false otherwise.
*/
int UnitTypeCanMoveTo(int x, int y, const UnitType* type)
int UnitTypeCanMoveTo(const UnitType* type, int x, int y)
{
return CanMoveToMask(x, y, TypeMovementMask(type));
int addx;
int addy;
int mask; // movement mask of the unit.
Assert(type);
mask = TypeMovementMask(type);
for (addx = 0; addx < type->TileWidth; addx++) {
for (addy = 0; addy < type->TileHeight; addy++) {
if (!CheckedCanMoveToMask(x + addx, y + addy, mask)) {
return 0;
}
}
}
return 1;
}
/**
** Can an unit move to this point.
**
** @param unit unit to be checked.
** @param x X map tile position.
** @param y Y map tile position.
** @param unit unit to be checked.
**
** @return True if could be entered, false otherwise.
*/
int UnitCanMoveTo(int x, int y, const Unit* unit)
int UnitCanMoveTo(const Unit* unit, int x, int y)
{
return CanMoveToMask(x, y, TypeMovementMask(unit->Type));
Assert(unit);
return UnitTypeCanMoveTo(unit->Type, x, y);
}
/**

View file

@ -300,6 +300,9 @@ static int CostMoveTo(Unit* unit, int ex, int ey, int mask, int current_cost) {
if (unit->X == ex && unit->Y == ey) {
return 0;
}
if (!UnitCanMoveTo(unit, ex, ey)) {
return -1;
}
j = TheMap.Fields[ex + ey * TheMap.Width].Flags & mask;
if( j && (AStarKnowUnknown
|| IsMapFieldExplored(unit->Player, ex, ey)) ) {
@ -752,45 +755,45 @@ int NextPathElement(Unit* unit,int* pxd,int *pyd)
// Attempt to use path cache
// FIXME: If there is a goal, it may have moved, ruining the cache
*pxd=0;
*pyd=0;
*pxd = 0;
*pyd = 0;
// Goal has moved, need to recalculate path or no cached path
if( unit->Data.Move.Length <= 0 ||
( unit->Goal && (unit->Goal->X != unit->Orders[0].X
|| unit->Goal->Y != unit->Orders[0].Y)) ) {
result=NewPath(unit);
if(unit->Data.Move.Length <= 0 ||
(unit->Goal && (unit->Goal->X != unit->Orders[0].X
|| unit->Goal->Y != unit->Orders[0].Y))) {
result = NewPath(unit);
if( result==PF_UNREACHABLE ) {
unit->Data.Move.Length=0;
if(result == PF_UNREACHABLE) {
unit->Data.Move.Length = 0;
return result;
}
if( result==PF_REACHED ) {
if(result == PF_REACHED) {
return result;
}
if( unit->Goal ) {
if(unit->Goal) {
// Update Orders
unit->Orders[0].X=unit->Goal->X;
unit->Orders[0].Y=unit->Goal->Y;
unit->Orders[0].X = unit->Goal->X;
unit->Orders[0].Y = unit->Goal->Y;
}
}
*pxd=Heading2X[(int)unit->Data.Move.Path[(int)unit->Data.Move.Length-1]];
*pyd=Heading2Y[(int)unit->Data.Move.Path[(int)unit->Data.Move.Length-1]];
result=unit->Data.Move.Length;
*pxd = Heading2X[(int)unit->Data.Move.Path[(int)unit->Data.Move.Length - 1]];
*pyd = Heading2Y[(int)unit->Data.Move.Path[(int)unit->Data.Move.Length - 1]];
result = unit->Data.Move.Length;
unit->Data.Move.Length--;
if( !CheckedCanMoveToMask(*pxd+unit->X,*pyd+unit->Y,UnitMovementMask(unit)) ) {
result=NewPath(unit);
if( result>0 ) {
*pxd=Heading2X[(int)unit->Data.Move.Path[(int)unit->Data.Move.Length-1]];
*pyd=Heading2Y[(int)unit->Data.Move.Path[(int)unit->Data.Move.Length-1]];
if( !CheckedCanMoveToMask(*pxd+unit->X,*pyd+unit->Y,UnitMovementMask(unit)) ) {
if(!UnitCanMoveTo(unit, *pxd + unit->X, *pyd + unit->Y)) {
result = NewPath(unit);
if(result > 0) {
*pxd = Heading2X[(int)unit->Data.Move.Path[(int)unit->Data.Move.Length - 1]];
*pyd = Heading2Y[(int)unit->Data.Move.Path[(int)unit->Data.Move.Length - 1]];
if(!UnitCanMoveTo(unit, *pxd + unit->X, *pyd + unit->Y)) {
// There may be unit in the way, Astar may allow you to walk onto it.
result=PF_UNREACHABLE;
*pxd=0;
*pyd=0;
result = PF_UNREACHABLE;
*pxd = 0;
*pyd = 0;
} else {
result=unit->Data.Move.Length;
result = unit->Data.Move.Length;
unit->Data.Move.Length--;
}
}

View file

@ -599,8 +599,6 @@ int CastAdjustVitals(Unit* caster, const SpellType* spell,
int CastPolymorph(Unit* caster, const SpellType* spell,
const SpellActionType* action, Unit* target, int x, int y)
{
int i;
int j;
UnitType* type;
type = action->Data.Polymorph.NewForm;
@ -625,13 +623,9 @@ int CastPolymorph(Unit* caster, const SpellType* spell,
// as said somewhere else -- no corpses :)
RemoveUnit(target, NULL);
for (i = 0; i < type->TileWidth; ++i) {
for (j = 0; j < type->TileHeight; ++j) {
if (!UnitTypeCanMoveTo(x + i, y + j, type)) {
PlaceUnit(target, target->X, target->Y);
return 0;
}
}
if (!UnitTypeCanMoveTo(type, x, y)) {
PlaceUnit(target, target->X, target->Y);
return 0;
}
caster->Mana -= spell->ManaCost;
if (action->Data.Polymorph.PlayerNeutral) {

View file

@ -1003,7 +1003,6 @@ static int CclCreateUnit(lua_State* l)
Unit* unit;
int heading;
int playerno;
int mask;
int ix;
int iy;
@ -1034,8 +1033,7 @@ static int CclCreateUnit(lua_State* l)
return 0;
}
unit = MakeUnit(unittype, &Players[playerno]);
mask = UnitMovementMask(unit);
if (CheckedCanMoveToMask(ix, iy, mask)) {
if (UnitCanMoveTo(unit, ix, iy)) {
unit->Wait = 1;
PlaceUnit(unit, ix, iy);
} else {

View file

@ -1805,7 +1805,6 @@ void DropOutOnSide(Unit* unit, int heading, int addx, int addy)
int x;
int y;
int i;
int mask;
if (unit->Container) {
x = unit->Container->X;
@ -1816,9 +1815,6 @@ void DropOutOnSide(Unit* unit, int heading, int addx, int addy)
// n0b0dy: yes, when training an unit.
}
mask = UnitMovementMask(unit);
if (heading < LookingNE || heading > LookingNW) {
x += addx - 1;
--y;
@ -1840,28 +1836,28 @@ void DropOutOnSide(Unit* unit, int heading, int addx, int addy)
for (;;) {
startw:
for (i = addy; i--; ++y) {
if (CheckedCanMoveToMask(x, y, mask)) {
if (UnitCanMoveTo(unit, x, y)) {
goto found;
}
}
++addx;
starts:
for (i = addx; i--; ++x) {
if (CheckedCanMoveToMask(x, y, mask)) {
if (UnitCanMoveTo(unit, x, y)) {
goto found;
}
}
++addy;
starte:
for (i = addy; i--; --y) {
if (CheckedCanMoveToMask(x, y, mask)) {
if (UnitCanMoveTo(unit, x, y)) {
goto found;
}
}
++addx;
startn:
for (i = addx; i--; --x) {
if (CheckedCanMoveToMask(x, y, mask)) {
if (UnitCanMoveTo(unit, x, y)) {
goto found;
}
}
@ -1891,7 +1887,6 @@ void DropOutNearest(Unit* unit, int gx, int gy, int addx, int addy)
int bestx;
int besty;
int bestd;
int mask;
int n;
Assert(unit->Removed);
@ -1906,7 +1901,6 @@ void DropOutNearest(Unit* unit, int gx, int gy, int addx, int addy)
}
Assert(x != -1 && y != -1);
mask = UnitMovementMask(unit);
bestd = 99999;
#ifdef DEBUG
@ -1917,7 +1911,7 @@ void DropOutNearest(Unit* unit, int gx, int gy, int addx, int addy)
--x;
for (;;) {
for (i = addy; i--; ++y) { // go down
if (CheckedCanMoveToMask(x, y, mask)) {
if (UnitCanMoveTo(unit, x, y)) {
n = MapDistance(gx, gy, x, y);
if (n < bestd) {
bestd = n;
@ -1928,7 +1922,7 @@ void DropOutNearest(Unit* unit, int gx, int gy, int addx, int addy)
}
++addx;
for (i = addx; i--; ++x) { // go right
if (CheckedCanMoveToMask(x, y, mask)) {
if (UnitCanMoveTo(unit, x, y)) {
n = MapDistance(gx, gy, x, y);
if (n < bestd) {
bestd = n;
@ -1939,7 +1933,7 @@ void DropOutNearest(Unit* unit, int gx, int gy, int addx, int addy)
}
++addy;
for (i = addy; i--; --y) { // go up
if (CheckedCanMoveToMask(x, y, mask)) {
if (UnitCanMoveTo(unit, x, y)) {
n = MapDistance(gx, gy, x, y);
if (n < bestd) {
bestd = n;
@ -1950,7 +1944,7 @@ void DropOutNearest(Unit* unit, int gx, int gy, int addx, int addy)
}
++addx;
for (i = addx; i--; --x) { // go left
if (CheckedCanMoveToMask(x, y, mask)) {
if (UnitCanMoveTo(unit, x, y)) {
n = MapDistance(gx, gy, x, y);
if (n < bestd) {
bestd = n;