/*
* Copyright (C) 2004-2015 L2J Server
*
* This file is part of L2J Server.
*
* L2J Server 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.
*
* L2J Server 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 com.l2jserver.gameserver.model.actor;
import com.l2jserver.gameserver.ai.CtrlEvent;
import com.l2jserver.gameserver.enums.InstanceType;
import com.l2jserver.gameserver.instancemanager.InstanceManager;
import com.l2jserver.gameserver.model.L2Object;
import com.l2jserver.gameserver.model.actor.instance.L2PcInstance;
import com.l2jserver.gameserver.model.actor.knownlist.PlayableKnownList;
import com.l2jserver.gameserver.model.actor.stat.PlayableStat;
import com.l2jserver.gameserver.model.actor.status.PlayableStatus;
import com.l2jserver.gameserver.model.actor.templates.L2CharTemplate;
import com.l2jserver.gameserver.model.effects.EffectFlag;
import com.l2jserver.gameserver.model.effects.L2EffectType;
import com.l2jserver.gameserver.model.entity.Instance;
import com.l2jserver.gameserver.model.events.EventDispatcher;
import com.l2jserver.gameserver.model.events.impl.character.OnCreatureKill;
import com.l2jserver.gameserver.model.events.returns.TerminateReturn;
import com.l2jserver.gameserver.model.quest.QuestState;
import com.l2jserver.gameserver.model.skills.Skill;
import com.l2jserver.gameserver.network.serverpackets.EtcStatusUpdate;
/**
* This class represents all Playable characters in the world.<br>
* L2Playable:
* <ul>
* <li>L2PcInstance</li>
* <li>L2Summon</li>
* </ul>
*/
public abstract class L2Playable extends L2Character
{
private L2Character _lockedTarget = null;
private L2PcInstance transferDmgTo = null;
/**
* Creates an abstract playable creature.
* @param objectId the playable object ID
* @param template the creature template
*/
public L2Playable(int objectId, L2CharTemplate template)
{
super(objectId, template);
setInstanceType(InstanceType.L2Playable);
setIsInvul(false);
}
public L2Playable(L2CharTemplate template)
{
super(template);
setInstanceType(InstanceType.L2Playable);
setIsInvul(false);
}
@Override
public PlayableKnownList getKnownList()
{
return (PlayableKnownList) super.getKnownList();
}
@Override
public void initKnownList()
{
setKnownList(new PlayableKnownList(this));
}
@Override
public PlayableStat getStat()
{
return (PlayableStat) super.getStat();
}
@Override
public void initCharStat()
{
setStat(new PlayableStat(this));
}
@Override
public PlayableStatus getStatus()
{
return (PlayableStatus) super.getStatus();
}
@Override
public void initCharStatus()
{
setStatus(new PlayableStatus(this));
}
@Override
public boolean doDie(L2Character killer)
{
final TerminateReturn returnBack = EventDispatcher.getInstance().notifyEvent(new OnCreatureKill(killer, this), this, TerminateReturn.class);
if ((returnBack != null) && returnBack.terminate())
{
return false;
}
// killing is only possible one time
synchronized (this)
{
if (isDead())
{
return false;
}
// now reset currentHp to zero
setCurrentHp(0);
setIsDead(true);
}
// Set target to null and cancel Attack or Cast
setTarget(null);
// Stop movement
stopMove(null);
// Stop HP/MP/CP Regeneration task
getStatus().stopHpMpRegeneration();
boolean deleteBuffs = true;
if (isNoblesseBlessedAffected())
{
stopEffects(L2EffectType.NOBLESSE_BLESSING);
deleteBuffs = false;
}
if (isResurrectSpecialAffected())
{
stopEffects(L2EffectType.RESURRECTION_SPECIAL);
deleteBuffs = false;
}
if (isPlayer())
{
L2PcInstance activeChar = getActingPlayer();
if (activeChar.hasCharmOfCourage())
{
if (activeChar.isInSiege())
{
getActingPlayer().reviveRequest(getActingPlayer(), null, false, 0);
}
activeChar.setCharmOfCourage(false);
activeChar.sendPacket(new EtcStatusUpdate(activeChar));
}
}
if (deleteBuffs)
{
stopAllEffectsExceptThoseThatLastThroughDeath();
}
// Send the Server->Client packet StatusUpdate with current HP and MP to all other L2PcInstance to inform
broadcastStatusUpdate();
if (getWorldRegion() != null)
{
getWorldRegion().onDeath(this);
}
// Notify Quest of L2Playable's death
L2PcInstance actingPlayer = getActingPlayer();
if (!actingPlayer.isNotifyQuestOfDeathEmpty())
{
for (QuestState qs : actingPlayer.getNotifyQuestOfDeath())
{
qs.getQuest().notifyDeath((killer == null ? this : killer), this, qs);
}
}
// Notify instance
if (getInstanceId() > 0)
{
final Instance instance = InstanceManager.getInstance().getInstance(getInstanceId());
if (instance != null)
{
instance.notifyDeath(killer, this);
}
}
if (killer != null)
{
L2PcInstance player = killer.getActingPlayer();
if (player != null)
{
player.onKillUpdatePvPKarma(this);
}
}
// Notify L2Character AI
getAI().notifyEvent(CtrlEvent.EVT_DEAD);
super.updateEffectIcons();
return true;
}
public boolean checkIfPvP(L2Character target)
{
if (target == null)
{
return false; // Target is null
}
if (target == this)
{
return false; // Target is self
}
if (!target.isPlayable())
{
return false; // Target is not a L2Playable
}
final L2PcInstance player = getActingPlayer();
if (player == null)
{
return false; // Active player is null
}
if (player.getKarma() != 0)
{
return false; // Active player has karma
}
final L2PcInstance targetPlayer = target.getActingPlayer();
if (targetPlayer == null)
{
return false; // Target player is null
}
if (targetPlayer == this)
{
return false; // Target player is self
}
if (targetPlayer.getKarma() != 0)
{
return false; // Target player has karma
}
if (targetPlayer.getPvpFlag() == 0)
{
return false;
}
return true;
// Even at war, there should be PvP flag
// if(
// player.getClan() == null ||
// targetPlayer.getClan() == null ||
// (
// !targetPlayer.getClan().isAtWarWith(player.getClanId()) &&
// targetPlayer.getWantsPeace() == 0 &&
// player.getWantsPeace() == 0
// )
// )
// {
// return true;
// }
// return false;
}
/**
* Return True.
*/
@Override
public boolean canBeAttacked()
{
return true;
}
// Support for Noblesse Blessing skill, where buffs are retained after resurrect
public final boolean isNoblesseBlessedAffected()
{
return isAffected(EffectFlag.NOBLESS_BLESSING);
}
/**
* @return {@code true} if char can resurrect by himself, {@code false} otherwise
*/
public final boolean isResurrectSpecialAffected()
{
return isAffected(EffectFlag.RESURRECTION_SPECIAL);
}
/**
* @return {@code true} if the Silent Moving mode is active, {@code false} otherwise
*/
public boolean isSilentMovingAffected()
{
return isAffected(EffectFlag.SILENT_MOVE);
}
/**
* For Newbie Protection Blessing skill, keeps you safe from an attack by a chaotic character >= 10 levels apart from you.
* @return
*/
public final boolean isProtectionBlessingAffected()
{
return isAffected(EffectFlag.PROTECTION_BLESSING);
}
@Override
public void updateEffectIcons(boolean partyOnly)
{
getEffectList().updateEffectIcons(partyOnly);
}
public boolean isLockedTarget()
{
return _lockedTarget != null;
}
public L2Character getLockedTarget()
{
return _lockedTarget;
}
public void setLockedTarget(L2Character cha)
{
_lockedTarget = cha;
}
public void setTransferDamageTo(L2PcInstance val)
{
transferDmgTo = val;
}
public L2PcInstance getTransferingDamageTo()
{
return transferDmgTo;
}
public abstract void doPickupItem(L2Object object);
public abstract int getKarma();
public abstract byte getPvpFlag();
public abstract boolean useMagic(Skill skill, boolean forceUse, boolean dontMove);
public abstract void storeMe();
public abstract void storeEffect(boolean storeEffects);
public abstract void restoreEffects();
@Override
public boolean isPlayable()
{
return true;
}
}