package org.pokenet.server.backend.entity;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import org.apache.mina.core.session.IoSession;
import org.pokenet.server.GameServer;
import org.pokenet.server.backend.map.ServerMap;
import org.pokenet.server.backend.map.ServerMap.PvPType;
import org.pokenet.server.battle.BattleField;
import org.pokenet.server.battle.DataService;
import org.pokenet.server.battle.Pokemon;
import org.pokenet.server.battle.PokemonSpecies;
import org.pokenet.server.battle.impl.PvPBattleField;
import org.pokenet.server.battle.impl.WildBattleField;
import org.pokenet.server.battle.mechanics.moves.PokemonMove;
import org.pokenet.server.feature.TimeService;
import org.pokenet.server.network.MySqlManager;
import org.pokenet.server.network.TcpProtocolHandler;
import org.pokenet.server.network.message.ItemMessage;
import org.pokenet.server.network.message.SpriteChangeMessage;
import org.pokenet.server.network.message.shop.ShopBuyMessage;
import org.pokenet.server.network.message.shop.ShopNoItemMessage;
import org.pokenet.server.network.message.shop.ShopNoMoneyMessage;
import org.pokenet.server.network.message.shop.ShopNoSpaceMessage;
import org.pokenet.server.network.message.shop.ShopSellMessage;
/**
* Represents a player
* @author shadowkanji
*
*/
public class PlayerChar extends Char implements Battleable, Tradeable {
/*
* An enum to store request types
*/
public enum RequestType { BATTLE, TRADE };
/*
* An enum to store the player's selected language
*/
public enum Language { ENGLISH, PORTUGESE, ITALIAN, FRENCH, FINNISH, SPANISH, GERMAN, DUTCH }
private Language m_language;
private Bag m_bag;
private int m_battleId;
private Pokemon[] m_pokemon;
private PokemonBox [] m_boxes;
private boolean m_isBattling = false;
private boolean m_isShopping = false;
private boolean m_isTalking = false;
private boolean m_isBoxing = false;
private boolean m_isSpriting = false;
private IoSession m_tcpSession = null;
private IoSession m_udpSession = null;
private int m_money;
private ArrayList<String> m_friends;
private long m_lastLogin;
private int m_skillHerbExp = 0;
private int m_skillCraftExp = 0;
private int m_skillFishExp = 0;
private int m_skillTrainingExp = 0;
private int m_skillCoordExp = 0;
private int m_skillBreedExp = 0;
private int m_oldLevel;
private BattleField m_battleField = null;
private int m_healX, m_healY, m_healMapX, m_healMapY;
private int m_adminLevel = 0;
private boolean m_isMuted, m_isFishing;
private Shop m_currentShop = null;
private int m_repel = 0;
private long m_lastTrade = 0;
/*
* Stores movement of other players to be
* sent in bulk to client
*/
private String [] m_movements = new String [7];
/*
* Kicking timer
*/
public long lastPacket = System.currentTimeMillis();
/*
* Fishing timer
*/
public long lastFishingTime = System.currentTimeMillis();
/*
* Trade stuff
*/
private Trade m_trade = null;
private boolean m_isReadyToTrade = false;
/*
* Badges are stored as bytes. 0 = not obtained, 1 = obtained
* Stored as following:
* 0 - 7 Kanto Badges
* 8 - 15 Johto Badges
* 16 - 23 Hoenn Badges
* 24 - 31 Sinnoh Badges
* 32 - 35 Orange Islands
* 36 - 41
*/
private byte [] m_badges;
/*
* Stores the list of requests the player has sent
*/
private HashMap<String, RequestType> m_requests;
/**
* Constructor
* NOTE: Minimal initialisations should occur here
*/
public PlayerChar() {
m_requests = new HashMap<String, RequestType>();
}
/**
* Queues other player movements to be sent to client in bulk
* @param d
* @param player
*/
public void queueOtherPlayerMovement(Direction d, int player) {
String s = d.name().toUpperCase().charAt(0) + String.valueOf(player);
/* Queue the movement */
for(int i = 0; i < m_movements.length; i++) {
if(m_movements[i] == null) {
m_movements[i] = s;
return;
}
}
/*
* Unsuccessful, queue is full!
* Send queue and place at 0
*/
String message = "M";
for(int i = 0; i < m_movements.length; i++) {
message = message + m_movements[i] + ",";
m_movements[i] = null;
}
message = message.substring(0, message.length() - 1);
m_tcpSession.write(message);
m_movements[0] = s;
}
/**
* Returns this player's ip address
* @return
*/
public String getIpAddress() {
if(m_tcpSession != null) {
String ip = m_tcpSession.getRemoteAddress().toString();
ip = ip.substring(1);
ip = ip.substring(0, ip.indexOf(":"));
return ip;
} else {
return "";
}
}
/**
* Sets how many steps this Pokemon can repel for
* @param steps
*/
public void setRepel(int steps) {
m_repel = steps;
}
/**
* Returns how many steps this player can repel Pokemon for
* @return
*/
public int getRepel() {
return m_repel;
}
/**
* Releases a pokemon from box
* @param box
* @param slot
*/
public void releasePokemon(int box, int slot) {
/* If the box doesn't exist, return */
if(m_boxes[box] == null)
return;
/* Check if the pokemon exists */
if(m_boxes[box].getPokemon(slot) != null) {
if(m_boxes[box].getPokemon(slot).getDatabaseID() > -1) {
/* This box exists and the pokemon exists in the database */
int id = m_boxes[box].getPokemon(slot).getDatabaseID();
MySqlManager m = new MySqlManager();
if(m.connect(GameServer.getDatabaseHost(),
GameServer.getDatabaseUsername(),
GameServer.getDatabasePassword())) {
m.selectDatabase(GameServer.getDatabaseName());
m.query("DELETE FROM pn_pokemon WHERE id='" + id + "'");
m.close();
m_boxes[box].setPokemon(slot, null);
}
} else {
/*
* This Pokemon or box has not been saved to the
* database yet so just null it.
*/
m_boxes[box].setPokemon(slot, null);
}
}
}
/**
* Swaps pokemon between box and party
* @param box
* @param boxSlot
* @param partySlot
*/
public void swapFromBox(int box, int boxSlot, int partySlot) {
if(box < 0 || box > 8)
return;
/* Ensure the box exists */
if(m_boxes[box] == null) {
m_boxes[box] = new PokemonBox();
m_boxes[box].setPokemon(new Pokemon[30]);
}
/* Make sure we're not depositing our only Pokemon */
if(getPartyCount() == 1) {
if(m_pokemon[partySlot] != null && m_boxes[box].getPokemon(boxSlot) == null)
return;
}
/* Everything is okay, let's get swapping! */
Pokemon temp = m_pokemon[partySlot];
m_pokemon[partySlot] = m_boxes[box].getPokemon(boxSlot);
m_boxes[box].setPokemon(boxSlot, temp);
if(m_pokemon[partySlot] != null) {
updateClientParty(partySlot);
} else {
m_tcpSession.write("PN" + partySlot);
}
}
/**
* Sets if this player is interacting with
* a sprite selection npc
* @param b
*/
public void setSpriting(boolean b) {
m_isSpriting = b;
}
/**
* Returns true if this player is
* interacting with a sprite selection npc
* @return
*/
public boolean isSpriting() {
return m_isSpriting;
}
/**
* Returns the preferred language of the user
* @return
*/
public Language getLanguage() {
return m_language;
}
/**
* Sets this player's preferred language
* @param l
*/
public void setLanguage(Language l) {
m_language = l;
}
/**
* Returns true if the player is trading
* @return
*/
public boolean isTrading() {
return m_trade != null;
}
/**
* Cancels this player's trade offer
*/
public void cancelTradeOffer() {
m_trade.cancelOffer(this);
}
public void cancelTrade() {
m_trade.endTrade();
}
public void finishTrading() {
m_isTalking = false;
m_isReadyToTrade = false;
m_trade = null;
if(m_tcpSession != null && m_tcpSession.isConnected())
m_tcpSession.write("Tf");
ensureHealthyPokemon();
m_lastTrade = System.currentTimeMillis();
}
public void receiveTradeOffer(TradeOffer[] o) {
m_tcpSession.write("To" + o[0].getId() + "," + o[1].getId());
}
public void receiveTradeOfferCancelation() {
m_tcpSession.write("Tc");
}
public void setTradeAccepted(boolean b) {
m_isReadyToTrade = b;
if(b)
m_trade.checkForExecution();
}
/**
* Returns the trade that the player is involved in
* @return
*/
public Trade getTrade() {
return m_trade;
}
/**
* Sets the trade this player is involved in
* @param t
*/
public void setTrade(Trade t) {
m_trade = t;
}
/**
* Returns true if the player accepted the trade offer
* @return
*/
public boolean acceptedTradeOffer() {
return m_isReadyToTrade;
}
/**
* Returns true if the player is allowed trade
* @return
*/
public boolean canTrade() {
return System.currentTimeMillis() - m_lastTrade > 60000 && getPartyCount() >= 2;
}
/**
* Stores a request the player has sent
* @param username
* @param r
*/
public void addRequest(String username, RequestType r) {
/* Check if it is a battle request on a pvp enforced map */
if(r == RequestType.BATTLE) {
/*
* If the player is on the same map and
* within 3 squares of the player, start the battle
*/
if(this.getMap().getPvPType() == PvPType.ENFORCED) {
PlayerChar otherPlayer = TcpProtocolHandler.getPlayer(username);
if(otherPlayer != null && this.getMap() == otherPlayer.getMap()) {
if(otherPlayer.getX() >= this.getX() - 96 ||
otherPlayer.getX() <= this.getX() + 96 ||
otherPlayer.getY() >= this.getY() - 96 ||
otherPlayer.getY() <= this.getY() + 96) {
/* This is a valid battle, start it */
ensureHealthyPokemon();
otherPlayer.ensureHealthyPokemon();
m_battleField = new PvPBattleField(
DataService.getBattleMechanics(),this, otherPlayer);
return;
} else {
m_tcpSession.write("r!3");
}
}
}
}
/* Else, add the request */
m_requests.put(username, r);
}
/**
* Removes a request
* @param username
*/
public void removeRequest(String username) {
m_requests.remove(username);
}
/**
* Called when a player accepts a request sent by this player
* @param username
*/
public void requestAccepted(String username) {
PlayerChar otherPlayer = TcpProtocolHandler.getPlayer(username);
if(otherPlayer != null) {
if(m_requests.containsKey(username)) {
switch(m_requests.get(username)) {
case BATTLE:
/* First, ensure both players are on the same map */
if(otherPlayer.getMap() != this.getMap())
return;
/*
* Based on the map's pvp type, check this battle is possible
* If pvp is enforced, it will be started when the offer is made
*/
if(this.getMap().getPvPType() != null) {
switch(this.getMap().getPvPType()) {
case DISABLED:
/* Some maps have pvp disabled */
otherPlayer.getTcpSession().write("r!2");
m_tcpSession.write("r!2");
return;
case ENABLED:
/* This is a valid battle, start it */
ensureHealthyPokemon();
otherPlayer.ensureHealthyPokemon();
m_battleField = new PvPBattleField(
DataService.getBattleMechanics(),this, otherPlayer);
return;
}
} else {
m_battleField = new PvPBattleField(
DataService.getBattleMechanics(),this, otherPlayer);
}
break;
case TRADE:
if(canTrade() && otherPlayer.canTrade()) {
/* Set the player as talking so they can't move */
m_isTalking = true;
/* Create the trade */
m_trade = new Trade(this, otherPlayer);
otherPlayer.setTrade(m_trade);
} else {
m_tcpSession.write("r!4");
otherPlayer.getTcpSession().write("r!4");
}
break;
}
}
} else {
m_tcpSession.write("r!0");
}
}
/**
* Clears the request list
*/
public void clearRequests() {
if(m_requests.size() > 0) {
for(String username : m_requests.keySet()) {
if(TcpProtocolHandler.containsPlayer(username)) {
TcpProtocolHandler.getPlayer(username).getTcpSession().write("rc" + this.getName());
}
}
m_requests.clear();
}
}
/**
* Sets the current shop
* @param s
*/
public void setShop(Shop s) {
m_currentShop = s;
}
/**
* Returns the shop the player is interacting with
* @return
*/
public Shop getShop() {
return m_currentShop;
}
/**
* Creates a new PlayerChar
*/
public void createNewPlayer() {
//Set up all badges.
m_badges = new byte[42];
for(int i = 0; i < m_badges.length; i++) {
m_badges[i] = 0;
}
m_isMuted = false;
}
/**
* Called when a player loses a battle
*/
public void lostBattle() {
/*
* Heal the players Pokemon
*/
healPokemon();
/*
* Make the Pokemon unhappy
*/
for(int i = 0; i < m_pokemon.length; i++) {
if(m_pokemon[i] != null)
m_pokemon[i].setHappiness(20);
}
/*
* Now warp them to the last place they were healed
*/
m_x = m_healX;
m_y = m_healY;
if(m_tcpSession.isConnected() && !m_tcpSession.isClosing()) {
this.setMap(GameServer.getServiceManager().getMovementService().getMapMatrix().
getMapByGamePosition(m_healMapX, m_healMapY), null);
} else {
m_mapX = m_healMapX;
m_mapY = m_healMapY;
}
/* Turn back to normal sprite */
if(isSurfing())
setSurfing(false);
}
/**
* Heals the player's pokemon
*/
public void healPokemon() {
for (Pokemon pokemon : getParty()) {
if (pokemon != null) {
pokemon.calculateStats(true);
pokemon.reinitialise();
pokemon.setIsFainted(false);
for(int i = 0; i < pokemon.getMoves().length; i++) {
if(pokemon.getMoves()[i] != null) {
PokemonMove move = pokemon.getMoves()[i].getMove();
pokemon.setPp(i, move.getPp() * (5 + pokemon.getPpUpCount(i)) / 5);
pokemon.setMaxPP(i, move.getPp() * (5 + pokemon.getPpUpCount(i)) / 5);
}
}
}
}
m_tcpSession.write("cH");
}
/**
* Removes temporary status effects such as StatChangeEffects
*/
public void removeTempStatusEffects() {
for(Pokemon pokemon: getParty()) {
if(pokemon != null) {
pokemon.removeStatusEffects(false);
}
}
}
/**
* Returns true if this player is accessing their box
* @return
*/
public boolean isBoxing() {
return m_isBoxing;
}
/**
* Sets if this player has box access at the moment
* @param b
*/
public void setBoxing(boolean b) {
m_isBoxing = b;
}
/**
* Returns true if this player is muted
* @return
*/
public boolean isMuted() {
return m_isMuted;
}
/**
* Sets if this player is muted
* @param b
*/
public void setMuted(boolean b) {
m_isMuted = b;
}
/**
* If the player's first Pokemon in party has 0 HP,
* it puts the first Pokemon in their party with more
* than 0 HP at the front
*/
public void ensureHealthyPokemon() {
if(m_pokemon[0] == null || m_pokemon[0].getHealth() == 0) {
for(int i = 1; i < 6; i++) {
if(m_pokemon[i] != null && m_pokemon[i].getHealth() > 0) {
swapPokemon(0, i);
return;
}
}
}
}
/**
* Swaps two Pokemon in a player's party
* @param a
* @param b
*/
public void swapPokemon(int a, int b) {
if(a >= 0 && a < 6 && b >= 0 && b < 6) {
Pokemon temp = m_pokemon[a];
m_pokemon[a] = m_pokemon[b];
m_pokemon[b] = temp;
m_tcpSession.write("s" + a + "," + b);
}
}
/**
* Returns true if this player is talking to an npc
* @return
*/
public boolean isTalking() {
return m_isTalking;
}
/**
* Sets if this player is talking to an npc
* @param b
*/
public void setTalking(boolean b) {
m_isTalking = b;
}
/**
* Adds a friend to the friend list
* @param username
*/
public void addFriend(String username) {
if(m_friends == null)
m_friends = new ArrayList<String>();
if(m_friends.size() < 10) {
m_friends.add(username);
m_tcpSession.write("Fa" + username);
}
}
/**
* Removes a friend from the friends list
* @param username
*/
public void removeFriend(String username) {
if(m_friends == null) {
m_friends = new ArrayList<String>();
return;
}
for(int i = 0; i < m_friends.size(); i++) {
if(m_friends.get(i).equalsIgnoreCase(username)) {
m_friends.remove(i);
m_tcpSession.write("Fr" + username);
return;
}
}
}
/**
* Returns the battlefield this player is on.
*/
public BattleField getBattleField() {
return m_battleField;
}
/**
* Returns the battle id of this player on the battlefield
*/
public int getBattleId() {
return m_battleId;
}
/**
* Returns this player's opponent
*/
public Battleable getOpponent() {
//DO WE REALLY NEED THIS?
return null;
}
/**
* Returns the amount of Pokemon in this player's party
* @return
*/
public int getPartyCount() {
int r = 0;
for(int i = 0; i < m_pokemon.length; i++) {
if(m_pokemon[i] != null)
r++;
}
return r;
}
/**
* Returns the highest level pokemon in the player's party
* @return
*/
public int getHighestLevel() {
int h = 0;
for(int i = 0; i < m_pokemon.length; i++) {
if(m_pokemon[i] != null && h < m_pokemon[i].getLevel())
h = m_pokemon[i].getLevel();
}
return h;
}
/**
* Returns the Pokemon party of this player
*/
public Pokemon[] getParty() {
return m_pokemon;
}
/**
* Returns true if this player is battling
*/
public boolean isBattling() {
return m_isBattling;
}
/**
* Sets if this player is battling
* @param b
*/
public void setBattling(boolean b) {
m_isBattling = b;
if(!m_isBattling) {
/*
* If the player has finished battling
* kill their battlefield
*/
m_battleField = null;
}
}
/**
* Sets this player's battle id on a battlefield
*/
public void setBattleId(int battleID) {
m_battleId = battleID;
}
/**
* Set the pokemon party of this player
*/
public void setParty(Pokemon[] team) {
m_pokemon = team;
}
/**
* Sets the TCP session for this player (their connection to the server)
* @param session
*/
public void setTcpSession(IoSession session) {
m_tcpSession = session;
}
/**
* Returns the TCP session (connection to server) for this player
* @return
*/
public IoSession getTcpSession() {
return m_tcpSession;
}
/**
* Returns the UDP session for this player
* @return
*/
public IoSession getUdpSession() {
return m_udpSession;
}
/**
* Fishes for a pokemon.
*/
public void fish(int rod) {
if(this.lastFishingTime + 1000 < System.currentTimeMillis()) {
if(this.getMap().caughtFish(this, this.getFacing(), rod)) {
Pokemon p = this.getMap().getWildPokemon(this);
//If we have both the required level to fish this thing up and the rod to do it
if(this.getFishingLevel() >= DataService.getFishDatabase().getFish(p.getSpeciesName()).getReqLevel() && rod >= DataService.getFishDatabase().getFish(p.getSpeciesName()).getReqRod()) {
this.addFishingExp(DataService.getFishDatabase().getFish(p.getSpeciesName()).getExperience());
this.ensureHealthyPokemon();
m_battleField = new WildBattleField(DataService.getBattleMechanics(),this,p);
}
//If you either have too low a fishing level or too weak a rod
else {
m_tcpSession.write("FU"); // Notify client you pulled up a fish too strong for you
this.addFishingExp(10); //Conciliatory exp for "hooking" something even if it got away
}
} else {
if (this.getMap().facingWater(this, getFacing()));
m_tcpSession.write("Fu"); //"Not even a nibble!" message
}
this.setFishing(false);
}
}
/**
* Overrides char's move method.
* Adds a check for wild battles and clears battle/trade request lists
*/
@Override
public boolean move(Direction d) {
if(!m_isBattling && !m_isTalking && !m_isShopping && !m_isBoxing) {
if(super.move(d)) {
//If the player moved
if(this.getMap() != null) {
if(m_repel > 0)
m_repel--;
if(m_repel <= 0 && this.getMap().isWildBattle(m_x, m_y, this)) {
m_tcpSession.write("U" + getX() + "," + getY());
this.ensureHealthyPokemon();
m_battleField = new WildBattleField(
DataService.getBattleMechanics(),
this,
this.getMap().getWildPokemon(this));
m_movementQueue.clear();
} else {
if(m_map.isNpcBattle(this))
m_movementQueue.clear();
}
/* If it wasn't a battle see should we increase happiness */
if(this.getX() % 32 == 0 || (this.getY() + 8) % 32 == 0) {
for(int i = 0; i < m_pokemon.length; i++) {
/*
* Pokemon only have their happiness
* increased by walking if it is below 70
*/
if(m_pokemon[i] != null && m_pokemon[i].getHappiness() < 70)
m_pokemon[i].setHappiness(m_pokemon[i].getHappiness() + 1);
}
}
}
return true;
}
} else {
if(getPriority() > 0) {
//Someone has been trying to move in-battle! RESYNC
m_movementQueue.clear();
m_tcpSession.write("U" + getX() + "," + getY());
}
}
return false;
}
/**
* Sets how much money this player has
* @param money
*/
public void setMoney(int money) {
m_money = money;
}
/**
* Returns how much money this player has
* @return
*/
public int getMoney() {
return m_money;
}
/**
* Returns true if this char is fishing
* @return
*/
public boolean isFishing() {
return m_isFishing;
}
/**
* Sets if this char is fishing or not and sends the sprite change information to everyone
* @param b
*/
public void setFishing(boolean b) {
m_isFishing = b;
if(b == true)
this.lastFishingTime = System.currentTimeMillis();
if(m_map != null) {
//Tell clients to update this char to reflect whether player is fishing or not.
}
}
/**
* Initializes the client's skill levels
*/
public void initializeClientSkills(){
m_tcpSession.write("cst" + getTrainingLevel());
m_tcpSession.write("csb" + getBreedingLevel());
m_tcpSession.write("csf" + getFishingLevel());
m_tcpSession.write("csc" + getCoordinatingLevel());
}
/**
* Sets the herbalism skill's exp points
* @param exp
*/
public void setHerbalismExp(int exp) {
m_skillHerbExp = exp;
}
/**
* Add something to the herbalism skill exp points
* @param exp
*/
public void addHerbalismExp(int exp) {
m_oldLevel = getHerbalismLevel();
m_skillHerbExp = m_skillHerbExp + exp;
if(getHerbalismLevel() > m_oldLevel && getHerbalismLevel()<= 100) {
m_tcpSession.write("csh" + getHerbalismLevel());
}
}
/**
* Returns the herbalism skill exp points
* @return
*/
public int getHerbalismExp() {
return m_skillHerbExp;
}
/**
* Returns the herbalism skill level
* @return
*/
public int getHerbalismLevel() {
int level = (int) Math.pow(m_skillHerbExp, (0.3333));
if(level <= 100)
return level;
else
return 100;
}
/**
* Sets the crafting skill exp points
* @param exp
*/
public void setCraftingExp(int exp) {
m_skillCraftExp = exp;
}
/**
* Add something to the crafting skill exp points
* @param exp
*/
public void addCraftingExp(int exp) {
m_oldLevel = getCraftingLevel();
m_skillCraftExp = m_skillCraftExp + exp;
if(getCraftingLevel() > m_oldLevel) {
m_tcpSession.write("csC" + getCraftingLevel());
}
}
/**
* Returns the crafting skill exp points
* @return
*/
public int getCraftingExp() {
return m_skillCraftExp;
}
/**
* Returns the crafting skill level
* @return
*/
public int getCraftingLevel() {
if(((int)Math.pow(m_skillCraftExp, (0.3333))) <= 100)
return (int)Math.pow(m_skillCraftExp, (0.3333));
else
return 100;
}
/**
* Sets the fishing skill exp points
* @param exp
*/
public void setFishingExp(int exp) {
m_skillFishExp = exp;
}
/**
* Add something to the fishing skill exp points
* @param exp
*/
public void addFishingExp(int exp) {
m_oldLevel = getFishingLevel();
m_skillFishExp = m_skillFishExp + exp;
if(getFishingLevel() > m_oldLevel) {
m_tcpSession.write("csf" + getFishingLevel());
}
}
/**
* Returns the fishing skill exp points
* @return
*/
public int getFishingExp() {
return m_skillFishExp;
}
/**
* Returns the fishing skill level
* @return
*/
public int getFishingLevel() {
int level = ((int)Math.pow(m_skillFishExp, (0.3333)));
if(level <= 100)
return level;
else
return 100;
}
/**
* Set the training skill exp points
* @param exp
*/
public void setTrainingExp(int exp) {
m_skillTrainingExp = exp;
}
/**
* Add something to the training skill exp points
* @param exp
*/
public void addTrainingExp(int exp) {
m_oldLevel = getTrainingLevel();
m_skillTrainingExp = m_skillTrainingExp + exp;
if(getTrainingLevel() > m_oldLevel) {
m_tcpSession.write("cst" + getTrainingLevel());
}
}
/**
* Return the training skill exp points
* @return
*/
public int getTrainingExp() {
return m_skillTrainingExp;
}
/**
* Returns the training skill level
* @return
*/
public int getTrainingLevel() {
int level = ((int)Math.pow((m_skillTrainingExp/1.25), (0.3333)));
if (level <= 100)
return level;
else
return 100;
}
/**
* Sets the co-ordinating skill exp points
* @param exp
*/
public void setCoordinatingExp(int exp) {
m_skillCoordExp = exp;
}
/**
* Add something to the coordinating skill exp points
* @param exp
*/
public void addCoordinatingExp(int exp) {
m_oldLevel = getCoordinatingLevel();
m_skillCoordExp = m_skillCoordExp + exp;
if(getCoordinatingLevel() > m_oldLevel) {
m_tcpSession.write("csc" + getCoordinatingLevel());
}
}
/**
* Returns the co-ordinating skill exp points
* @return
*/
public int getCoordinatingExp() {
return m_skillCoordExp;
}
/**
* Returns the co-ordinating skill level
* @return
*/
public int getCoordinatingLevel() {
int level = ((int)Math.pow(m_skillCoordExp, (0.3333)));
if(level <= 100)
return level;
else
return 100;
}
/**
* Sets the breeding skill exp points
* @param exp
*/
public void setBreedingExp(int exp) {
m_skillBreedExp = exp;
}
/**
* Add something to the breeding skill exp points
* @param exp
*/
public void addBreedingExp(int exp) {
m_oldLevel = getBreedingLevel();
m_skillBreedExp = m_skillBreedExp + exp;
if(getBreedingLevel() > m_oldLevel) {
m_tcpSession.write("csb" + getBreedingLevel());
}
}
/**
* Returns the breeding skill exp
* @return
*/
public int getBreedingExp() {
return m_skillBreedExp;
}
/**
* Returns the breeding skill level
* @return
*/
public int getBreedingLevel() {
int level = (int)Math.pow((m_skillBreedExp/1.25), (0.3333));
if(level <= 100)
return level;
else
return 100;
}
/**
* Sets this player's boxes
* @param boxes
*/
public void setBoxes(PokemonBox [] boxes) {
m_boxes = boxes;
}
/**
* Returns this player's boxes
* @return
*/
public PokemonBox[] getBoxes() {
return m_boxes;
}
/**
* Stores a caught Pokemon in the player's party or box
* @param p
*/
public void catchPokemon(Pokemon p) {
Date d = new Date();
String date = new SimpleDateFormat ("yyyy-MM-dd:HH-mm-ss").format (d);
p.setDateCaught(date);
p.setOriginalTrainer(this.getName());
p.setDatabaseID(-1);
addPokemon(p);
addTrainingExp(1000/p.getRareness());
}
/**
* Adds a pokemon to this player's party or box
* @param p
*/
public void addPokemon(Pokemon p) {
/* See if there is space in the player's party */
for(int i = 0; i < 6; i++) {
if(m_pokemon[i] == null) {
m_pokemon[i] = p;
updateClientParty(i);
return;
}
}
/* Else, find space in a box */
for(int i = 0; i < m_boxes.length; i++) {
if(m_boxes[i] != null) {
/* Find space in an existing box */
for(int j = 0; j < m_boxes[i].getPokemon().length; j++) {
if(m_boxes[i].getPokemon(j) == null) {
m_boxes[i].setPokemon(j, p) ;
return;
}
}
} else {
/* We need a new box */
m_boxes[i] = new PokemonBox();
m_boxes[i].setPokemon(new Pokemon[30]);
m_boxes[i].setPokemon(0, p);
break;
}
}
}
/**
* Sets the last login time (used for connection downtimes)
* @param t
*/
public void setLastLoginTime(long t) {
m_lastLogin = t;
}
/**
* Returns the last login time
* @return
*/
public long getLastLoginTime() {
return m_lastLogin;
}
/**
* Returns the player's bag
* @return
*/
public Bag getBag() {
return m_bag;
}
/**
* Sets the player's bag
* @param b
*/
public void setBag(Bag b) {
m_bag = b;
}
/**
* Sets the map for this player
*/
@Override
public void setMap(ServerMap map, Direction dir) {
char direction = 'n';
if (dir != null) {
switch (dir) {
case Up:
direction = 'u';
break;
case Down:
direction = 'd';
break;
case Left:
direction = 'l';
break;
case Right:
direction = 'r';
break;
}
}
super.setMap(map, dir);
//Clear the requests list
clearRequests();
//Send the map switch packet to the client
m_tcpSession.write("ms" + direction + map.getX() + "," + map.getY() + "," + (map.isWeatherForced() ? map.getWeatherId() : TimeService.getWeatherId()));
Char c;
String packet = "mi";
//Send all player information to the client
for(PlayerChar p : map.getPlayers().values()) {
c = p;
packet = packet + c.getName() + "," +
c.getId() + "," + c.getSprite() + "," + c.getX() + "," + c.getY() + "," +
(c.getFacing() == Direction.Down ? "D" :
c.getFacing() == Direction.Up ? "U" :
c.getFacing() == Direction.Left ? "L" :
"R") + ",";
}
//Send all npc information to the client
for(int i = 0; i < map.getNpcs().size(); i++) {
c = map.getNpcs().get(i);
if(!c.getName().equalsIgnoreCase("NULL")) {
/* Send no name to indicate NPC */
packet = packet + "!NPC!," +
c.getId() + "," + c.getSprite() + "," + c.getX() + "," + c.getY() + "," +
(c.getFacing() == Direction.Down ? "D" :
c.getFacing() == Direction.Up ? "U" :
c.getFacing() == Direction.Left ? "L" :
"R") + ",";
}
}
/*
* Only send the packet if there were players on the map
*/
if(packet.length() > 2)
m_tcpSession.write(packet);
}
/**
* Disposes of this player char
*/
public void dispose() {
super.dispose();
m_pokemon = null;
m_boxes = null;
m_friends = null;
m_bag = null;
m_currentShop = null;
m_battleField = null;
}
/**
* Forces the player to be logged out
*/
public void forceLogout() {
if(m_tcpSession.isConnected()) {
m_tcpSession.close(true);
} else {
GameServer.getServiceManager().getNetworkService().getLogoutManager().queuePlayer(this);
}
}
/**
* Sets if this player is interacting with a shop npc
* @param b
*/
public void setShopping(boolean b) {
m_isShopping = b;
if(!b) {
m_currentShop = null;
}
}
/**
* Returns true if this player is shopping
* @return
*/
public boolean isShopping() {
return m_isShopping;
}
/**
* Returns true if the player has the badge
* @param badge
* @return
*/
public boolean hasBadge(int badge) {
return m_badges[badge] == 1;
}
/**
* Sets the badges this player has
* @param badges
*/
public void setBadges(byte [] badges) {
m_badges = badges;
}
/**
* Adds a badge to the player's badge collection
* @param num
*/
public void addBadge(int num) {
if(num >= 0 && num < m_badges.length) {
m_badges[num] = 1;
m_tcpSession.write("cBa" + num);
}
}
/**
* Generates the player's badges from a string
* @param badges
*/
public void generateBadges(String badges) {
m_badges = new byte[42];
if(badges == null || badges.equalsIgnoreCase("")) {
for(int i = 0; i < 42; i++)
m_badges[i] = 0;
} else {
for(int i = 0; i < 42; i++) {
if(badges.charAt(i) == '1')
m_badges[i] = 1;
else
m_badges[i] = 0;
}
}
}
/**
* Returns the badges of this player
* @return
*/
public byte[] getBadges() {
return m_badges;
}
/**
* Sets the admin level for this player
* @param adminLevel
*/
public void setAdminLevel(int adminLevel) {
m_adminLevel = adminLevel;
}
/**
* Returns the admin level of this player
* @return
*/
public int getAdminLevel() {
return m_adminLevel;
}
/**
* Sets the location this player was last healed at
* @param x
* @param y
* @param mapX
* @param mapY
*/
public void setLastHeal(int x, int y, int mapX, int mapY) {
m_healX = x;
m_healY = y;
m_healMapX = mapX;
m_healMapY = mapY;
}
/**
* Returns the x co-ordinate of this player's last heal point
* @return
*/
public int getHealX() {
return m_healX;
}
/**
* Returns the y co-ordinate of this player's last heal point
* @return
*/
public int getHealY() {
return m_healY;
}
/**
* Returns the map x of this player's last heal point
* @return
*/
public int getHealMapX() {
return m_healMapX;
}
/**
* Returns the map y of this player's last heal point
* @return
*/
public int getHealMapY() {
return m_healMapY;
}
/**
* Returns true if this player can surf
* @return
*/
public boolean canSurf() {
return (getTrainingLevel() >= 25);
}
/**
* Returns how many badges this player has
* @return
*/
public int getBadgeCount() {
int result = 0;
for(int i = 0; i < m_badges.length; i++) {
if(m_badges[i] == 1)
result++;
}
return result;
}
/**
* This player talks to the npc in front of them
*/
public void talkToNpc() {
if(m_map != null)
this.getMap().talkToNpc(this);
}
/**
* Sends box information to client
* @param i - Box number
*/
public void sendBoxInfo(int j) {
/* If box is non-existant, create it and send small packet */
if(m_boxes[j] == null) {
m_boxes[j] = new PokemonBox();
m_boxes[j].setPokemon(new Pokemon[30]);
m_tcpSession.write("B");
}
/* Else send all pokes in box */
String packet = "";
for(int i = 0; i < m_boxes[j].getPokemon().length; i++) {
if(m_boxes[j].getPokemon(i) != null)
packet = packet + m_boxes[j].getPokemon(i).getSpeciesNumber() + ",";
else
packet = packet + ",";
}
m_tcpSession.write("B" + packet);
}
/**
* Allows the player to buy an item
* @param id
* @param q
*/
public void buyItem(int id, int q) {
/* If the player isn't shopping, ignore this */
if(m_currentShop == null)
return;
if(m_bag.hasSpace(id)) {
/* First, check if the player can afford this */
if(m_money - (q * m_currentShop.getPriceForItem(id)) >= 0) {
/* Finally, if the item is in stock, buy it */
if(m_currentShop.buyItem(id, q)) {
m_money = m_money - (q * m_currentShop.getPriceForItem(id));
m_bag.addItem(id, q);
this.updateClientMoney();
//Let player know he bought the item
TcpProtocolHandler.writeMessage(m_tcpSession,
new ShopBuyMessage(GameServer.getServiceManager().getItemDatabase().getItem(id).getId()));
//Update player inventory
TcpProtocolHandler.writeMessage(m_tcpSession, new ItemMessage(true,
GameServer.getServiceManager().getItemDatabase().getItem(id).getId(), 1));
}
}else{
//Return You have no money, fool!
TcpProtocolHandler.writeMessage(m_tcpSession, new ShopNoMoneyMessage());
}
}else{
//Send You cant carry any more items!
TcpProtocolHandler.writeMessage(m_tcpSession, new ShopNoSpaceMessage());
}
}
/**
* Allows the player to sell an item
* @param id
* @param q
*/
public void sellItem(int id, int q) {
/* If the player isn't shopping, ignore this */
if(m_currentShop == null)
return;
if(m_bag.containsItem(id) > -1) { //Guy does have the item he's selling.
m_money = m_money + m_currentShop.sellItem(id, q);
m_bag.removeItem(id, q);
//Tell the client to remove the item from the player's inventory
TcpProtocolHandler.writeMessage(m_tcpSession, new ItemMessage(false,
GameServer.getServiceManager().getItemDatabase().getItem(id).getId(), q));
//Update the client's money
this.updateClientMoney();
//Let player know he sold the item.
TcpProtocolHandler.writeMessage(m_tcpSession,
new ShopSellMessage(GameServer.getServiceManager().getItemDatabase().getItem(id).getId()));
} else {
//Return You don't have that item, fool!
TcpProtocolHandler.writeMessage(m_tcpSession, new ShopNoItemMessage(GameServer.getServiceManager().getItemDatabase()
.getItem(id).getName()));
}
}
/**
* Updates the player's money clientside
*/
public void updateClientMoney() {
m_tcpSession.write("cM" + m_money);
}
/**
* Sends all badges to client
*/
public void updateClientBadges() {
String data = "";
for(int i = 0; i < m_badges.length; i++) {
data = data + m_badges[i];
}
m_tcpSession.write("cBi" + data);
}
/**
* Sends all party information to the client
*/
public void updateClientParty() {
for(int i = 0; i < this.getParty().length; i++) {
updateClientParty(i);
}
}
/**
* Sends all bag information to the client
*/
public void updateClientBag() {
for(int i = 0; i < this.getBag().getItems().size(); i++) {
updateClientBag(i);
}
}
/**
* Updates the client with their sprite
*/
public void updateClientSprite() {
TcpProtocolHandler.writeMessage(m_tcpSession, new SpriteChangeMessage(m_id, m_sprite));
}
/**
* Sets the battlefield for this player
*/
public void setBattleField(BattleField b) {
if(m_battleField == null)
m_battleField = b;
}
/**
* Returns the index of the pokemon in the player's party
* @param p
* @return
*/
public int getPokemonIndex(Pokemon p) {
for(int i = 0; i < m_pokemon.length; i++) {
if(m_pokemon[i] != null) {
if(p.compareTo(m_pokemon[i]) == 0)
return i;
}
}
return -1;
}
/**
* Updates the client for a specific Pokemon
* @param index
*/
public void updateClientParty(int i) {
if(this.getParty()[i] != null) {
m_tcpSession.write("Pi" + i + PokemonSpecies.getDefaultData().getPokemonByName(this.getParty()[i].getSpeciesName()).getSpeciesNumber() + "," +
this.getParty()[i].getName() + "," +
this.getParty()[i].getHealth() + "," +
this.getParty()[i].getGender() + "," +
(this.getParty()[i].isShiny() ? 1 : 0) + "," +
this.getParty()[i].getStat(0) + "," +
this.getParty()[i].getStat(1) + "," +
this.getParty()[i].getStat(2) + "," +
this.getParty()[i].getStat(3) + "," +
this.getParty()[i].getStat(4) + "," +
this.getParty()[i].getStat(5) + "," +
this.getParty()[i].getTypes()[0] + "," +
(this.getParty()[i].getTypes().length > 1 &&
this.getParty()[i].getTypes()[1] != null ? this.getParty()[i].getTypes()[1] + "," : ",") +
this.getParty()[i].getExp() + "," +
this.getParty()[i].getLevel() + "," +
this.getParty()[i].getAbilityName() + "," +
this.getParty()[i].getNature().getName() + "," +
(this.getParty()[i].getMoves()[0] != null ? this.getParty()[i].getMoveName(0) : "") + "," +
(this.getParty()[i].getMoves()[1] != null ? this.getParty()[i].getMoveName(1) : "") + "," +
(this.getParty()[i].getMoves()[2] != null ? this.getParty()[i].getMoveName(2) : "") + "," +
(this.getParty()[i].getMoves()[3] != null ? this.getParty()[i].getMoveName(3) : "")
);
/* Update move pp */
for(int j = 0; j < 4; j++) {
updateClientPP(i, j);
}
}
}
/**
* Updates stats for a Pokemon
* @param i
*/
public void updateClientPokemonStats(int i) {
if(m_pokemon[i] != null) {
m_tcpSession.write("PS" + i + m_pokemon[i].getHealth() + "," +
m_pokemon[i].getStat(0) + "," +
m_pokemon[i].getStat(1) + "," +
m_pokemon[i].getStat(2) + "," +
m_pokemon[i].getStat(3) + "," +
m_pokemon[i].getStat(4) + "," +
m_pokemon[i].getStat(5));
}
}
/**
* Updates the pp of a move
* @param poke
* @param move
*/
public void updateClientPP(int poke, int move) {
if(this.getParty()[poke] != null && this.getParty()[poke].getMove(move) != null)
m_tcpSession.write("Pp" + String.valueOf(poke) + String.valueOf(move)
+ this.getParty()[poke].getPp(move) + "," + this.getParty()[poke].getMaxPp(move));
}
/**
* Updates the client for a specific Item
* @param index
*/
public void updateClientBag(int i) {
if(this.getBag().getItems().get(i) != null) {
TcpProtocolHandler.writeMessage(m_tcpSession, new ItemMessage(true,
getBag().getItems().get(i).getItemNumber(),
getBag().getItems().get(i).getQuantity()));
}
}
}