/* * This program 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. This program 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 this program. If * not, see <http://www.gnu.org/licenses/>. */ package silentium.gameserver.model.actor.stat; import silentium.gameserver.configs.MainConfig; import silentium.gameserver.configs.PlayersConfig; import silentium.gameserver.model.actor.L2Character; import silentium.gameserver.model.actor.instance.L2PcInstance; import silentium.gameserver.model.actor.instance.L2PetInstance; import silentium.gameserver.model.base.Experience; import silentium.gameserver.model.quest.QuestState; import silentium.gameserver.network.SystemMessageId; import silentium.gameserver.network.serverpackets.PledgeShowMemberListUpdate; import silentium.gameserver.network.serverpackets.SocialAction; import silentium.gameserver.network.serverpackets.StatusUpdate; import silentium.gameserver.network.serverpackets.SystemMessage; import silentium.gameserver.network.serverpackets.UserInfo; import silentium.gameserver.skills.Stats; import silentium.gameserver.tables.NpcTable; import silentium.gameserver.tables.PetDataTable; import silentium.gameserver.utils.Util; public class PcStat extends PlayableStat { private int _oldMaxHp; // stats watch private int _oldMaxMp; // stats watch private int _oldMaxCp; // stats watch public PcStat(L2PcInstance activeChar) { super(activeChar); } @Override public boolean addExp(long value) { L2PcInstance activeChar = getActiveChar(); // Allowed to gain exp? if (!getActiveChar().getAccessLevel().canGainExp()) return false; if (!super.addExp(value)) return false; // Set new karma if (!activeChar.isCursedWeaponEquipped() && activeChar.getKarma() > 0 && !activeChar.isInsideZone(L2Character.ZONE_PVP)) { int karmaLost = activeChar.calculateKarmaLost(value); if (karmaLost > 0) activeChar.setKarma(activeChar.getKarma() - karmaLost); } activeChar.sendPacket(new UserInfo(activeChar)); return true; } /** * Add Experience and SP rewards to the L2PcInstance, remove its Karma (if necessary) and Launch increase level task.<BR> * <BR> * <B><U> Actions </U> :</B><BR> * <BR> * <li>Remove Karma when the player kills L2MonsterInstance</li> <li>Send a Server->Client packet StatusUpdate to the L2PcInstance</li> <li> * Send a Server->Client System Message to the L2PcInstance</li> <li>If the L2PcInstance increases it's level, send a Server->Client packet * SocialAction (broadcast)</li> <li>If the L2PcInstance increases it's level, manage the increase level task (Max MP, Max MP, * Recommandation, Expertise and beginner skills...)</li> <li>If the L2PcInstance increases it's level, send a Server->Client packet UserInfo * to the L2PcInstance</li><BR> * <BR> * * @param addToExp * The Experience value to add * @param addToSp * The SP value to add */ @Override public boolean addExpAndSp(long addToExp, int addToSp) { float ratioTakenByPet = 0; // Player is Gm and acces level is below or equal to GM_DONT_TAKE_EXPSP and is in party, don't give Xp/Sp L2PcInstance activeChar = getActiveChar(); if (!activeChar.getAccessLevel().canGainExp()) return false; // if this player has a pet that takes from the owner's Exp, give the pet Exp now if (activeChar.hasPet()) { final L2PetInstance pet = (L2PetInstance) activeChar.getPet(); if (pet.getStat().getExp() <= (PetDataTable.getInstance().getPetLevelData(pet.getNpcId(), 81).getPetMaxExp() + 10000)) { if (Util.checkIfInShortRadius(PlayersConfig.ALT_PARTY_RANGE, pet, activeChar, true)) { ratioTakenByPet = pet.getPetLevelData().getOwnerExpTaken(); // only give exp/sp to the pet by taking from the owner if the pet has a positive ratio // allow possible customizations that would have the pet earning more than 100% of the // owner's exp/sp if (ratioTakenByPet > 0 && !pet.isDead()) pet.addExpAndSp((long) (addToExp * ratioTakenByPet), (int) (addToSp * ratioTakenByPet)); // now adjust the max ratio to avoid the owner earning negative exp/sp if (ratioTakenByPet > 1) ratioTakenByPet = 1; addToExp = (long) (addToExp * (1 - ratioTakenByPet)); addToSp = (int) (addToSp * (1 - ratioTakenByPet)); } } } if (!super.addExpAndSp(addToExp, addToSp)) return false; if (addToExp == 0 && addToSp > 0) { SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.ACQUIRED_S1_SP); sm.addNumber(addToSp); activeChar.sendPacket(sm); } else if (addToExp > 0 && addToSp == 0) { SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.EARNED_S1_EXPERIENCE); sm.addNumber((int) addToExp); activeChar.sendPacket(sm); } else { SystemMessage sm = SystemMessage.getSystemMessage(SystemMessageId.YOU_EARNED_S1_EXP_AND_S2_SP); sm.addNumber((int) addToExp); sm.addNumber(addToSp); activeChar.sendPacket(sm); } return true; } @Override public boolean removeExpAndSp(long removeExp, int removeSp) { return removeExpAndSp(removeExp, removeSp, true); } public boolean removeExpAndSp(long removeExp, int removeSp, boolean sendMessage) { int level = getLevel(); if (!super.removeExpAndSp(removeExp, removeSp)) return false; // Send messages. if (sendMessage) { getActiveChar().sendPacket(SystemMessage.getSystemMessage(SystemMessageId.EXP_DECREASED_BY_S1).addNumber((int) removeExp)); getActiveChar().sendPacket(SystemMessage.getSystemMessage(SystemMessageId.SP_DECREASED_S1).addNumber(removeSp)); if (getLevel() < level) getActiveChar().broadcastStatusUpdate(); } return true; } @Override public final boolean addLevel(byte value) { if (getLevel() + value > Experience.MAX_LEVEL - 1) return false; boolean levelIncreased = super.addLevel(value); if (levelIncreased) { if (!MainConfig.DISABLE_TUTORIAL) { QuestState qs = getActiveChar().getQuestState("Tutorial"); if (qs != null) qs.getQuest().notifyEvent("CE40", null, getActiveChar()); } // If player reaches level 6, verify if the newbie value is already sets. if (getActiveChar().getLevel() == 6 && getActiveChar().getNewbieState() == 0) getActiveChar().updateNewbieState(); getActiveChar().setCurrentCp(getMaxCp()); getActiveChar().broadcastPacket(new SocialAction(getActiveChar(), 15)); getActiveChar().sendPacket(SystemMessageId.YOU_INCREASED_YOUR_LEVEL); } getActiveChar().rewardSkills(); // Give Expertise skill of this level if (getActiveChar().getClan() != null) { getActiveChar().getClan().updateClanMember(getActiveChar()); getActiveChar().getClan().broadcastToOnlineMembers(new PledgeShowMemberListUpdate(getActiveChar())); } if (getActiveChar().isInParty()) getActiveChar().getParty().recalculatePartyLevel(); // Recalculate the party level StatusUpdate su = new StatusUpdate(getActiveChar()); su.addAttribute(StatusUpdate.LEVEL, getLevel()); su.addAttribute(StatusUpdate.MAX_CP, getMaxCp()); su.addAttribute(StatusUpdate.MAX_HP, getMaxHp()); su.addAttribute(StatusUpdate.MAX_MP, getMaxMp()); getActiveChar().sendPacket(su); // Update the overloaded status of the L2PcInstance getActiveChar().refreshOverloaded(); // Update the expertise status of the L2PcInstance getActiveChar().refreshExpertisePenalty(); // Send a Server->Client packet UserInfo to the L2PcInstance getActiveChar().sendPacket(new UserInfo(getActiveChar())); return levelIncreased; } @Override public boolean addSp(int value) { if (!super.addSp(value)) return false; StatusUpdate su = new StatusUpdate(getActiveChar()); su.addAttribute(StatusUpdate.SP, getSp()); getActiveChar().sendPacket(su); return true; } @Override public final long getExpForLevel(int level) { return Experience.LEVEL[level]; } @Override public final L2PcInstance getActiveChar() { return (L2PcInstance) super.getActiveChar(); } @Override public final long getExp() { if (getActiveChar().isSubClassActive()) return getActiveChar().getSubClasses().get(getActiveChar().getClassIndex()).getExp(); return super.getExp(); } @Override public final void setExp(long value) { if (getActiveChar().isSubClassActive()) getActiveChar().getSubClasses().get(getActiveChar().getClassIndex()).setExp(value); else super.setExp(value); } @Override public final byte getLevel() { if (getActiveChar().isSubClassActive()) return getActiveChar().getSubClasses().get(getActiveChar().getClassIndex()).getLevel(); return super.getLevel(); } @Override public final void setLevel(byte value) { if (value > Experience.MAX_LEVEL - 1) value = Experience.MAX_LEVEL - 1; if (getActiveChar().isSubClassActive()) getActiveChar().getSubClasses().get(getActiveChar().getClassIndex()).setLevel(value); else super.setLevel(value); } @Override public final int getMaxCp() { // Get the Max CP (base+modifier) of the L2PcInstance int val = super.getMaxCp(); if (val != _oldMaxCp) { _oldMaxCp = val; // Launch a regen task if the new Max CP is higher than the old one if (getActiveChar().getStatus().getCurrentCp() != val) getActiveChar().getStatus().setCurrentCp(getActiveChar().getStatus().getCurrentCp()); // trigger start of // regeneration } return val; } @Override public final int getMaxHp() { // Get the Max HP (base+modifier) of the L2PcInstance int val = super.getMaxHp(); if (val != _oldMaxHp) { _oldMaxHp = val; // Launch a regen task if the new Max HP is higher than the old one if (getActiveChar().getStatus().getCurrentHp() != val) getActiveChar().getStatus().setCurrentHp(getActiveChar().getStatus().getCurrentHp()); // trigger start of // regeneration } return val; } @Override public final int getMaxMp() { // Get the Max MP (base+modifier) of the L2PcInstance int val = super.getMaxMp(); if (val != _oldMaxMp) { _oldMaxMp = val; // Launch a regen task if the new Max MP is higher than the old one if (getActiveChar().getStatus().getCurrentMp() != val) getActiveChar().getStatus().setCurrentMp(getActiveChar().getStatus().getCurrentMp()); // trigger start of // regeneration } return val; } @Override public final int getSp() { if (getActiveChar().isSubClassActive()) return getActiveChar().getSubClasses().get(getActiveChar().getClassIndex()).getSp(); return super.getSp(); } @Override public final void setSp(int value) { if (getActiveChar().isSubClassActive()) getActiveChar().getSubClasses().get(getActiveChar().getClassIndex()).setSp(value); else super.setSp(value); } @Override public int getRunSpeed() { if (getActiveChar() == null) return 1; int val; L2PcInstance player = getActiveChar(); if (player.isMounted()) { int baseRunSpd = NpcTable.getInstance().getTemplate(getActiveChar().getMountNpcId()).getBaseRunSpd(); val = (int) (calcStat(Stats.RUN_SPEED, baseRunSpd, null, null)); } else val = super.getRunSpeed(); return val; } @Override public float getMovementSpeedMultiplier() { if (getActiveChar() == null) return 1; if (getActiveChar().isMounted()) return getRunSpeed() * 1f / NpcTable.getInstance().getTemplate(getActiveChar().getMountNpcId()).getBaseRunSpd(); return super.getMovementSpeedMultiplier(); } @Override public int getWalkSpeed() { if (getActiveChar() == null) return 1; return (getRunSpeed() * 70) / 100; } }