org.starhope.appius.user
Class AbstractNonPlayerCharacter

java.lang.Object
  extended by org.starhope.appius.user.GeneralUser
      extended by org.starhope.appius.user.AbstractNonPlayerCharacter
All Implemented Interfaces:
Serializable, Comparable<Object>, RoomListener, Collidable, HasVariables, AbstractUser, DataRecordBacked<UserRecord>, AcceptsMetronomeTicks, HasName
Direct Known Subclasses:
Plebeian, QuestItemExchanger

public abstract class AbstractNonPlayerCharacter
extends GeneralUser
implements AcceptsMetronomeTicks

This is the base class from which NPCs are derived.

Author:
brpocock@star-hope.org
See Also:
Serialized Form

Nested Class Summary
private  class AbstractNonPlayerCharacter.RealSpeakRunner
          WRITEME: Document this type.
 
Field Summary
protected  List<String> buddyList
          WRITEME
protected  Queue<String> casualSpeechQueue
          a queue of arbitrary things that Harmony might say, if she gets bored.
protected  long casualSpeechRate
          the rate at which speech is emitted
private  List<String> ignoreList
          WRITEME
protected  int instanceID
          WRITEME
protected  Kalendor kalendor
          Just fetch the Kalendor once, and keep working with it, rather than fucking around with fetching it every time.
protected  long lastActive
          WRITEME: Document this brpocock@star-hope.org
protected  long lastSpoken
          Time at which we last spoke
private static long serialVersionUID
          Java serialisation unique ID
 
Fields inherited from class org.starhope.appius.user.GeneralUser
baseDefenses, baseStats, collisionBounds, currentRoom, facing, lastUserMovement, location, pathFinder, target, travelStartTime, userRecord, userVariables
 
Constructor Summary
  AbstractNonPlayerCharacter(String login)
           
protected AbstractNonPlayerCharacter(UserRecord dataRecord)
          WRITEME
 
Method Summary
 void acceptErrorReply(String command, String error, org.json.JSONObject result, Room userCurrentRoomInZone)
           
 void acceptGameAction(AbstractUser u, org.json.JSONObject action)
          Broadcast message of a game action taking place
 void acceptGameStateChange(GameEvent gameCode, GameStateFlag gameState)
          Notification of a GameEvent changing state for the room
 void acceptMessage(String title, String label, String content)
          Accept an administrative/moderator message with the full range of options.
 void acceptPrivateMessage(AbstractUser speaker, String speech)
          Accept a private message from another user (a whisper)
 void acceptPublicMessage(AbstractUser sender, Room room, String message)
          Accept a public chat message or /emote.
 void acceptPublicMessage(AbstractUser from, String message)
          Accept a public chat message.
 void acceptSuccessReply(String command, org.json.JSONObject jsonData, Room room)
           
 void acceptUserList(String whichList, List<UserListEntry> users)
          WRITEME: Document this method brpocock@star-hope.org
 void addBuddy(AbstractUser buddy)
           
 void addGiftSubscription(int i, int days)
           
 void addItem(int itemID)
           
 boolean canTalk()
           
 void destroy()
          WRITEME
 void doTransport()
          WRITEME
 boolean equals(Object obj)
           
protected  Set<String> getAccessibleRooms()
          Get all rooms currently accessible from the present room, via normal doors.
 AvatarClass getAvatarClass()
           
 String getAvatarLabel()
          The avatar label is the text block that is displayed with the avatar for this object.
 Colour getBaseColor()
           
 Collection<String> getBuddyListNames()
          WRITEME: document this method (brpocock@star-hope.org, Jan 11, 2010)
 String getDebugName()
          Get a version of the user's ID and name suitable for use in debugging dumps.
static String getGreeting(String name)
          WRITEME brpocock@star-hope.org Jul 21, 2010
protected abstract  int getInstanceID()
           
 String getIPAddress()
           
 String getKickedMessage()
           
 long getLag()
           
 String getLanguage()
           
 Coord3D getLocation()
          Gets the current start coördinates
 String getMail()
           
 String getName()
          Return a user-visible, unique name for this class.
 Date getNameApprovedAt()
           
 Date getNameRequestedAt()
           
static String getNameStripped(String name)
           
 org.json.JSONObject getPublicInfo_new()
           
 ServerThread getServerThread()
           
 int hashCode()
           
 void inviteBuddy(AbstractUser newBuddy)
          Ask someone to be my friend
 boolean isBuddy(AbstractUser who)
           
 boolean isNPC()
          This is an overriding method.
 boolean isOnline()
          WRITEME: document this method (brpocock@star-hope.org, Oct 31, 2009)
 void kick(AbstractUser u, String kickReason, int duration)
           
 void liftBan(AbstractUser authority)
          remove a ban placed upon this user
 boolean needsParent()
          Kid accounts (under 13) require parental confirmation.
 void reportedToModeratorBy(AbstractUser u)
           
 void reportedToModeratorBy(AbstractUser u, String reason)
           
 void sendMigrate(AbstractZone refugeeZone)
          WRITEME: document this method (brpocock@star-hope.org, Jan 11, 2010)
 void sendOops()
          WRITEME
 void sendResponse(org.json.JSONObject result)
           
 void setLastActive()
          WRITEME
 void setMail(String email)
          WRITEME
 void setParent(Parent newParent)
          If this is a child account (per COPPA), then associate a parent record with it.
 void speak(Room room, String string)
           
 void speakCasually(String text)
           
 void tick(long currentTime, long deltaTime)
          This method is called periodically from the metronome thread.
 org.json.JSONObject toJSON()
           
 String toSFSXML()
          Deprecated. 
 String toString()
           
 long whenAtTarget(Runnable runnable)
          Perform some action when the current movement-target position has been reached
 
Methods inherited from class org.starhope.appius.user.GeneralUser
acceptObjectJoinRoom, acceptObjectPartRoom, acceptOutOfBandMessage, acceptUserAction, acceptUserVariableUpdate, assertLocationUnlocked, assertStaffLevel, attend, canApproveSelf, canBetaTest, canEnterChatZone, canEnterMenuZone, changeBaseDefenses, compareTo, deleteVariable, doffClothes, getAge, getAgeGroup, getApprovedDateString, getBaseDefenses, getBaseStat, getCenterOfMass, getCollisionBounds, getCurrentAction, getD, getDialect, getDisplayName, getEffectiveDefenses, getEndMovementTime, getExtraColor, getFacing, getGameEquipItems_JSON, getGameEquipItems, getHeight, getHouse, getInventory, getItemsByType, getItemsByType, getItemsByTypeAsArray, getKickedByUserID, getKickedReasonCode, getKickedUntil, getLocationForUpdate, getMass, getMoney, getPathFinder, getPublicInfo, getRegisteredAt, getRegisteredDate, getRegisteredDateString, getRequestedName, getResponsibleMail, getRoom, getRoomNumber, getSizeScalar, getStaffLevel, getStartMovementTime, getStartT, getStat, getTarget, getTravelRate, getTravelStart, getUserID, getUserListIterator, getUserName, getUserVariables, getVariable, getVariables, getVariablesJSON, getVelocity, getWallet, getZone, handleWalkFail, hasStaffLevel, hasVariable, ignore, isActive, isApproved, isBanned, isCanceled, isKicked, isPaidMember, local_publicInfo, purchase, removeBuddy, resetVariables, sendBuddyList, sendEarnings, sendWardrobe, setAgeGroupToSystem, setBackingRecord, setBaseColor, setCanTalk, setCenterOfMass, setCurrentAction, setExtraColor, setFacing, setLocation, setRoom, setStartT, setTarget, setTravelRate, setTravelStart, setVariable, setVariable, setVariables, setVelocity, takeAttack, unlockLocation, updateWallet
 
Methods inherited from class java.lang.Object
clone, finalize, getClass, notify, notifyAll, wait, wait, wait
 
Methods inherited from interface org.starhope.appius.user.AbstractUser
ban
 

Field Detail

serialVersionUID

private static final long serialVersionUID
Java serialisation unique ID

See Also:
Constant Field Values

kalendor

protected final Kalendor kalendor
Just fetch the Kalendor once, and keep working with it, rather than fucking around with fetching it every time.


instanceID

protected final int instanceID
WRITEME


lastActive

protected long lastActive
WRITEME: Document this brpocock@star-hope.org


buddyList

protected final List<String> buddyList
WRITEME


ignoreList

private final List<String> ignoreList
WRITEME


casualSpeechQueue

protected Queue<String> casualSpeechQueue
a queue of arbitrary things that Harmony might say, if she gets bored.


lastSpoken

protected long lastSpoken
Time at which we last spoke


casualSpeechRate

protected long casualSpeechRate
the rate at which speech is emitted

Constructor Detail

AbstractNonPlayerCharacter

public AbstractNonPlayerCharacter(String login)
                           throws NotFoundException,
                                  GameLogicException
Parameters:
login - the user login of the account for which this NPC should be instantiated.
Throws:
NotFoundException - if the user login given doesn't yield a valid data record
GameLogicException - if the user record isn't an NPC

AbstractNonPlayerCharacter

protected AbstractNonPlayerCharacter(UserRecord dataRecord)
                              throws GameLogicException
WRITEME

Parameters:
dataRecord - WRITEME
Throws:
GameLogicException - for hate
Method Detail

getGreeting

public static String getGreeting(String name)
WRITEME brpocock@star-hope.org Jul 21, 2010

Parameters:
name - whom to greet
Returns:
an “appropriate” greeting of some kind

getNameStripped

public static String getNameStripped(String name)
Parameters:
name - any user's name
Returns:
the name truncated to before the $ (if any)

acceptErrorReply

public void acceptErrorReply(String command,
                             String error,
                             org.json.JSONObject result,
                             Room userCurrentRoomInZone)
Specified by:
acceptErrorReply in interface AbstractUser
Parameters:
command - The command which produced the error
error - The error code
result - The additional JSON data describing the error
userCurrentRoomInZone - The room in which the user was standing when the error occurred.
See Also:
AbstractUser.acceptErrorReply(java.lang.String, java.lang.String, org.json.JSONObject, org.starhope.appius.game.Room)

acceptGameAction

public void acceptGameAction(AbstractUser u,
                             org.json.JSONObject action)
Description copied from interface: RoomListener
Broadcast message of a game action taking place

Specified by:
acceptGameAction in interface RoomListener
Parameters:
u - the sender
action - The game action. The verb is in action.getString("action").
See Also:
RoomListener.acceptGameAction(org.starhope.appius.user.AbstractUser, org.json.JSONObject)

acceptGameStateChange

public void acceptGameStateChange(GameEvent gameCode,
                                  GameStateFlag gameState)
Description copied from interface: RoomListener
Notification of a GameEvent changing state for the room

Specified by:
acceptGameStateChange in interface RoomListener
Parameters:
gameCode - The GameEvent whose state is changing
gameState - The new state
See Also:
RoomListener.acceptGameStateChange(org.starhope.appius.game.GameEvent, org.starhope.appius.game.GameStateFlag)

acceptMessage

public void acceptMessage(String title,
                          String label,
                          String content)
Description copied from interface: AbstractUser
Accept an administrative/moderator message with the full range of options. If the user is currently online, forward this message to them.

Specified by:
acceptMessage in interface AbstractUser
Parameters:
title - The title of the message
label - A label which nominally identifies the source of the message
content - The contents of the message
See Also:
AbstractUser.acceptMessage(java.lang.String, java.lang.String, java.lang.String)

acceptPrivateMessage

public void acceptPrivateMessage(AbstractUser speaker,
                                 String speech)
Description copied from interface: AbstractUser
Accept a private message from another user (a whisper)

Specified by:
acceptPrivateMessage in interface AbstractUser
Parameters:
speaker - the person whispering
speech - what was whispered
See Also:
AbstractUser.acceptPrivateMessage(org.starhope.appius.user.AbstractUser, java.lang.String)

acceptPublicMessage

public void acceptPublicMessage(AbstractUser sender,
                                Room room,
                                String message)
Description copied from interface: RoomListener
Accept a public chat message or /emote.

Specified by:
acceptPublicMessage in interface RoomListener
Parameters:
sender - The speaker
room - The room in which the words were spoken
message - The spoken text or /emote
See Also:
RoomListener.acceptPublicMessage(org.starhope.appius.user.AbstractUser, org.starhope.appius.game.Room, java.lang.String)

acceptPublicMessage

public void acceptPublicMessage(AbstractUser from,
                                String message)
Description copied from interface: RoomListener
Accept a public chat message. This prototype does not specify the room, on the (potentially invalid) assumption that the room listener doesn't care from which room the speech was made.

Specified by:
acceptPublicMessage in interface RoomListener
Parameters:
from - The speaker
message - The spoken text or /emote
See Also:
RoomListener.acceptPublicMessage(org.starhope.appius.user.AbstractUser, java.lang.String)

acceptSuccessReply

public void acceptSuccessReply(String command,
                               org.json.JSONObject jsonData,
                               Room room)
Specified by:
acceptSuccessReply in interface AbstractUser
Parameters:
command - WRITEME
jsonData - WRITEME
room - WRITEME
See Also:
AbstractUser.acceptSuccessReply(java.lang.String, org.json.JSONObject, org.starhope.appius.game.Room)

acceptUserList

public void acceptUserList(String whichList,
                           List<UserListEntry> users)
WRITEME: Document this method brpocock@star-hope.org

Parameters:
whichList - WRITEME
users - WRITEME

addBuddy

public void addBuddy(AbstractUser buddy)
Specified by:
addBuddy in interface AbstractUser
Overrides:
addBuddy in class GeneralUser
Parameters:
buddy - WRITEME
See Also:
GeneralUser.addBuddy(org.starhope.appius.user.AbstractUser)

addGiftSubscription

public void addGiftSubscription(int i,
                                int days)
Specified by:
addGiftSubscription in interface AbstractUser
Parameters:
i - WRITEME
days - WRITEME
See Also:
AbstractUser.addGiftSubscription(int, int)

addItem

public void addItem(int itemID)
Specified by:
addItem in interface AbstractUser
Parameters:
itemID - the item ID to be instantiated and added
See Also:
AbstractUser.addItem(int)

canTalk

public boolean canTalk()
Specified by:
canTalk in interface AbstractUser
Returns:
WRITEME
See Also:
AbstractUser.canTalk()

destroy

public void destroy()
WRITEME


doTransport

public void doTransport()
Description copied from interface: AbstractUser
WRITEME

Specified by:
doTransport in interface AbstractUser
See Also:
AbstractUser.doTransport()

equals

public boolean equals(Object obj)
Overrides:
equals in class GeneralUser
See Also:
Object.equals(java.lang.Object)

getAccessibleRooms

protected Set<String> getAccessibleRooms()
Get all rooms currently accessible from the present room, via normal doors.

Returns:
the set of all rooms potentially accessible

getAvatarClass

public AvatarClass getAvatarClass()
Specified by:
getAvatarClass in interface AbstractUser
Returns:
WRITEME
See Also:
AbstractUser.getAvatarClass()

getAvatarLabel

public String getAvatarLabel()
Description copied from interface: AbstractUser
The avatar label is the text block that is displayed with the avatar for this object. It should be unique but isn't guaranteed to be distinct as user names are. (At any given moment, there can be only one object with a given avatar label in the room, but there can be only one user with a given name in the multiverse.) For users, this is the user name.

Specified by:
getAvatarLabel in interface AbstractUser
Returns:
The avatar label
See Also:
AbstractUser.getAvatarLabel()

getBaseColor

public Colour getBaseColor()
Specified by:
getBaseColor in interface AbstractUser
Returns:
base colour
See Also:
AbstractUser.getBaseColor()

getBuddyListNames

public Collection<String> getBuddyListNames()
Description copied from interface: AbstractUser
WRITEME: document this method (brpocock@star-hope.org, Jan 11, 2010)

Specified by:
getBuddyListNames in interface AbstractUser
Returns:
WRITEME
See Also:
AbstractUser.getBuddyListNames()

getDebugName

public String getDebugName()
Description copied from interface: AbstractUser
Get a version of the user's ID and name suitable for use in debugging dumps. The format is: “LOGIN” #ID — e.g. "“Pil” #2". Note the use of typographically correct quotation marks

Specified by:
getDebugName in interface AbstractUser
Returns:
A string with the user's login string and user ID number, formatted for debugging output
See Also:
AbstractUser.getDebugName()

getInstanceID

protected abstract int getInstanceID()
Returns:
An unique ID for this instance of

getIPAddress

public String getIPAddress()
Specified by:
getIPAddress in interface AbstractUser
Returns:
WRITEME
See Also:
AbstractUser.getIPAddress()

getKickedMessage

public String getKickedMessage()
Specified by:
getKickedMessage in interface AbstractUser
Returns:
WRITEME
See Also:
AbstractUser.getKickedMessage()

getLag

public long getLag()
Specified by:
getLag in interface AbstractUser
Returns:
round-trip lag time
See Also:
AbstractUser.getLag()

getLanguage

public String getLanguage()
Specified by:
getLanguage in interface AbstractUser
Returns:
WRITEME
See Also:
AbstractUser.getLanguage()

getLocation

public Coord3D getLocation()
Description copied from interface: AbstractUser
Gets the current start coördinates

Specified by:
getLocation in interface AbstractUser
Returns:
the location at which the user was located at AbstractUser.getTravelStart()
See Also:
AbstractUser.getLocation()

getMail

public String getMail()
Specified by:
getMail in interface AbstractUser
Returns:
WRITEME
See Also:
AbstractUser.getMail()

getName

public String getName()
Description copied from interface: HasName
Return a user-visible, unique name for this class. This name may not necessarily be globally unique, but must be unique across all objects of this class. For example, having both a User and a Zone named “Lightning” is acceptable, but there may not be two users with the same name.

Specified by:
getName in interface HasName
Returns:
a user-visible string name for this instance
See Also:
HasName.getName()

getNameApprovedAt

public Date getNameApprovedAt()
Specified by:
getNameApprovedAt in interface AbstractUser
Returns:
WRITEME
See Also:
AbstractUser.getNameApprovedAt()

getNameRequestedAt

public Date getNameRequestedAt()
Specified by:
getNameRequestedAt in interface AbstractUser
Returns:
WRITEME
See Also:
AbstractUser.getNameRequestedAt()

getPublicInfo_new

public org.json.JSONObject getPublicInfo_new()
Returns:
WRITEME
See Also:
AbstractUser.getPublicInfo()

getServerThread

public ServerThread getServerThread()
Specified by:
getServerThread in interface AbstractUser
Returns:
WRITEME
See Also:
AbstractUser.getServerThread()

hashCode

public int hashCode()
Overrides:
hashCode in class GeneralUser
See Also:
Object.hashCode()

inviteBuddy

public void inviteBuddy(AbstractUser newBuddy)
Ask someone to be my friend

Parameters:
newBuddy - that special someone

isBuddy

public boolean isBuddy(AbstractUser who)
Parameters:
who - someone who might be my friend
Returns:
true, if they're on my buddy list

isNPC

public boolean isNPC()
This is an overriding method.

Specified by:
isNPC in interface AbstractUser
Returns:
WRITEME
See Also:
AbstractUser.isNPC()

isOnline

public boolean isOnline()
Description copied from interface: AbstractUser
WRITEME: document this method (brpocock@star-hope.org, Oct 31, 2009)

Specified by:
isOnline in interface AbstractUser
Returns:
WRITEME
See Also:
AbstractUser.isOnline()

kick

public void kick(AbstractUser u,
                 String kickReason,
                 int duration)
          throws PrivilegeRequiredException
Specified by:
kick in interface AbstractUser
Parameters:
u - WRITEME
kickReason - WRITEME
duration - WRITEME
Throws:
PrivilegeRequiredException - WRITEME
See Also:
AbstractUser.kick(org.starhope.appius.user.AbstractUser, java.lang.String, int)

liftBan

public void liftBan(AbstractUser authority)
             throws PrivilegeRequiredException
Description copied from interface: AbstractUser
remove a ban placed upon this user

Specified by:
liftBan in interface AbstractUser
Parameters:
authority - WRITEME
Throws:
PrivilegeRequiredException - WRITEME
See Also:
AbstractUser.liftBan(org.starhope.appius.user.AbstractUser)

needsParent

public boolean needsParent()
Description copied from class: GeneralUser
Kid accounts (under 13) require parental confirmation. In order to get that, we have to get a parental contact. If this field is false, then the user is either a teenager or adult, or they have a parent on file. It does not mean that they have had their account approved: only that they have given us the parental information (if we needed it). If we ever encounter a user for whom this flag is true, ask them “who's your daddy?”

Specified by:
needsParent in interface AbstractUser
Overrides:
needsParent in class GeneralUser
Returns:
true, if this is a kid account without a known parent (yet)
See Also:
AbstractUser.needsParent()

reportedToModeratorBy

public void reportedToModeratorBy(AbstractUser u)
Specified by:
reportedToModeratorBy in interface AbstractUser
Parameters:
u - WRITEME
See Also:
AbstractUser.reportedToModeratorBy(org.starhope.appius.user.AbstractUser)

reportedToModeratorBy

public void reportedToModeratorBy(AbstractUser u,
                                  String reason)
Specified by:
reportedToModeratorBy in interface AbstractUser
Parameters:
u - WRITEME
reason - WRITEME
See Also:
AbstractUser.reportedToModeratorBy(org.starhope.appius.user.AbstractUser, java.lang.String)

sendMigrate

public void sendMigrate(AbstractZone refugeeZone)
                 throws UserDeadException
Description copied from interface: AbstractUser
WRITEME: document this method (brpocock@star-hope.org, Jan 11, 2010)

Specified by:
sendMigrate in interface AbstractUser
Parameters:
refugeeZone - WRITEME
Throws:
UserDeadException - WRITEME
See Also:
AbstractUser.sendMigrate(org.starhope.appius.types.AbstractZone)

sendOops

public void sendOops()
Description copied from interface: AbstractUser
WRITEME

Specified by:
sendOops in interface AbstractUser
See Also:
AbstractUser.sendOops()

sendResponse

public void sendResponse(org.json.JSONObject result)
Specified by:
sendResponse in interface AbstractUser
Parameters:
result - WRITEME
See Also:
AbstractUser.sendResponse(org.json.JSONObject)

setLastActive

public void setLastActive()
Description copied from interface: AbstractUser
WRITEME

Specified by:
setLastActive in interface AbstractUser
See Also:
AbstractUser.setLastActive()

setMail

public void setMail(String email)
             throws GameLogicException
Description copied from interface: AbstractUser
WRITEME

Specified by:
setMail in interface AbstractUser
Parameters:
email - WRITEME
Throws:
GameLogicException - WRITEME
See Also:
AbstractUser.setMail(java.lang.String)

setParent

public void setParent(Parent newParent)
               throws GameLogicException,
                      ForbiddenUserException,
                      AlreadyExistsException
Description copied from interface: AbstractUser
If this is a child account (per COPPA), then associate a parent record with it. Affiliated with Parent class and AbstractUser.needsParent()

Specified by:
setParent in interface AbstractUser
Parameters:
newParent - the new parent record to associate with this user
Throws:
GameLogicException - if this user account does not need a parent record (adult account or system/robot account)
ForbiddenUserException - if the parent is not allowed to register/associate new child accounts (usually due to having other child accounts which are banned)
AlreadyExistsException - if the parent account has the maximum allowed children.
See Also:
AbstractUser.setParent(org.starhope.appius.user.Parent)

speak

public void speak(Room room,
                  String string)
Specified by:
speak in interface AbstractUser
Parameters:
room - the room in which to speak. Typically, the user must be present in that room.
string - the speech (or emote)
See Also:
AbstractUser.speak(org.starhope.appius.game.Room, java.lang.String)

speakCasually

public void speakCasually(String text)
Parameters:
text - WRITEME

tick

public void tick(long currentTime,
                 long deltaTime)
          throws UserDeadException
Description copied from interface: AcceptsMetronomeTicks
This method is called periodically from the metronome thread. To save computation, it receives both the current time since epoch in milliseconds at the start of the global tick propagation, and the delta time since the previous metronome tick.

Specified by:
tick in interface AcceptsMetronomeTicks
Parameters:
currentTime - Time since epoch at the start of the global metronome propagation, as per System.currentTimeMillis()
deltaTime - Delta-time in milliseconds since the prior global metronome tick
Throws:
UserDeadException - if a user has died during this tick
See Also:
AcceptsMetronomeTicks.tick(long, long)

toJSON

public org.json.JSONObject toJSON()
Specified by:
toJSON in interface AbstractUser
Returns:
a JavaScript Object representing this user
See Also:
AbstractUser.toJSON()

toSFSXML

@Deprecated
public String toSFSXML()
Deprecated. 

Specified by:
toSFSXML in interface AbstractUser
Returns:
a string representing Smart Fox Server Pro style of XML data
See Also:
AbstractUser.toSFSXML()

toString

public String toString()
Overrides:
toString in class Object
See Also:
Object.toString()

whenAtTarget

public long whenAtTarget(Runnable runnable)
Perform some action when the current movement-target position has been reached

Parameters:
runnable - what to do when the target position is (or at least, should have been) reached
Returns:
the handle to the event, in case it's needed to cancel it
See Also:
Kalendor.schedule(long, Runnable), Kalendor.cancel(long), Geometry.getTimeToTarget(AbstractUser, long)