/*
* This file is part of aion-emu <aion-emu.com>.
*
* aion-emu is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* aion-emu is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with aion-emu. If not, see <http://www.gnu.org/licenses/>.
*/
package com.aionemu.gameserver.model.gameobjects.player;
import java.sql.Timestamp;
import org.apache.log4j.Logger;
import com.aionemu.gameserver.dataholders.DataManager;
import com.aionemu.gameserver.dataholders.StaticData;
import com.aionemu.gameserver.model.Gender;
import com.aionemu.gameserver.model.PlayerClass;
import com.aionemu.gameserver.model.Race;
import com.aionemu.gameserver.model.gameobjects.stats.StatEnum;
import com.aionemu.gameserver.model.templates.VisibleObjectTemplate;
import com.aionemu.gameserver.network.aion.serverpackets.SM_DP_INFO;
import com.aionemu.gameserver.network.aion.serverpackets.SM_STATS_INFO;
import com.aionemu.gameserver.network.aion.serverpackets.SM_STATUPDATE_DP;
import com.aionemu.gameserver.network.aion.serverpackets.SM_STATUPDATE_EXP;
import com.aionemu.gameserver.network.aion.serverpackets.SM_SYSTEM_MESSAGE;
import com.aionemu.gameserver.utils.PacketSendUtility;
import com.aionemu.gameserver.utils.stats.XPLossEnum;
import com.aionemu.gameserver.world.WorldPosition;
/**
* This class is holding base information about player, that may be used even when player itself is not online.
*
* @author Luno
*
*/
public class PlayerCommonData extends VisibleObjectTemplate
{
/** Logger used by this class and {@link StaticData} class */
static Logger log = Logger.getLogger(PlayerCommonData.class);
private final int playerObjId;
private Race race;
private String name;
private PlayerClass playerClass;
/** Should be changed right after character creation **/
private int level = 0;
private long exp = 0;
private long expRecoverable = 0;
private Gender gender;
private Timestamp lastOnline;
private boolean online;
private String note;
private WorldPosition position;
private int cubeSize = 0;
private int warehouseSize = 0;
private int bindPoint;
private int titleId = -1;
private int dp = 0;
private int mailboxLetters;
public PlayerCommonData(int objId)
{
this.playerObjId = objId;
}
public int getPlayerObjId()
{
return playerObjId;
}
public long getExp()
{
return this.exp;
}
public int getCubeSize()
{
return this.cubeSize;
}
public void setCubesize(int cubeSize)
{
this.cubeSize = cubeSize;
}
public long getExpShown()
{
return this.exp - DataManager.PLAYER_EXPERIENCE_TABLE.getStartExpForLevel(this.level);
}
public long getExpNeed()
{
if (this.level == DataManager.PLAYER_EXPERIENCE_TABLE.getMaxLevel())
{
return 0;
}
return DataManager.PLAYER_EXPERIENCE_TABLE.getStartExpForLevel(this.level + 1) - DataManager.PLAYER_EXPERIENCE_TABLE.getStartExpForLevel(this.level);
}
/**
* calculate the lost experience
* must be called before setexp
* @author Jangan
*/
public void calculateExpLoss()
{
long expLost = XPLossEnum.getExpLoss(this.level, this.getExpNeed()); // This Calculates all the exp lost when dieing.
int unrecoverable = (int) (expLost * 0.33333333); // This is 1000% Correct
int recoverable = (int) expLost - unrecoverable;// This is 1000% Correct
long allExpLost = recoverable + this.expRecoverable; // lol some crack headed formula ???
// This loops states that if the unrecoverable exp is bigger than your current exp
// we delete all your exp and go back to 0 pretty much.
if(this.getExpShown() > unrecoverable)
{
this.exp = this.exp - unrecoverable;
}
else
{
this.exp = this.exp - this.getExpShown();
}
if(this.getExpShown() > allExpLost)
{
this.expRecoverable = allExpLost;
this.exp = this.exp - recoverable;
}
else
{
this.expRecoverable = this.expRecoverable + this.getExpShown();
this.exp = this.exp - this.getExpShown();
}
PacketSendUtility.sendPacket(this.getPlayer(), new SM_STATUPDATE_EXP(this.getExpShown(), this
.getExpRecoverable(), this.getExpNeed()));
}
public void setRecoverableExp(long expRecoverable)
{
this.expRecoverable = expRecoverable;
}
public void resetRecoverableExp()
{
long el = this.expRecoverable;
this.expRecoverable = 0;
this.setExp(this.exp + el);
}
public long getExpRecoverable()
{
return this.expRecoverable;
}
/**
*
* @param value
*/
public void addExp(long value)
{
this.setExp(this.exp + value);
if(this.getPlayer() != null)
{
PacketSendUtility.sendPacket(this.getPlayer(),SM_SYSTEM_MESSAGE.EXP(Long.toString(value)));
}
}
/**
* sets the exp value
* @param exp
*/
public void setExp(long exp)
{
//maxLevel is 51 but in game 50 should be shown with full XP bar
int maxLevel = DataManager.PLAYER_EXPERIENCE_TABLE.getMaxLevel();
if (getPlayerClass() != null && getPlayerClass().isStartingClass())
maxLevel = 10;
long maxExp = DataManager.PLAYER_EXPERIENCE_TABLE.getStartExpForLevel(maxLevel);
int level = 1;
if (exp > maxExp)
{
exp = maxExp;
}
//make sure level is never larger than maxLevel-1
while ((level + 1) != maxLevel && exp >= DataManager.PLAYER_EXPERIENCE_TABLE.getStartExpForLevel(level + 1))
{
level++;
}
if (level != this.level)
{
this.level = level;
this.exp = exp;
if(this.getPlayer() != null)
{
upgradePlayer();
}
}
else
{
this.exp = exp;
if(this.getPlayer() != null)
{
PacketSendUtility.sendPacket(this.getPlayer(),
new SM_STATUPDATE_EXP(this.getExpShown(), this.getExpRecoverable(), this.getExpNeed()));
}
}
}
/**
* Do necessary player upgrades on level up
*/
public void upgradePlayer()
{
Player player = this.getPlayer();
if(player != null)
{
player.getController().upgradePlayer(level);
}
}
public Race getRace()
{
return race;
}
public void setRace(Race race)
{
this.race = race;
}
@Override
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public PlayerClass getPlayerClass()
{
return playerClass;
}
public void setPlayerClass(PlayerClass playerClass)
{
this.playerClass = playerClass;
}
public boolean isOnline()
{
return online;
}
public void setOnline(boolean online)
{
this.online = online;
}
public Gender getGender()
{
return gender;
}
public void setGender(Gender gender)
{
this.gender = gender;
}
public WorldPosition getPosition()
{
return position;
}
public Timestamp getLastOnline()
{
return lastOnline;
}
public void setBindPoint(int bindId)
{
this.bindPoint = bindId;
}
public int getBindPoint()
{
return bindPoint;
}
public void setLastOnline(Timestamp timestamp)
{
lastOnline = timestamp;
}
public int getLevel()
{
return level;
}
public void setLevel(int level)
{
if (level <= DataManager.PLAYER_EXPERIENCE_TABLE.getMaxLevel())
{
this.setExp(DataManager.PLAYER_EXPERIENCE_TABLE.getStartExpForLevel(level));
}
}
public String getNote()
{
return note;
}
public void setNote(String note)
{
this.note = note;
}
public int getTitleId()
{
return titleId;
}
public void setTitleId(int titleId)
{
this.titleId = titleId;
}
/**
* This method should be called exactly once after creating object of this class
* @param position
*/
public void setPosition(WorldPosition position)
{
if(this.position != null)
{
throw new IllegalStateException("position already set");
}
this.position = position;
}
/**
* Gets the cooresponding Player for this common data.
* Returns null if the player is not online
* @return Player or null
*/
public Player getPlayer()
{
if (online && getPosition() != null)
{
return getPosition().getWorld().findPlayer(playerObjId);
}
return null;
}
public void addDp(int dp)
{
setDp(this.dp + dp);
}
/**
* //TODO move to lifestats -> db save?
*
* @param dp
*/
public void setDp(int dp)
{
if(getPlayer() != null)
{
if(playerClass.isStartingClass())
return;
int maxDp = getPlayer().getGameStats().getCurrentStat(StatEnum.MAXDP);
this.dp = dp > maxDp ? maxDp : dp;
PacketSendUtility.broadcastPacket(getPlayer(), new SM_DP_INFO(playerObjId, this.dp), true);
PacketSendUtility.sendPacket(getPlayer(), new SM_STATS_INFO(getPlayer()));
PacketSendUtility.sendPacket(getPlayer(), new SM_STATUPDATE_DP(this.dp));
}
else
{
log.warn("CHECKPOINT : getPlayer in PCD return null for setDP " + isOnline() + " " + getPosition());
}
}
public int getDp()
{
return this.dp;
}
@Override
public int getTemplateId()
{
return 100000 + race.getRaceId()*2 + gender.getGenderId();
}
@Override
public int getNameId()
{
return 0;
}
/**
* @param warehouseSize the warehouseSize to set
*/
public void setWarehouseSize(int warehouseSize)
{
this.warehouseSize = warehouseSize;
}
/**
* @return the warehouseSize
*/
public int getWarehouseSize()
{
return warehouseSize;
}
public void setMailboxLetters(int count)
{
this.mailboxLetters = count;
}
public int getMailboxLetters()
{
return mailboxLetters;
}
}