Bugfix: Wandering NPCs no longer ghost through the player.
Bugfix: Wandering NPCs no longer ghost through the player.

package com.dryerzinia.pokemon; package com.dryerzinia.pokemon;
/* /*
By: ??? By: ???
TODO: TODO:
Write CMD line args parser Write CMD line args parser
Add port for remote control window via network Add port for remote control window via network
Add a CMD line option to open a control window Add a CMD line option to open a control window
In control window enable observer mode In control window enable observer mode
*/ */
import java.io.EOFException; import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; import java.io.ObjectOutputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.BindException; import java.net.BindException;
import java.net.DatagramPacket; import java.net.DatagramPacket;
import java.net.DatagramSocket; import java.net.DatagramSocket;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.net.SocketException; import java.net.SocketException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
  import java.util.Iterator;
  import java.util.Map.Entry;
import java.util.Timer; import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
import java.util.Map.Entry;  
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import com.dryerzinia.pokemon.map.Direction; import com.dryerzinia.pokemon.map.Direction;
  import com.dryerzinia.pokemon.map.Level;
import com.dryerzinia.pokemon.map.Pose; import com.dryerzinia.pokemon.map.Pose;
import com.dryerzinia.pokemon.net.ByteInputStream; import com.dryerzinia.pokemon.net.ByteInputStream;
import com.dryerzinia.pokemon.net.DatagramSocketStreamer; import com.dryerzinia.pokemon.net.DatagramSocketStreamer;
import com.dryerzinia.pokemon.net.Streamer; import com.dryerzinia.pokemon.net.Streamer;
import com.dryerzinia.pokemon.net.TCPStreamer; import com.dryerzinia.pokemon.net.TCPStreamer;
import com.dryerzinia.pokemon.net.msg.client.CMLoad; import com.dryerzinia.pokemon.net.msg.client.CMLoad;
import com.dryerzinia.pokemon.net.msg.client.ClientMessage; import com.dryerzinia.pokemon.net.msg.client.ClientMessage;
import com.dryerzinia.pokemon.net.msg.client.MessageClientMessage; import com.dryerzinia.pokemon.net.msg.client.MessageClientMessage;
import com.dryerzinia.pokemon.net.msg.client.PlayerInfo; import com.dryerzinia.pokemon.net.msg.client.PlayerInfo;
import com.dryerzinia.pokemon.net.msg.client.PlayerMovement; import com.dryerzinia.pokemon.net.msg.client.PlayerMovement;
import com.dryerzinia.pokemon.net.msg.client.act.SendActMovedClientMessage; import com.dryerzinia.pokemon.net.msg.client.act.SendActMovedClientMessage;
import com.dryerzinia.pokemon.net.msg.client.act.SendActTalkingToClientMessage;  
import com.dryerzinia.pokemon.net.msg.client.act.SendPerson;  
import com.dryerzinia.pokemon.net.msg.client.fight.SendFightClientMessage; import com.dryerzinia.pokemon.net.msg.client.fight.SendFightClientMessage;
import com.dryerzinia.pokemon.net.msg.server.ServerMessage; import com.dryerzinia.pokemon.net.msg.server.ServerMessage;
import com.dryerzinia.pokemon.obj.Actor;  
import com.dryerzinia.pokemon.obj.GameState; import com.dryerzinia.pokemon.obj.GameState;
  import com.dryerzinia.pokemon.obj.Player;
import com.dryerzinia.pokemon.obj.tiles.Person; import com.dryerzinia.pokemon.obj.tiles.Person;
import com.dryerzinia.pokemon.obj.Player;  
import com.dryerzinia.pokemon.ui.Fight; import com.dryerzinia.pokemon.ui.Fight;
import com.dryerzinia.pokemon.util.Database; import com.dryerzinia.pokemon.util.Database;
import com.dryerzinia.pokemon.util.ResourceLoader; import com.dryerzinia.pokemon.util.ResourceLoader;
public class PokemonServer { public class PokemonServer {
/* /*
* Number for Manhattan distances * Number for Manhattan distances
* 14 Max distance at which fights can be initiated * 14 Max distance at which fights can be initiated
* 50 Max distance at which people can hear each other in chat without whispering * 50 Max distance at which people can hear each other in chat without whispering
* 16 Distance at which other players and actors movements are no longer being told * 16 Distance at which other players and actors movements are no longer being told
* 14 Distance at which other players and actors movements start being told * 14 Distance at which other players and actors movements start being told
* 2 width of the transition zone where clients are told either that a player is * 2 width of the transition zone where clients are told either that a player is
* coming into view or a player is going out of view * coming into view or a player is going out of view
* [16-14) going out of view * [16-14) going out of view
* [14-12) Coming into view * [14-12) Coming into view
* *
* TODO move values to configuration file * TODO move values to configuration file
*/ */
public static final int FIGHT_DISTANCE = 14; public static final int FIGHT_DISTANCE = 14;
public static final int TALK_DISTANCE = 50; public static final int TALK_DISTANCE = 50;
public static final int FOG_OF_WAR = 16; public static final int FOG_OF_WAR = 16;
public static final int VISIBLE_DISTANCE = 14; public static final int VISIBLE_DISTANCE = 14;
public static final int TRANSITION_ZONE = 2; public static final int TRANSITION_ZONE = 2;
// TODO possibly multiple ports with per port mode settings in file // TODO possibly multiple ports with per port mode settings in file
public static final int PORT_NUM = 53879; public static final int PORT_NUM = 53879;
public static final int CM_TCP = 0; public static final int CM_TCP = 0;
public static final int CM_DATAGRAM = 1; public static final int CM_DATAGRAM = 1;
public static final int CM_ALL = 2; public static final int CM_ALL = 2;
private static int connectMode = CM_ALL; private static int connectMode = CM_ALL;
public static PokemonServer pokes; public static PokemonServer pokes;
ServerSocket ssock; ServerSocket ssock;
public static ConcurrentHashMap<Integer, PlayerInstanceData> players = new ConcurrentHashMap<Integer, PlayerInstanceData>(); public static ConcurrentHashMap<Integer, PlayerInstanceData> players = new ConcurrentHashMap<Integer, PlayerInstanceData>();
int playeridcount = 0; int playeridcount = 0;
ArrayList<ObjectOutputStream> oos2; ArrayList<ObjectOutputStream> oos2;
Timer server_tasks; Timer server_tasks;
/** /**
* Entry point for Pokemon game server * Entry point for Pokemon game server
* @param args * @param args
*/ */
public static void main(String args[]) { public static void main(String args[]) {
new PokemonServer(); new PokemonServer();
} }
public PokemonServer() { public PokemonServer() {
oos2 = new ArrayList<ObjectOutputStream>(); oos2 = new ArrayList<ObjectOutputStream>();
// We have to pretend to have a head for the Pokemon // We have to pretend to have a head for the Pokemon
// Game instance to be created // Game instance to be created
System.setProperty("java.awt.headless", "false"); System.setProperty("java.awt.headless", "false");
// Probably do some other thing for this singleton // Probably do some other thing for this singleton
pokes = this; pokes = this;
// Don't need to load images for headless server // Don't need to load images for headless server
ResourceLoader.setDoLoad(false); ResourceLoader.setDoLoad(false);
// Game Instance Data // Game Instance Data
GameState.init(); GameState.init();
// Load Actors // Load Actors
GameState.loadActors("Actors.json"); GameState.loadActors("Actors.json");
System.out.println("Game World Instace Created"); System.out.println("Game World Instace Created");
server_tasks = new Timer(); server_tasks = new Timer();
server_tasks.schedule(new ActTask(), 0, 250); server_tasks.schedule(new ActTask(), 0, 250);
server_tasks.scheduleAtFixedRate(new SaveAllTask(), 0, 120000); server_tasks.scheduleAtFixedRate(new SaveAllTask(), 0, 120000);
server_tasks.scheduleAtFixedRate(new KickInactiveTask(), 0, 30000); server_tasks.scheduleAtFixedRate(new KickInactiveTask(), 0, 30000);
listen(); listen();
} }
/** /**
* Saves all of the information of connected players every 2 minutes * Saves all of the information of connected players every 2 minutes
* in case server crashes * in case server crashes
*/ */
public class SaveAllTask extends TimerTask { public class SaveAllTask extends TimerTask {
public void run() { public void run() {
for (PlayerInstanceData pid : players.values()) for (PlayerInstanceData pid : players.values())
Database.savePlayerData(pid.getPlayer()); Database.savePlayerData(pid.getPlayer());
} }
} }
/** /**
* Kicks any players who we have not received a message from in the last * Kicks any players who we have not received a message from in the last
* 45 seconds. Player should send pings every 15 seconds to insure they * 45 seconds. Player should send pings every 15 seconds to insure they
* stay connected. This helps remove UDP Clients who have disconnected * stay connected. This helps remove UDP Clients who have disconnected
* without saying anything. This takes runs once every 30 seconds so the * without saying anything. This takes runs once every 30 seconds so the
* longest a player can be disconnected and not removed is 1:15 * longest a player can be disconnected and not removed is 1:15
*/ */
public class KickInactiveTask extends TimerTask { public class KickInactiveTask extends TimerTask {
public void run() { public void run() {
kickInactive(); kickInactive();
} }
} }
/** /**
* Removes players who have not sent a message in the last 45 seconds * Removes players who have not sent a message in the last 45 seconds
*/ */
public synchronized void kickInactive() { public synchronized void kickInactive() {
for(Entry<Integer, PlayerInstanceData> pidEntry : players.entrySet()) { for(Entry<Integer, PlayerInstanceData> pidEntry : players.entrySet()) {
PlayerInstanceData pid = pidEntry.getValue(); PlayerInstanceData pid = pidEntry.getValue();
/* Players who have not send a message in the last 45 seconds /* Players who have not send a message in the last 45 seconds
* Are removed from the game, They should ping at least once * Are removed from the game, They should ping at least once
* every 30 seconds to show they are Connected particularly * every 30 seconds to show they are Connected particularly
* for UDP connections this is important. * for UDP connections this is important.
*/ */
if (!pid.hasMessageLast45()) { if (!pid.hasMessageLast45()) {
System.out.println("Player " + pid.getPlayer().getName() System.out.println("Player " + pid.getPlayer().getName()
+ " not responsive"); + " not responsive");
Database.savePlayerData(pid.getPlayer()); Database.savePlayerData(pid.getPlayer());
// Remove PlayerInstanceData from server // Remove PlayerInstanceData from server
players.remove(pidEntry.getKey()); players.remove(pidEntry.getKey());
// TODO Proper disconnect and killing of all threads // TODO Proper disconnect and killing of all threads
System.out.println("Player kicked!"); System.out.println("Player kicked!");
} }
} }
} }
/** /**
* Runs AI for all Actors in the game world and updates players near them * Runs AI for all Actors in the game world and updates players near them
* of their actions. AI runs ~4 times per second. * of their actions. AI runs ~4 times per second.
*/ */
public class ActTask extends TimerTask { public class ActTask extends TimerTask {
public void run() { public void run() {
for(Person person: GameState.people.values()) for(Person person: GameState.people.values())
sendPlayerActorUpdate(person, person.act()); sendPlayerActorUpdate(person, person.act());
} }
} }
/** /**
* Synchronized because PlayerInstanceData iteration * Synchronized because PlayerInstanceData iteration
* @param person Actor that changed and needs to be updated * @param person Actor that changed and needs to be updated
* TODO all actors are persons??? * TODO all actors are persons???
*/ */
public synchronized static void sendPlayerActorUpdate(Person person, boolean changed){ public synchronized static void sendPlayerActorUpdate(Person person, boolean changed){
// TODO PER level search // TODO PER level search
for(PlayerInstanceData pid : players.values()) { for(PlayerInstanceData pid : players.values()) {
if(VISIBLE_DISTANCE > GameState.getMap().manhattanDistance(pid.getPlayer().getPose(), person.getPose())) if(VISIBLE_DISTANCE > GameState.getMap().manhattanDistance(pid.getPlayer().getPose(), person.getPose()))
try { try {
if(changed){ if(changed){
pid.sendActor(person, Person.A_MOVED); pid.sendActor(person, Person.A_MOVED);
} }
} catch (IOException ioe) { } catch (IOException ioe) {
System.err.println("Could not send actor update to player: " + ioe.getMessage()); System.err.println("Could not send actor update to player: " + ioe.getMessage());
// TODO likely cause client is disconnected we should probably remove them here // TODO likely cause client is disconnected we should probably remove them here
} }
} }
} }
/** /**
* TODO figure out what the fuck this is for * Return true if the given tile is occupied by any player.
* @param x * @param tileX
* @param y * @param tileY
* @param level * @param levelId
* @return */
*/ public synchronized static boolean isPlayerAtTile(
public synchronized static boolean isPlayer(int x, int y, int level) { int tileX, int tileY, int levelId) {
for(PlayerInstanceData pid : players.values()) {  
Player player = pid.getPlayer(); Level level = GameState.getMap().getLevel(levelId);
if(player.getPose().getX() + 4 == x Iterator<Player> players = level.nearbyPlayerIterator();
&& player.getPose().getY() + 4 == y  
&& player.getPose().getLevel() == level) while (players.hasNext()) {
return true; Player player = players.next();
} Pose playerPose = player.getPose();
   
  int playerX = (int) playerPose.getX();
  int playerY = (int) playerPose.getY();
  int playerLvl = playerPose.getLevel();
   
  if (playerX == tileX && playerY == tileY && playerLvl == levelId) {
  return true;
  }
  }
   
return false; return false;
} }
/** /**
* Binds TCP to the server socket and starts accepting * Binds TCP to the server socket and starts accepting
* connections from clients * connections from clients
*/ */
public void startTCPListen() { public void startTCPListen() {
try { try {
ssock = new ServerSocket(); ssock = new ServerSocket();
ssock.bind(new InetSocketAddress(PORT_NUM)); ssock.bind(new InetSocketAddress(PORT_NUM));
(new TCPListener()).start(); (new TCPListener()).start();
} catch (BindException be) { } catch (BindException be) {
System.err.println("Unable to bind to port: " + be.getMessage()); System.err.println("Unable to bind to port: " + be.getMessage());
System.err.println("Not listening on TCP!"); System.err.println("Not listening on TCP!");
} catch (IOException ioe){ } catch (IOException ioe){
ioe.printStackTrace(); ioe.printStackTrace();
} }
} }
/** /**
* Binds UDP to the Server Socket and starts listening for * Binds UDP to the Server Socket and starts listening for
* packets from clients * packets from clients
*/ */
public void startDatagramListen() { public void startDatagramListen() {
try { try {
(new DatagramListener(new DatagramSocket(PORT_NUM))).start(); (new DatagramListener(new DatagramSocket(PORT_NUM))).start();
} catch (SocketException se) { } catch (SocketException se) {
System.err.println("Could not attach to UDP Socket: " + se.getMessage()); System.err.println("Could not attach to UDP Socket: " + se.getMessage());
System.err.println("Not listening on UDP!"); System.err.println("Not listening on UDP!");
} }
} }
/** /**
* Thread for communicating with Client * Thread for communicating with Client
*/ */
public class MessageListener extends Thread { public class MessageListener extends Thread {
InputStream is; InputStream is;
OutputStream os; OutputStream os;
Streamer streamer; Streamer streamer;
PlayerInstanceData pid; PlayerInstanceData pid;
boolean kill = false; boolean kill = false;
public MessageListener(Streamer streamer, PlayerInstanceData pid) { public MessageListener(Streamer streamer, PlayerInstanceData pid) {
this.streamer = streamer; this.streamer = streamer;
try { try {
this.is = streamer.getInputStream(); this.is = streamer.getInputStream();
this.os = streamer.getOutputStream(); this.os = streamer.getOutputStream();
} catch (IOException ioe) { } catch (IOException ioe) {
System.err.println("Could not open Stream to/from client."); System.err.println("Could not open Stream to/from client.");
} }
this.pid = pid; this.pid = pid;
} }
/** /**
* Closes the socket and ends this thread * Closes the socket and ends this thread
*/ */
public void stop_listening(){ public void stop_listening(){
try { try {
streamer.close(); streamer.close();
} catch(IOException ioe){ } catch(IOException ioe){
System.err.println("Unable to close listening thread: " + ioe.getMessage()); System.err.println("Unable to close listening thread: " + ioe.getMessage());
} }
} }
/** /**
* Run loop for listening to messages from client and processing them * Run loop for listening to messages from client and processing them
*/ */
public void run() { public void run() {
try (ObjectInputStream ois = new ObjectInputStream(is)) { try (ObjectInputStream ois = new ObjectInputStream(is)) {
while(true){ while(true){
ServerMessage receivedMessage = (ServerMessage) ois.readObject(); ServerMessage receivedMessage = (ServerMessage) ois.readObject();
pid.recivedMessage(); pid.recivedMessage();
receivedMessage.proccess(ois, pid); receivedMessage.proccess(ois, pid);
} }
} catch(SocketException se) { } catch(SocketException se) {
// Safe disconnect should be an socket close interupt // Safe disconnect should be an socket close interupt
} catch (EOFException eofe) { } catch (EOFException eofe) {
System.out.println("EOF Disconnect, thats not very nice!"); System.out.println("EOF Disconnect, thats not very nice!");
} catch (IOException ioe) { } catch (IOException ioe) {
System.err.println("IOException occured!"); System.err.println("IOException occured!");
System.err.println("Client " + pid.getPlayer().getName() + "disconnected!"); System.err.println("Client " + pid.getPlayer().getName() + "disconnected!");
ioe.printStackTrace(); ioe.printStackTrace();
} catch (ClassNotFoundException cnfe) { } catch (ClassNotFoundException cnfe) {
System.err.println("Received unknown message from Client:"); System.err.println("Received unknown message from Client:");
cnfe.printStackTrace(); cnfe.printStackTrace();
} finally { } finally {
System.out.println("Client " + pid.getPlayer().getName() + " disconnected"); System.out.println("Client " + pid.getPlayer().getName() + " disconnected");
// Remove player from list of connected players // Remove player from list of connected players
if (pid.isLoggedIn()) if (pid.isLoggedIn())
// Save player // Save player
remove(pid); remove(pid);
else else
// Don't save anything for players who never logged in successfully // Don't save anything for players who never logged in successfully
removeNoSave(pid); removeNoSave(pid);
} }
} }
} }
/** /**
* This thread waits for a socket connections on TCP * This thread waits for a socket connections on TCP
* then splits off a new socket acceptor and starts handling * then splits off a new socket acceptor and starts handling
* messages from the client * messages from the client
*/ */
public class TCPListener extends Thread { public class TCPListener extends Thread {
Streamer streamer; Streamer streamer;
public TCPListener() { public TCPListener() {
} }
public void run() { public void run() {
try { try {
Socket sock = ssock.accept(); Socket sock = ssock.accept();
Thread tcp_client_listener = new TCPListener(); Thread tcp_client_listener = new TCPListener();
tcp_client_listener.start(); tcp_client_listener.start();
streamer = new TCPStreamer(sock); streamer = new TCPStreamer(sock);
try { try {
/* Create's new player instance data and sets a player object /* Create's new player instance data and sets a player object
* for it and the output stream to send messages on * for it and the output stream to send messages on
*/ */
PlayerInstanceData pid = new PlayerInstanceData(); PlayerInstanceData pid = new PlayerInstanceData();
pid.setPlayer(getNextPlayer()); pid.setPlayer(getNextPlayer());
pid.setOutputStream(new ObjectOutputStream(streamer.getOutputStream())); pid.setOutputStream(new ObjectOutputStream(streamer.getOutputStream()));
/* Starts listening for messages from the client /* Starts listening for messages from the client
*/ */
MessageListener message_listener = new MessageListener(streamer, pid); MessageListener message_listener = new MessageListener(streamer, pid);
message_listener.start(); message_listener.start();
/* sets a reference to the message listener so it can be /* sets a reference to the message listener so it can be
* killed when we need to remove this player * killed when we need to remove this player
*/ */
pid.setListener(message_listener); pid.setListener(message_listener);
} catch (IOException ioe) { } catch (IOException ioe) {
/* We likely lost connection to player during accept /* We likely lost connection to player during accept
* player is added during login messages so no need to * player is added during login messages so no need to
* clean player up * clean player up
*/ */
System.err.println("Failed to open streams to new client: " + ioe.getMessage()); System.err.println("Failed to open streams to new client: " + ioe.getMessage());
} }
} catch(IOException ioe){ } catch(IOException ioe){
System.err.println("Error occured while waiting for connection."); System.err.println("Error occured while waiting for connection.");
System.err.println("We are no longer listening on TCP."); System.err.println("We are no longer listening on TCP.");
} catch(SecurityException se){ } catch(SecurityException se){
System.err.println("Not allowed to accept on this socket."); System.err.println("Not allowed to accept on this socket.");
System.err.println("We are no longer listening on TCP."); System.err.println("We are no longer listening on TCP.");
} }
} }
} }
/** /**
* Thread listens for datagram packets and routes them to the * Thread listens for datagram packets and routes them to the
* ObjectInputStream of the appropriate client * ObjectInputStream of the appropriate client
* TODO clients can easily hijack other datagram clients connections * TODO clients can easily hijack other datagram clients connections
* crashing them. Add some kind of authentication * crashing them. Add some kind of authentication
*/ */
public class DatagramListener extends Thread { public class DatagramListener extends Thread {
/* Socket to listen for UPD packets on /* Socket to listen for UPD packets on
* TODO why public? * TODO why public?
*/ */
public DatagramSocket ds; public DatagramSocket ds;
/* HashMap of connected clients for routing incoming packets /* HashMap of connected clients for routing incoming packets
*/ */
private HashMap<Integer, DatagramSocketStreamer> dss = new HashMap<Integer, DatagramSocketStreamer>(); private HashMap<Integer, DatagramSocketStreamer> dss = new HashMap<Integer, DatagramSocketStreamer>();
public DatagramListener(DatagramSocket ds) { public DatagramListener(DatagramSocket ds) {
this.ds = ds; this.ds = ds;
} }
public void run() { public void run() {
DatagramPacket dp = new DatagramPacket(new byte[10000], 10000); DatagramPacket dp = new DatagramPacket(new byte[10000], 10000);
while(true) { while(true) {
try { try {
ds.receive(dp); ds.receive(dp);
try (ByteInputStream bis = new ByteInputStream(dp.getData())) { try (ByteInputStream bis = new ByteInputStream(dp.getData())) {
int id = bis.readInt(); int id = bis.readInt();
int len = bis.readInt(); int len = bis.readInt();
byte[] data = new byte[len]; byte[] data = new byte[len];
for (int i = 0; i < len; i++) for (int i = 0; i < len; i++)
data[i] = (byte) bis.read(); data[i] = (byte) bis.read();
DatagramSocketStreamer dssi = dss.get(new Integer(id)); DatagramSocketStreamer dssi = dss.get(new Integer(id));
if (dssi == null) { if (dssi == null) {
InetAddress from = dp.getAddress(); InetAddress from = dp.getAddress();
int fport = dp.getPort(); int fport = dp.getPort();
Player p = getNextPlayer(); Player p = getNextPlayer();
int id2 = p.getID(); int id2 = p.getID();
PlayerInstanceData pid = new PlayerInstanceData(); PlayerInstanceData pid = new PlayerInstanceData();
pid.setPlayer(p); pid.setPlayer(p);
dssi = new DatagramSocketStreamer(ds, dssi = new DatagramSocketStreamer(ds,
new InetSocketAddress(from, fport), id2); new InetSocketAddress(from, fport), id2);
ObjectOutputStream oos = new ObjectOutputStream(dssi.getOutputStream()); ObjectOutputStream oos = new ObjectOutputStream(dssi.getOutputStream());
pid.setOutputStream(oos); pid.setOutputStream(oos);
pid.setSockID(id2); pid.setSockID(id2);
sendID(dssi.getID(), oos); sendID(dssi.getID(), oos);
MessageListener message_listener = new MessageListener(dssi, pid); MessageListener message_listener = new MessageListener(dssi, pid);
message_listener.start(); message_listener.start();
pid.setListener(message_listener); pid.setListener(message_listener);
dss.put(new Integer(id2), dssi); dss.put(new Integer(id2), dssi);
} else { } else {
dssi.addToByteArray(data); dssi.addToByteArray(data);
} }
} catch(IOException ioe){ } catch(IOException ioe){
System.err.println("Error while reading Packet: " + ioe.getMessage()); System.err.println("Error while reading Packet: " + ioe.getMessage());
} }
} catch(IOException ioe){ } catch(IOException ioe){
System.err.println("Failed to read datagram packet: " + ioe.getMessage()); System.err.println("Failed to read datagram packet: " + ioe.getMessage());
// TODO we may have lost the socket here and need to do some resetting // TODO we may have lost the socket here and need to do some resetting
} }
} }
} }
/** /**
* sends the client its Assigned ID when it first connects * sends the client its Assigned ID when it first connects
* @param id ID of new client * @param id ID of new client
* @param oos Output stream to send ID over * @param oos Output stream to send ID over
* @throws IOException * @throws IOException
*/ */
public void sendID(int id, ObjectOutputStream oos) throws IOException { public void sendID(int id, ObjectOutputStream oos) throws IOException {
oos.writeInt(id); oos.writeInt(id);
oos.flush(); oos.flush();
} }
} }
/** /**
* starts listening for connections to server * starts listening for connections to server
*/ */
public void listen() { public void listen() {
switch (connectMode) { switch (connectMode) {
case CM_TCP: case CM_TCP:
startTCPListen(); startTCPListen();
break; break;
case CM_DATAGRAM: case CM_DATAGRAM:
startDatagramListen(); startDatagramListen();
break; break;
case CM_ALL: case CM_ALL:
startTCPListen(); startTCPListen();
startDatagramListen(); startDatagramListen();
break; break;
} }
} }
/** /**
* Creates new player with instance ID auto incremented * Creates new player with instance ID auto incremented
* but dosen't add to master list * but dosen't add to master list
*/ */
public synchronized Player getNextPlayer() { public synchronized Player getNextPlayer() {
playeridcount++; playeridcount++;
return new Player(playeridcount, new Pose(5, 5, 9, Direction.UP), "Player"); return new Player(playeridcount, new Pose(5, 5, 9, Direction.UP), "Player");
} }
/** /**
* Adds player instance data to master list for client management * Adds player instance data to master list for client management
* @param pid PlayerInstanceData of new player to add to master list * @param pid PlayerInstanceData of new player to add to master list
*/ */
public synchronized void addPlayer(PlayerInstanceData pid) { public synchronized void addPlayer(PlayerInstanceData pid) {
players.put(pid.getPlayer().getID(), pid); players.put(pid.getPlayer().getID(), pid);
} }
/** /**
* Calculates the Manhattan Distance between 2 players * Calculates the Manhattan Distance between 2 players
* *
* @param p1 first player * @param p1 first player
* @param p2 second player * @param p2 second player
* @return Manhattan Distance between players * @return Manhattan Distance between players
*/ */
public static int distance(Player p1, Player p2) { public static int distance(Player p1, Player p2) {
return GameState.getMap().manhattanDistance(p1.getPose(), p2.getPose()); return GameState.getMap().manhattanDistance(p1.getPose(), p2.getPose());
} }
/** /**
* Thread safe method called from MesageServerMessage to send * Thread safe method called from MesageServerMessage to send
* any messages to the appropriate players based on there relative * any messages to the appropriate players based on there relative
* locations and the message type * locations and the message type
* @param s the message * @param s the message
* @param p2id the player who sent the message * @param p2id the player who sent the message
*/ */
public synchronized void sendMessage(String s, PlayerInstanceData p2id) { public synchronized void sendMessage(String s, PlayerInstanceData p2id) {
Player p2 = p2id.getPlayer(); Player p2 = p2id.getPlayer();
if(s.charAt(0) == '/') { if(s.charAt(0) == '/') {
switch (s.charAt(1)) { switch (s.charAt(1)) {
case 'w': case 'w':
try { try {
int sp = s.indexOf(' ', 3); int sp = s.indexOf(' ', 3);
String name = s.substring(3, sp); String name = s.substring(3, sp);
String message = s.substring(sp, s.length()); String message = s.substring(sp, s.length());
for(PlayerInstanceData pid : players.values()) { for(PlayerInstanceData pid : players.values()) {
Player p = pid.getPlayer(); Player p = pid.getPlayer();
if (p.name.equals(name)) { if (p.name.equals(name)) {
pid.sendMessage(p2.name + " whispers: " + message); pid.sendMessage(p2.name + " whispers: " + message);
} }
} }
} catch (Exception x) { } catch (Exception x) {
} }
break; break;
case 'f': case 'f':
try { try {
String name = s.substring(3, s.length()); String name = s.substring(3, s.length());
if (name.equals(p2.getName())) if (name.equals(p2.getName()))
break; break;
for(PlayerInstanceData pid : players.values()) { for(PlayerInstanceData pid : players.values()) {
Player p = pid.getPlayer(); Player p = pid.getPlayer();
if (p.name.equals(name) && FIGHT_DISTANCE > distance(p, p2)){ if (p.name.equals(name) && FIGHT_DISTANCE > distance(p, p2)){
Fight f; Fight f;
// Confirming/Starting Fight // Confirming/Starting Fight
if ((f = pid.getFight()) != null) { if ((f = pid.getFight()) != null) {
pid.isChallenger = true; pid.isChallenger = true;
p2id.isChallenger = false; p2id.isChallenger = false;
// Set up server part of the fight // Set up server part of the fight
f.currentPlayer = p2id.getPlayer(); f.currentPlayer = p2id.getPlayer();
f.enemyPlayer = pid.getPlayer(); f.enemyPlayer = pid.getPlayer();
f.setOutPokemon(p2id.getPlayer().getFirstOut()); f.setOutPokemon(p2id.getPlayer().getFirstOut());
f.setEnemyPokemon(pid.getPlayer().getFirstOut()); f.setEnemyPokemon(pid.getPlayer().getFirstOut());
f.activePokemonE = f.enemyPlayer.poke f.activePokemonE = f.enemyPlayer.poke
.getFirstHealthy(); .getFirstHealthy();
f.activePokemonC = f.currentPlayer.poke f.activePokemonC = f.currentPlayer.poke
.getFirstHealthy(); .getFirstHealthy();
p2id.getPlayer() p2id.getPlayer()
.getFirstOut() .getFirstOut()
.getBase(); .getBase();
pid.getPlayer() pid.getPlayer()
.getFirstOut() .getFirstOut()
.getBase(); .getBase();
pid.sendFightStart(p2id.getPlayer()); pid.sendFightStart(p2id.getPlayer());
p2id.sendFightStart(pid.getPlayer()); p2id.sendFightStart(pid.getPlayer());
// Asking to fight // Asking to fight
} else { } else {
f = new Fight(); f = new Fight();
p2id.setFight(f); p2id.setFight(f);
pid.setFight(f); pid.setFight(f);
pid.sendMessage(p2.name + " wants to fight..."); pid.sendMessage(p2.name + " wants to fight...");
} }
} }
} }
} catch (Exception x) { } catch (Exception x) {
x.printStackTrace(); x.printStackTrace();
System.err.println("Failed to get player to Fight..."); System.err.println("Failed to get player to Fight...");
} }
break; break;
} }
} else { } else {
for(PlayerInstanceData pid : players.values()) { for(PlayerInstanceData pid : players.values()) {
Player p = pid.getPlayer(); Player p = pid.getPlayer();
if(p.id != p2.id && TALK_DISTANCE > distance(p, p2)){ if(p.id != p2.id && TALK_DISTANCE > distance(p, p2)){
try { try {
pid.sendMessage(p2.name + ": " + s); pid.sendMessage(p2.name + ": " + s);
} catch (IOException x) { } catch (IOException x) {
System.out.println("Failed to send Message"); System.out.println("Failed to send Message");
} }
} }
} }
} }
} }
/** /**
* Checks to see if a player is already logged in via * Checks to see if a player is already logged in via
* username comparison * username comparison
* @param p * @param p
* @return * @return
*/ */
public synchronized boolean isLoggedIn(Player logged_in) { public synchronized boolean isLoggedIn(Player logged_in) {
for(PlayerInstanceData pid : players.values()) { for(PlayerInstanceData pid : players.values()) {
if(pid.getPlayer().equals(logged_in)) if(pid.getPlayer().equals(logged_in))
return true; return true;
} }
return false; return false;
} }
/** /**
* Removes kicked or disconnected player from master list * Removes kicked or disconnected player from master list
* @param toRemove PlayerInstance Data of player to remove from master list * @param toRemove PlayerInstance Data of player to remove from master list
*/ */
public synchronized void remove(PlayerInstanceData toRemove) { public synchronized void remove(PlayerInstanceData toRemove) {
Player playerToRemove = toRemove.getPlayer(); Player playerToRemove = toRemove.getPlayer();
/* If the player is not logged in their level will be -1 /* If the player is not logged in their level will be -1
* so we check for this, we only want to save changes if * so we check for this, we only want to save changes if
* they where logged in, also we only need to update nearby * they where logged in, also we only need to update nearby
* people if they where logged in * people if they where logged in
*/ */
boolean loggedIn = false; boolean loggedIn = false;
if(playerToRemove.getPose().getLevel() != -1) if(playerToRemove.getPose().getLevel() != -1)
loggedIn = true; loggedIn = true;
/* /*
* Remove the player from the level list he is in * Remove the player from the level list he is in
*/ */
GameState.getMap().getLevel(playerToRemove.getPose().getLevel()).removePlayer(playerToRemove); GameState.getMap().getLevel(playerToRemove.getPose().getLevel()).removePlayer(playerToRemove);
/* /*
* Save player if they where logged in * Save player if they where logged in
*/ */
if(loggedIn) if(loggedIn)
Database.savePlayerData(playerToRemove); Database.savePlayerData(playerToRemove);
/* /*
* Tell any near by players this one is gone and remove this players * Tell any near by players this one is gone and remove this players
* Instance data from the list * Instance data from the list
* TODO don't iterate WHOLE LIST LOCALS ONLY! * TODO don't iterate WHOLE LIST LOCALS ONLY!
* TODO every once in a while the client should remove nowhere land players * TODO every once in a while the client should remove nowhere land players
*/ */
for(Entry<Integer, PlayerInstanceData> pidEntry : players.entrySet()){ for(Entry<Integer, PlayerInstanceData> pidEntry : players.entrySet()){
PlayerInstanceData pid = pidEntry.getValue(); PlayerInstanceData pid = pidEntry.getValue();
Player player = pid.getPlayer(); Player player = pid.getPlayer();
/* If the ID's are equal we found the player we are /* If the ID's are equal we found the player we are
* removing from the master list * removing from the master list
*/ */
if(pid == toRemove) if(pid == toRemove)
players.remove(pidEntry.getKey()); players.remove(pidEntry.getKey());
/* /*
* If this player was near the player to remove tell them he is in * If this player was near the player to remove tell them he is in
* nowhere land * nowhere land
*/ */
else if(VISIBLE_DISTANCE < distance(playerToRemove, player)) else if(VISIBLE_DISTANCE < distance(playerToRemove, player))
pid.writeClientMessage(new PlayerMovement(player.getID(), Pose.NOWHERE_LAND)); pid.writeClientMessage(new PlayerMovement(player.getID(), Pose.NOWHERE_LAND));
} }
} }
/** /**
* Removes a player from the master list without saving there status * Removes a player from the master list without saving there status
* @param pid player to remove * @param pid player to remove
*/ */
public synchronized void removeNoSave(PlayerInstanceData pid) { public synchronized void removeNoSave(PlayerInstanceData pid) {
for(Entry<Integer, PlayerInstanceData> pidEntry : players.entrySet()) { for(Entry<Integer, PlayerInstanceData> pidEntry : players.entrySet()) {
PlayerInstanceData pid2 = pidEntry.getValue(); PlayerInstanceData pid2 = pidEntry.getValue();
// Removes the PlayerInstanceData for the player // Removes the PlayerInstanceData for the player
if (pid == pid2) { if (pid == pid2) {
players.remove(pidEntry.getKey()); players.remove(pidEntry.getKey());
break; break;
} }
} }
} }
/** /**
* Contains everything the server needs to keep track of players and * Contains everything the server needs to keep track of players and
* send messages to them * send messages to them
*/ */
public static class PlayerInstanceData { public static class PlayerInstanceData {
public Player p; public Player p;
private int sockID = -1; private int sockID = -1;
private long lastRecivedMessageTime = 0; private long lastRecivedMessageTime = 0;
private MessageListener message_listener; private MessageListener message_listener;
private ObjectOutputStream oos; private ObjectOutputStream oos;
private boolean loggedIn = false; private boolean loggedIn = false;
private Fight f = null; private Fight f = null;
private boolean isChallenger = false; private boolean isChallenger = false;
public PlayerInstanceData() { public PlayerInstanceData() {
} }
public PlayerInstanceData(Player player, long last_message_recived_time, MessageListener message_listener) { public PlayerInstanceData(Player player, long last_message_recived_time, MessageListener message_listener) {
this.p = player; this.p = player;
this.lastRecivedMessageTime = last_message_recived_time; this.lastRecivedMessageTime = last_message_recived_time;
this.message_listener = message_listener; this.message_listener = message_listener;
} }
boolean hasMessageLast45() { boolean hasMessageLast45() {
if (System.currentTimeMillis() - 45000 > lastRecivedMessageTime) if (System.currentTimeMillis() - 45000 > lastRecivedMessageTime)
return false; return false;
return true; return true;
} }
public void stop() { public void stop() {
message_listener.stop_listening(); message_listener.stop_listening();
} }
public Player getPlayer() { public Player getPlayer() {
return p; return p;
} }
public void setPlayer(Player p) { public void setPlayer(Player p) {
this.p = p; this.p = p;
} }
public boolean isLoggedIn() { public boolean isLoggedIn() {
return loggedIn; return loggedIn;
} }
public boolean isChallenger() { public boolean isChallenger() {
return isChallenger; return isChallenger;
} }
public void setSockID(int id) { public void setSockID(int id) {
sockID = id; sockID = id;
} }
public int getSockID() { public int getSockID() {
return sockID; return sockID;
} }
public void setFight(Fight f) { public void setFight(Fight f) {
this.f = f; this.f = f;
} }
public Fight getFight() { public Fight getFight() {
return f; return f;
} }
public void setListener(MessageListener message_listener) { public void setListener(MessageListener message_listener) {
this.message_listener = message_listener; this.message_listener = message_listener;
} }
public void setLoggedIn(boolean li) { public void setLoggedIn(boolean li) {
loggedIn = li; loggedIn = li;
} }
public void recivedMessage() { public void recivedMessage() {
lastRecivedMessageTime = System.currentTimeMillis(); lastRecivedMessageTime = System.currentTimeMillis();
} }
public void setOutputStream(ObjectOutputStream oos) { public void setOutputStream(ObjectOutputStream oos) {
this.oos = oos; this.oos = oos;
} }
public void setIsChallenger(boolean chal) { public void setIsChallenger(boolean chal) {
isChallenger = chal; isChallenger = chal;
} }
public synchronized void writeClientMessage(ClientMessage cm) { public synchronized void writeClientMessage(ClientMessage cm) {
try { try {
oos.writeObject(cm); oos.writeObject(cm);
oos.flush(); oos.flush();
oos.reset(); oos.reset();
} catch (Exception x) { } catch (Exception x) {
x.printStackTrace(); x.printStackTrace();
} }
} }
public synchronized void sendActor(Person p, int activity) public synchronized void sendActor(Person p, int activity)
throws IOException { throws IOException {
// TODO redo player talking to // TODO redo player talking to
//if (activity == Person.A_TALKING_TO) //if (activity == Person.A_TALKING_TO)
// oos.writeObject(new SendActTalkingToClientMessage(p.id, (int)p.x, // oos.writeObject(new SendActTalkingToClientMessage(p.id, (int)p.x,
// (int)p.y, p.dir, p.level, p.onClick.getActive())); // (int)p.y, p.dir, p.level, p.onClick.getActive()));
//else //else
oos.writeObject(new SendActMovedClientMessage(p.id, p.getPose())); oos.writeObject(new SendActMovedClientMessage(p.id, p.getPose()));
oos.flush(); oos.flush();
oos.reset(); oos.reset();
} }
public synchronized void sendPlayerUpdate(Player p, boolean self) public synchronized void sendPlayerUpdate(Player p, boolean self)
throws IOException { throws IOException {
oos.writeObject(new PlayerInfo(p, self)); oos.writeObject(new PlayerInfo(p, self));
oos.flush(); oos.flush();
oos.reset(); oos.reset();
} }
public synchronized void sendMessage(String message) throws IOException { public synchronized void sendMessage(String message) throws IOException {
oos.writeObject(new MessageClientMessage(message)); oos.writeObject(new MessageClientMessage(message));
oos.flush(); oos.flush();
oos.reset(); oos.reset();
} }
public synchronized void sendCommand(int command) throws IOException { public synchronized void sendCommand(int command) throws IOException {
oos.writeInt(command); oos.writeInt(command);
oos.flush(); oos.flush();
} }
public synchronized void sendLoad() throws IOException { public synchronized void sendLoad() throws IOException {
int ids[] = new int[6]; int ids[] = new int[6];
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
if (p.poke.belt[i] != null) if (p.poke.belt[i] != null)
ids[i] = p.poke.belt[i].idNo; ids[i] = p.poke.belt[i].idNo;
else else
ids[i] = -1; ids[i] = -1;
} }
oos.writeObject(new CMLoad(ids, p.poke.box, p.items)); oos.writeObject(new CMLoad(ids, p.poke.box, p.items));
oos.flush(); oos.flush();
oos.reset(); oos.reset();
} }
public synchronized void sendFightStart(Player enemyPlayer) public synchronized void sendFightStart(Player enemyPlayer)
throws IOException { throws IOException {
// Create a new fight // Create a new fight
Fight f = new Fight(); Fight f = new Fight();
// Set the other guy to the enemy player // Set the other guy to the enemy player
f.enemyPlayer = enemyPlayer; f.enemyPlayer = enemyPlayer;
// set the number of pokemon and the enemy // set the number of pokemon and the enemy
f.pokemonCountE = 0; f.pokemonCountE = 0;
f.activePokemonE = -1; f.activePokemonE = -1;
// Count pokemon // Count pokemon
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
if (enemyPlayer.poke.belt[i] == null) if (enemyPlayer.poke.belt[i] == null)
break; break;
if (f.activePokemonE == -1 if (f.activePokemonE == -1
&& enemyPlayer.poke.belt[i].currentHP > 0) { && enemyPlayer.poke.belt[i].currentHP > 0) {
f.activePokemonE = i; // Set first slot f.activePokemonE = i; // Set first slot
f.enemy = enemyPlayer.poke.belt[i]; // Set Enemy Pokemon f.enemy = enemyPlayer.poke.belt[i]; // Set Enemy Pokemon
} }
f.pokemonCountE++; f.pokemonCountE++;
} }
// Set self to Well self // Set self to Well self
f.currentPlayer = p; f.currentPlayer = p;
// Send the fight to the opponent // Send the fight to the opponent
oos.writeObject(new SendFightClientMessage(f)); oos.writeObject(new SendFightClientMessage(f));
oos.flush(); oos.flush();
oos.reset(); oos.reset();
} }
} }
} }
   
package com.dryerzinia.pokemon.obj.tiles; package com.dryerzinia.pokemon.obj.tiles;
import java.util.HashMap; import java.util.HashMap;
import com.dryerzinia.pokemon.PokemonServer; import com.dryerzinia.pokemon.PokemonServer;
import com.dryerzinia.pokemon.map.Direction; import com.dryerzinia.pokemon.map.Direction;
import com.dryerzinia.pokemon.map.Grid; import com.dryerzinia.pokemon.map.Grid;
import com.dryerzinia.pokemon.map.Pose; import com.dryerzinia.pokemon.map.Pose;
import com.dryerzinia.pokemon.util.JSONObject; import com.dryerzinia.pokemon.util.JSONObject;
import com.dryerzinia.pokemon.obj.Actor; import com.dryerzinia.pokemon.obj.Actor;
public class WanderingPerson extends Person implements Actor { public class WanderingPerson extends Person implements Actor {
static final long serialVersionUID = -3752479366750590617L; static final long serialVersionUID = -3752479366750590617L;
protected int w, h; protected int w, h;
protected int rx = 0, ry = 0; protected int rx = 0, ry = 0;
protected int con = 0; protected int con = 0;
protected transient Grid g; protected transient Grid g;
public WanderingPerson() { public WanderingPerson() {
} }
public WanderingPerson(String imgName, boolean cbso, int w, int h, int rx, int ry, Pose location, Grid g) { public WanderingPerson(String imgName, boolean cbso, int w, int h, int rx, int ry, Pose location, Grid g) {
this.imgName = imgName; this.imgName = imgName;
pixelOffsetX = 0; pixelOffsetX = 0;
pixelOffsetY = 0; pixelOffsetY = 0;
canBeSteppedOn = cbso; canBeSteppedOn = cbso;
this.w = w; this.w = w;
this.h = h; this.h = h;
this.rx = rx; this.rx = rx;
this.ry = ry; this.ry = ry;
this.location = location; this.location = location;
this.g = g; this.g = g;
loadImage(); loadImage();
} }
protected boolean wander() { protected boolean wander() {
boolean canMove = false; boolean canMove = false;
boolean changed = false; boolean changed = false;
int pos = (int) (Math.random() * 20); int pos = (int) (Math.random() * 20);
if (pos < 4) { if (pos < 4) {
if (location.facing().getValue() != pos) { if (location.facing().getValue() != pos) {
location.changeDirection(Direction.get(pos)); location.changeDirection(Direction.get(pos));
changed = true; changed = true;
} }
} }
Direction dir = location.facing(); Direction dir = location.facing();
int level = location.getLevel(); int level = location.getLevel();
int x = (int) location.getX(); int x = (int) location.getX();
int y = (int) location.getY(); int y = (int) location.getY();
pos = (int) (Math.random() * 20); pos = (int) (Math.random() * 20);
if (pos > 2 && con % 4 == 0) { if (pos > 2 && con % 4 == 0) {
if (dir == Direction.UP) { if (dir == Direction.UP) {
if (!PokemonServer.isPlayer(x, y - 1, level) if (!PokemonServer.isPlayerAtTile(x, y - 1, level)
&& g.canStepOn(x, y - 1)) && g.canStepOn(x, y - 1))
canMove = true; canMove = true;
} else if (dir == Direction.DOWN) { } else if (dir == Direction.DOWN) {
if (!PokemonServer.isPlayer(x, y + 1, level) if (!PokemonServer.isPlayerAtTile(x, y + 1, level)
&& g.canStepOn(x, y + 1)) && g.canStepOn(x, y + 1))
canMove = true; canMove = true;
} else if (dir == Direction.LEFT) { } else if (dir == Direction.LEFT) {
if (!PokemonServer.isPlayer(x - 1, y, level) if (!PokemonServer.isPlayerAtTile(x - 1, y, level)
&& g.canStepOn(x - 1, y)) && g.canStepOn(x - 1, y))
canMove = true; canMove = true;
} else if (dir == Direction.RIGHT) { } else if (dir == Direction.RIGHT) {
if (!PokemonServer.isPlayer(x + 1, y, level) if (!PokemonServer.isPlayerAtTile(x + 1, y, level)
&& g.canStepOn(x + 1, y)) && g.canStepOn(x + 1, y))
canMove = true; canMove = true;
} }
} }
if (canMove && con % 7 == 0) { if (canMove && con % 7 == 0) {
changed = true; changed = true;
if (dir == Direction.UP) { if (dir == Direction.UP) {
g.move(x, y - 1, x, y, this); g.move(x, y - 1, x, y, this);
ry--; ry--;
y--; y--;
} else if (dir == Direction.DOWN) { } else if (dir == Direction.DOWN) {
g.move(x, y + 1, x, (int)y, this); g.move(x, y + 1, x, (int)y, this);
ry++; ry++;
y++; y++;
} else if (dir == Direction.LEFT) { } else if (dir == Direction.LEFT) {
g.move(x - 1, y, x, y, this); g.move(x - 1, y, x, y, this);
rx--; rx--;
x--; x--;
} else if (dir == Direction.RIGHT) { } else if (dir == Direction.RIGHT) {
g.move(x + 1, y, x, y, this); g.move(x + 1, y, x, y, this);
rx++; rx++;
x++; x++;
} }
} }
con++; con++;
if(changed){ if(changed){
location.setX(x); location.setX(x);
location.setY(y); location.setY(y);
location.changeDirection(dir); location.changeDirection(dir);
} }
return changed; return changed;
} }
public boolean act() { public boolean act() {
return wander(); return wander();
} }
public void initializeSecondaryReferences(Grid g) { public void initializeSecondaryReferences(Grid g) {
this.g = g; this.g = g;
} }
public Object deepCopy() { public Object deepCopy() {
return new WanderingPerson(new String(imgName), canBeSteppedOn, return new WanderingPerson(new String(imgName), canBeSteppedOn,
w, h, rx, ry, location, this.g); w, h, rx, ry, location, this.g);
} }
public void fromJSON(HashMap<String, Object> json){ public void fromJSON(HashMap<String, Object> json){
super.fromJSON(json); super.fromJSON(json);
w = ((Float) json.get("w")).intValue(); w = ((Float) json.get("w")).intValue();
h = ((Float) json.get("h")).intValue();; h = ((Float) json.get("h")).intValue();;
rx = ((Float) json.get("rx")).intValue(); rx = ((Float) json.get("rx")).intValue();
ry = ((Float) json.get("ry")).intValue(); ry = ((Float) json.get("ry")).intValue();
con = ((Float) json.get("con")).intValue(); con = ((Float) json.get("con")).intValue();
} }
@Override @Override
public String toJSON() throws IllegalAccessException { public String toJSON() throws IllegalAccessException {
return JSONObject.defaultToJSON(this); return JSONObject.defaultToJSON(this);
} }
} }