public void move()
{
// Immobile beings cannot move.
if(!checkAttributeExists((int)Attributes.ATTR_MOVE_SPEED_RAW)
||getModifiedAttribute((int)Attributes.ATTR_MOVE_SPEED_RAW)==0)
return;
// Remember the current position before moving. This is used by
// MapComposite::update() to determine whether a being has moved from one
// zone to another.
mOld=getPosition();
if(mMoveTime>ManaServ.WORLD_TICK_MS)
{
// Current move has not yet ended
mMoveTime-=ManaServ.WORLD_TICK_MS;
return;
}
Map map=getMap().getMap();
int tileWidth=map.getTileWidth();
int tileHeight=map.getTileHeight();
int tileSX=getPosition().x/tileWidth;
int tileSY=getPosition().y/tileHeight;
int tileDX=mDst.x/tileWidth;
int tileDY=mDst.y/tileHeight;
if(tileSX==tileDX&&tileSY==tileDY)
{
if(mAction==BeingAction.WALK)
setAction(BeingAction.STAND);
// Moving while staying on the same tile is free
// We only update the direction in that case.
updateDirection(getPosition(), mDst);
setPosition(mDst);
mMoveTime=0;
return;
}
/* If no path exists, the for-loop won't be entered. Else a path for the
* current destination has already been calculated.
* The tiles in this path have to be checked for walkability,
* in case there have been changes. The 'getWalk' method of the Map
* class has been used, because that seems to be the most logical
* place extra functionality will be added.
*/
foreach(Point point in mPath)
{
if(!map.getWalk(point.x, point.y, getWalkMask()))
{
mPath.Clear();
break;
}
}
if(mPath.Count==0)
{
// No path exists: the walkability of cached path has changed, the
// destination has changed, or a path was never set.
mPath=findPath();
}
if(mPath.Count==0)
{
if(mAction==BeingAction.WALK)
setAction(BeingAction.STAND);
// no path was found
mDst=mOld;
mMoveTime=0;
return;
}
setAction(BeingAction.WALK);
Point prev=new Point(tileSX, tileSY);
Point pos=new Point();
do
{
Point next=mPath[0];
mPath.RemoveAt(0);
// SQRT2 is used for diagonal movement.
mMoveTime+=(ushort)((prev.x==next.x||prev.y==next.y)?
getModifiedAttribute((int)Attributes.ATTR_MOVE_SPEED_RAW):
getModifiedAttribute((int)Attributes.ATTR_MOVE_SPEED_RAW)*Math.Sqrt(2));
if(mPath.Count==0)
{
// skip last tile center
pos=mDst;
break;
}
// Position the actor in the middle of the tile for pathfinding purposes
pos.x=next.x*tileWidth+(tileWidth/2);
pos.y=next.y*tileHeight+(tileHeight/2);
}
while (mMoveTime < ManaServ.WORLD_TICK_MS);
setPosition(pos);
mMoveTime=(ushort)(mMoveTime>ManaServ.WORLD_TICK_MS?mMoveTime-ManaServ.WORLD_TICK_MS:0);
// Update the being direction also
updateDirection(mOld, pos);
}