package org.pokenet.server.backend.entity;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;
import org.pokenet.server.battle.DataService;
import org.pokenet.server.battle.Pokemon;
import org.pokenet.server.battle.impl.NpcBattleField;
import org.pokenet.server.network.TcpProtocolHandler;
import org.pokenet.server.network.message.NpcSpeechMessage;
import org.pokenet.server.network.message.SpriteSelectMessage;
import org.pokenet.server.network.message.shop.ShopStockMessage;
/**
* Represents a Non Playable Character
* @author shadowkanji
*
*/
public class NonPlayerChar extends Char {
/*
* Trainers can have an more than 6 possible Pokemon.
* When a battle is started with this NPC, it'll check the min party size.
* If you have a party bigger than min party,
* it'll generate a party of random size between minParty and your party size + 1.
* (Unless your party size is 6)
*/
private HashMap<String, Integer> m_possiblePokemon;
private int m_minPartySize = 1;
private boolean m_isBox = false;
private boolean m_isHeal = false;
private int m_isShop = 0;
private int m_badge = -1;
private ArrayList<Integer> m_speech;
private Shop m_shop = null;
private long m_lastBattle = 0;
/**
* Constructor
*/
public NonPlayerChar() {}
/**
* Returns a string of this npcs speech ids
* @param p
*/
private String getSpeech() {
String result = "";
for(int i = 0; i < m_speech.size(); i++) {
result = result + m_speech.get(i) + ",";
}
return result;
}
/**
* Returns true if this NPC can battle
* @return
*/
public boolean canBattle() {
return m_lastBattle == 0;
}
/**
* Sets the time this NPC last battled
* @param l
*/
public void setLastBattleTime(long l) {
/* Only set this if they are not gym leaders */
if(!isGymLeader())
m_lastBattle = l;
}
/**
* Returns the time this NPC last battled
* NOTE: Is valued 0 if the NPC is able to battle
* @return
*/
public long getLastBattleTime() {
return m_lastBattle;
}
/**
* Challenges a player (NOTE: Should only be called from NpcBattleLauncher)
* @param p
*/
public void challengePlayer(PlayerChar p) {
String speech = this.getSpeech();
if(!speech.equalsIgnoreCase("")) {
TcpProtocolHandler.writeMessage(p.getTcpSession(), new NpcSpeechMessage(speech));
}
}
/**
* Talks to a player
* @param p
*/
public void talkToPlayer(PlayerChar p) {
if(isTrainer()) {
if(canBattle()) {
String speech = this.getSpeech();
if(!speech.equalsIgnoreCase("")) {
TcpProtocolHandler.writeMessage(p.getTcpSession(), new NpcSpeechMessage(speech));
}
setLastBattleTime(System.currentTimeMillis());
p.setBattling(true);
p.setBattleField(new NpcBattleField(DataService.getBattleMechanics(), p, this));
return;
} else {
p.setTalking(false);
return;
}
} else {
/* If this NPC wasn't a trainer, handle other possibilities */
String speech = this.getSpeech();
if(!speech.equalsIgnoreCase("")) {
if(!p.isShopping()) {
//Dont send if player is shopping!
TcpProtocolHandler.writeMessage(p.getTcpSession(), new NpcSpeechMessage(speech));
}
}
/* If this NPC is a sprite selection npc */
if(m_name.equalsIgnoreCase("Spriter")) {
p.setSpriting(true);
TcpProtocolHandler.writeMessage(p.getTcpSession(), new SpriteSelectMessage());
return;
}
/* Box access */
if(m_isBox) {
//Send the data for the player's first box, they may change this later
p.setTalking(false);
p.setBoxing(true);
p.sendBoxInfo(0);
}
/* Healer */
if(m_isHeal) {
p.healPokemon();
p.setLastHeal(p.getX(), p.getY(), p.getMapX(), p.getMapY());
}
/* Shop access */
if(m_isShop>0) { //0 is not a shop, over 0 means some kind of shop.
//Send shop packet to display shop window clientside
if(!p.isShopping()){ //Dont display if user's shopping
TcpProtocolHandler.writeMessage(p.getTcpSession(), new ShopStockMessage(m_shop.getStockData()));
p.setShopping(true);
p.setShop(m_shop);
}
}
}
}
/**
* Returns true if this npc can see the player
* @param p
* @return
*/
public boolean canSee(PlayerChar p) {
if(!p.isBattling() && !isGymLeader() && canBattle()) {
Random r = new Random();
switch(this.getFacing()) {
case Up:
if(p.getY() >= this.getY() - (32 * (r.nextInt(4) + 1)))
return true;
break;
case Down:
if(p.getY() <= this.getY() + (32 * (r.nextInt(4) + 1)))
return true;
break;
case Left:
if(p.getX() >= this.getX() - (32 * (r.nextInt(4) + 1)))
return true;
break;
case Right:
if(p.getX() <= this.getX() + (32 * (r.nextInt(4) + 1)))
return true;
break;
}
}
return false;
}
/**
* Adds speech to this npc
* @param id
*/
public void addSpeech(int id) {
if(m_speech == null)
m_speech = new ArrayList<Integer>();
m_speech.add(id);
}
/**
* Returns true if the npc is a gym leader
* @return
*/
public boolean isGymLeader() {
return m_badge > -1;
}
/**
* Returns true if an NPC is a trainer
* @return
*/
public boolean isTrainer() {
return m_possiblePokemon != null && m_minPartySize > 0 && m_possiblePokemon.size() > 0;
}
/**
* Return true if this npc heals your pokemon
* @return
*/
public boolean isHealer() {
return m_isHeal;
}
/**
* Sets if this npc is a healer or not
* @param b
*/
public void setHealer(boolean b) {
m_isHeal = b;
}
/**
* Returns true if this npc is a shop keeper
* @return
*/
public boolean isShopKeeper() {
if(m_isShop>0)
return true;
else
return false;
}
/**
* Returns true if this npc allows box access
* @return
*/
public boolean isBox() {
return m_isBox;
}
/**
* Sets if this npc allows box access
* @param b
*/
public void setBox(boolean b) {
m_isBox = b;
}
/**
* Sets if this npc is a shop keeper
* @param b
*/
public void setShopKeeper(int b) {
m_isShop = b;
if(b>0) {
try{
m_shop = new Shop(b);
m_shop.start();
} catch (Exception e){e.printStackTrace();}
}
}
/**
* Sets the possible Pokemon this trainer can have
* @param pokes
*/
public void setPossiblePokemon(HashMap<String, Integer> pokes) {
m_possiblePokemon = pokes;
}
/**
* Sets the badge this npc gives, if any
* @param i
*/
public void setBadge(int i) {
m_badge = i;
}
/**
* Returns the number of the badge this npc gives. -1 if no badge.
* @return
*/
public int getBadge() {
return m_badge;
}
/**
* Sets the minimum sized party this npc should have
* @param size
*/
public void setPartySize(int size) {
m_minPartySize = (size > 6 ? 6 : size);
}
/**
* Returns a dynamically generated Pokemon party based on how well trained a player is
* @param p
* @return
*/
public Pokemon [] getParty(PlayerChar p) {
Pokemon [] party = new Pokemon[6];
Pokemon poke;
int level;
String name;
Random r = DataService.getBattleMechanics().getRandom();
if(isGymLeader()) {
if(p.getBadgeCount() > 7) {
/* If a player has 8 badges, level 80s all round */
for(int i = 0; i < 6; i++) {
name = (String) m_possiblePokemon.keySet().toArray()[r.nextInt(m_possiblePokemon.keySet().size())];
level = 80;
poke = Pokemon.getRandomPokemon(name, level);
party[i] = poke;
}
} else {
/* If a player hasn't got 8 badges, give them normal levels */
for(int i = 0; i < m_minPartySize; i++) {
name = (String) m_possiblePokemon.keySet().toArray()[r.nextInt(m_possiblePokemon.keySet().size())];
level = m_possiblePokemon.get(name);
poke = Pokemon.getRandomPokemon(name, level);
party[i] = poke;
}
}
} else {
int playerPartySize = p.getPartyCount();
if(m_minPartySize < playerPartySize && m_possiblePokemon.size() >= playerPartySize + 1) {
/*
* The player has more Pokemon, generate a random party
*/
/*
* First, get a random party size that is greater than m_minPartySize
* and less than or equal to the amount of pokemon in the player's party + 1
*/
int pSize = r.nextInt(playerPartySize + 1 > 6 ? 6 : playerPartySize + 1);
while(pSize < m_minPartySize) {
pSize = r.nextInt(playerPartySize + 1 > 6 ? 6 : playerPartySize + 1);
}
/*
* Now generate the random Pokemon
*/
for(int i = 0; i <= pSize; i++) {
//Select a random Pokemon
name = (String) m_possiblePokemon.keySet().toArray()[r.nextInt(m_possiblePokemon.keySet().size())];
level = m_possiblePokemon.get(name);
/* Level scaling */
/*while(level < p.getHighestLevel() - 3) {
level = r.nextInt(p.getHighestLevel() + 5);
}*/
poke = Pokemon.getRandomPokemon(name, level);
party[i] = poke;
}
} else {
/*
* Generate a party of size m_minPartySize
*/
for(int i = 0; i < m_minPartySize; i++) {
//Select a random Pokemon from this list of possible Pokemons
name = (String) m_possiblePokemon.keySet().toArray()[r.nextInt(m_possiblePokemon.keySet().size())];
level = m_possiblePokemon.get(name);
//Ensure levels are the similiar
/*while(level < p.getHighestLevel() - 3) {
level = r.nextInt(p.getHighestLevel() + 5);
}*/
poke = Pokemon.getRandomPokemon(name, level);
party[i] = poke;
}
}
}
return party;
}
}