/*
* This file is part of aion-unique <aion-unique.com>.
*
* aion-unique 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-unique 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-unique. If not, see <http://www.gnu.org/licenses/>.
*/
package com.aionemu.gameserver.skillengine.model;
import java.util.List;
import java.util.concurrent.Future;
import com.aionemu.gameserver.controllers.attack.AttackStatus;
import com.aionemu.gameserver.controllers.movement.ActionObserver;
import com.aionemu.gameserver.controllers.movement.AttackCalcObserver;
import com.aionemu.gameserver.model.gameobjects.Creature;
import com.aionemu.gameserver.model.gameobjects.player.Player;
import com.aionemu.gameserver.model.templates.item.ItemTemplate;
import com.aionemu.gameserver.network.aion.serverpackets.SM_SKILL_ACTIVATION;
import com.aionemu.gameserver.skillengine.effect.EffectTemplate;
import com.aionemu.gameserver.skillengine.effect.Effects;
import com.aionemu.gameserver.utils.PacketSendUtility;
import com.aionemu.gameserver.utils.ThreadPoolManager;
/**
* @author ATracer
*
*/
public class Effect
{
private SkillTemplate skillTemplate;
private int skillLevel;
private int duration;
private int endTime;
private Creature effected;
private Creature effector;
private Future<?> checkTask = null;
private Future<?> task = null;
private Future<?>[] periodicTasks = null;
private Future<?> mpUseTask = null;
/**
* Used for damage/heal values
*/
private int reserved1;
/**
* Used for shield total hit damage;
*/
private int reserved2;
/**
* Used for shield hit damage
*/
private int reserved3;
/**
* Spell Status
*
* 1 : stumble
* 2 : knockback
* 4 : open aerial
* 8 : close aerial
* 16 : spin
* 32 : block
* 64 : parry
* 128 : dodge
* 256 : resist
*/
private SpellStatus spellStatus = SpellStatus.NONE;
private AttackStatus attackStatus = AttackStatus.NORMALHIT;
private int shieldDefense;
private boolean addedToController;
private int successEffect;
private AttackCalcObserver[] attackStatusObserver;
private AttackCalcObserver[] attackShieldObserver;
private boolean launchSubEffect = true;
private Effect subEffect = null;
private boolean isStopped;
private ItemTemplate itemTemplate;
/**
* Hate that will be placed on effected list
*/
private int tauntHate;
/**
* Total hate that will be broadcasted
*/
private int effectHate;
/**
* Action observer that should be removed after effect end
*/
private ActionObserver[] actionObserver;
public Effect(Creature effector, Creature effected, SkillTemplate skillTemplate, int skillLevel, int duration)
{
this.effector = effector;
this.effected = effected;
this.skillTemplate = skillTemplate;
this.skillLevel = skillLevel;
this.duration = duration;
}
public Effect(Creature effector, Creature effected, SkillTemplate skillTemplate, int skillLevel, int duration, ItemTemplate itemTemplate)
{
this(effector, effected, skillTemplate, skillLevel, duration);
this.itemTemplate = itemTemplate;
}
/**
* @return the effectorId
*/
public int getEffectorId()
{
return effector.getObjectId();
}
/**
* @return the skillId
*/
public int getSkillId()
{
return skillTemplate.getSkillId();
}
/**
* @return the stack
*/
public String getStack()
{
return skillTemplate.getStack();
}
/**
* @return the skillLevel
*/
public int getSkillLevel()
{
return skillLevel;
}
/**
* @return the skillStackLvl
*/
public int getSkillStackLvl()
{
return skillTemplate.getLvl();
}
/**
*
* @return
*/
public SkillType getSkillType()
{
return skillTemplate.getType();
}
/**
* @return the duration
*/
public int getDuration()
{
return duration;
}
/**
* @return the effected
*/
public Creature getEffected()
{
return effected;
}
/**
* @return the effector
*/
public Creature getEffector()
{
return effector;
}
/**
* @return the isPassive
*/
public boolean isPassive()
{
return skillTemplate.isPassive();
}
/**
* @param task the task to set
*/
public void setTask(Future<?> task)
{
this.task = task;
}
/**
* @return the periodicTask
*/
public Future<?> getPeriodicTask(int i)
{
return periodicTasks[i];
}
/**
* @param periodicTask the periodicTask to set
* @param i
*/
public void setPeriodicTask(Future<?> periodicTask, int i)
{
if(periodicTasks == null)
periodicTasks = new Future<?>[4];
this.periodicTasks[i] = periodicTask;
}
/**
* @return the mpUseTask
*/
public Future<?> getMpUseTask()
{
return mpUseTask;
}
/**
* @param mpUseTask the mpUseTask to set
*/
public void setMpUseTask(Future<?> mpUseTask)
{
this.mpUseTask = mpUseTask;
}
/**
* @return the reserved1
*/
public int getReserved1()
{
return reserved1;
}
/**
* @param reserved1 the reserved1 to set
*/
public void setReserved1(int reserved1)
{
this.reserved1 = reserved1;
}
/**
* @return the reserved2
*/
public int getReserved2()
{
return reserved2;
}
/**
* @param reserved2 the reserved2 to set
*/
public void setReserved2(int reserved2)
{
this.reserved2 = reserved2;
}
/**
* @return the reserved3
*/
public int getReserved3()
{
return reserved3;
}
/**
* @param reserved3 the reserved3 to set
*/
public void setReserved3(int reserved3)
{
this.reserved3 = reserved3;
}
/**
* @return the attackStatus
*/
public AttackStatus getAttackStatus()
{
return attackStatus;
}
/**
* @param attackStatus the attackStatus to set
*/
public void setAttackStatus(AttackStatus attackStatus)
{
this.attackStatus = attackStatus;
}
/**
* @return the successEffect
*/
public int getSuccessEffect()
{
return successEffect;
}
public void increaseSuccessEffect()
{
successEffect++;
}
public List<EffectTemplate> getEffectTemplates()
{
return skillTemplate.getEffects().getEffects();
}
public boolean isFood()
{
Effects effects = skillTemplate.getEffects();
return effects != null && effects.isFood();
}
public boolean isToggle()
{
return skillTemplate.getActivationAttribute() == ActivationAttribute.TOGGLE;
}
public int getTargetSlot()
{
return skillTemplate.getTargetSlot().ordinal();
}
/**
* @param i
* @return attackStatusObserver for this effect template
*/
public AttackCalcObserver getAttackStatusObserver(int i)
{
return attackStatusObserver[i];
}
/**
* @param attackStatusObserver the attackCalcObserver to set
*/
public void setAttackStatusObserver(AttackCalcObserver attackStatusObserver, int i)
{
if(this.attackStatusObserver == null)
this.attackStatusObserver = new AttackCalcObserver[4];
this.attackStatusObserver[i] = attackStatusObserver;
}
/**
* @param i
* @return attackShieldObserver for this effect template
*/
public AttackCalcObserver getAttackShieldObserver(int i)
{
return attackShieldObserver[i];
}
/**
* @param attackShieldObserver the attackShieldObserver to set
*/
public void setAttackShieldObserver(AttackCalcObserver attackShieldObserver, int i)
{
if(this.attackShieldObserver == null)
this.attackShieldObserver = new AttackCalcObserver[4];
this.attackShieldObserver[i] = attackShieldObserver;
}
/**
* @return the launchSubEffect
*/
public boolean isLaunchSubEffect()
{
return launchSubEffect;
}
/**
* @param launchSubEffect the launchSubEffect to set
*/
public void setLaunchSubEffect(boolean launchSubEffect)
{
this.launchSubEffect = launchSubEffect;
}
/**
* @return the shieldDefense
*/
public int getShieldDefense()
{
return shieldDefense;
}
/**
* @param shieldDefense the shieldDefense to set
*/
public void setShieldDefense(int shieldDefense)
{
this.shieldDefense = shieldDefense;
}
/**
* @return the spellStatus
*/
public SpellStatus getSpellStatus()
{
return spellStatus;
}
/**
* @param spellStatus the spellStatus to set
*/
public void setSpellStatus(SpellStatus spellStatus)
{
this.spellStatus = spellStatus;
}
/**
* @return the subEffect
*/
public Effect getSubEffect()
{
return subEffect;
}
/**
* @param subEffect the subEffect to set
*/
public void setSubEffect(Effect subEffect)
{
this.subEffect = subEffect;
}
/**
*
* @param effectId
* @return true or false
*/
public boolean containsEffectId(int effectId)
{
for(EffectTemplate template : getEffectTemplates())
{
if(template.getEffectid() == effectId)
return true;
}
return false;
}
/**
* Correct lifecycle of Effect
* - INITIALIZE
* - APPLY
* - START
* - END
*/
/**
* Do initialization with proper calculations
*/
public void initialize()
{
if(skillTemplate.getEffects() == null)
return;
int effectCounter = 0;
for(EffectTemplate template : getEffectTemplates())
{
if(effectCounter != successEffect)
break;
template.calculate(this);
template.calculateSubEffect(this);
template.calculateHate(this);
effectCounter++;
}
}
/**
* Apply all effect templates
*/
public void applyEffect()
{
if(skillTemplate.getEffects() == null)
return;
int effectCounter = 0;
for(EffectTemplate template : getEffectTemplates())
{
if(effectCounter == successEffect)
break;
template.applyEffect(this);
template.startSubEffect(this);
effectCounter++;
}
/**
* broadcast final hate to all visible objects
*/
if(effectHate != 0)
effector.getController().broadcastHate(effectHate);
}
/**
* Start effect which includes:
* - start effect defined in template
* - start subeffect if possible
* - activate toogle skill if needed
* - schedule end of effect
*/
public void startEffect()
{
for(EffectTemplate template : getEffectTemplates())
{
template.startEffect(this);
}
if(isToggle() && effector instanceof Player)
{
activateToggleSkill();
}
if(duration == 0)
return;
endTime = (int) System.currentTimeMillis() + duration;
task = ThreadPoolManager.getInstance().scheduleEffect((new Runnable()
{
@Override
public void run()
{
endEffect();
}
}), duration);
}
/**
* Will activate toggle skill and start checking task
*/
private void activateToggleSkill()
{
PacketSendUtility.sendPacket((Player) effector, new SM_SKILL_ACTIVATION(getSkillId(), true));
}
/**
* Will deactivate toggle skill and stop checking task
*/
private void deactivateToggleSkill()
{
PacketSendUtility.sendPacket((Player) effector, new SM_SKILL_ACTIVATION(getSkillId(), false));
}
/**
* End effect and all effect actions
* This method is synchronized and prevented to be called several times
* which could cause unexpected behavior
*/
public synchronized void endEffect()
{
if(isStopped)
return;
for(EffectTemplate template : getEffectTemplates())
{
template.endEffect(this);
}
if(isToggle() && effector instanceof Player)
{
deactivateToggleSkill();
}
stopTasks();
effected.getEffectController().clearEffect(this);
this.isStopped = true;
}
/**
* Stop all scheduled tasks
*/
public void stopTasks()
{
if(task != null)
{
task.cancel(true);
task = null;
}
if(checkTask != null)
{
checkTask.cancel(true);
checkTask = null;
}
if(periodicTasks != null)
{
for(Future<?> periodicTask : this.periodicTasks)
{
if(periodicTask != null)
{
periodicTask.cancel(true);
periodicTask = null;
}
}
}
if(mpUseTask != null)
{
mpUseTask.cancel(true);
mpUseTask = null;
}
}
public int getElapsedTime()
{
int elapsedTime = endTime - (int)System.currentTimeMillis();
return elapsedTime > 0 ? elapsedTime : 0;
}
/**
* PVP damage ration
*
* @return
*/
public int getPvpDamage()
{
return skillTemplate.getPvpDamage();
}
public ItemTemplate getItemTemplate()
{
return itemTemplate;
}
/**
* Try to add this effect to effected controller
*/
public void addToEffectedController()
{
if(!addedToController)
{
effected.getEffectController().addEffect(this);
addedToController = true;
}
}
/**
* @return the effectHate
*/
public int getEffectHate()
{
return effectHate;
}
/**
* @param effectHate the effectHate to set
*/
public void setEffectHate(int effectHate)
{
this.effectHate = effectHate;
}
/**
* @return the tauntHate
*/
public int getTauntHate()
{
return tauntHate;
}
/**
* @param tauntHate the tauntHate to set
*/
public void setTauntHate(int tauntHate)
{
this.tauntHate = tauntHate;
}
/**
* @param i
* @return actionObserver for this effect template
*/
public ActionObserver getActionObserver(int i)
{
return actionObserver[i];
}
/**
* @param observer the observer to set
*/
public void setActionObserver(ActionObserver observer, int i)
{
if(actionObserver == null)
actionObserver = new ActionObserver[4];
actionObserver[i] = observer;
}
}