forked from MagicBane/Server
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
663 lines
20 KiB
663 lines
20 KiB
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . |
|
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· |
|
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ |
|
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ |
|
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ |
|
// Magicbane Emulator Project © 2013 - 2022 |
|
// www.magicbane.com |
|
|
|
|
|
package engine.objects; |
|
|
|
import engine.Enum.DamageType; |
|
import engine.Enum.EffectSourceType; |
|
import engine.gameManager.PowersManager; |
|
import engine.job.AbstractJob; |
|
import engine.job.AbstractScheduleJob; |
|
import engine.job.JobContainer; |
|
import engine.jobs.AbstractEffectJob; |
|
import engine.jobs.DamageOverTimeJob; |
|
import engine.jobs.NoTimeJob; |
|
import engine.jobs.PersistentAoeJob; |
|
import engine.net.ByteBufferWriter; |
|
import engine.net.client.ClientConnection; |
|
import engine.powers.ActionsBase; |
|
import engine.powers.EffectsBase; |
|
import engine.powers.PowersBase; |
|
import engine.powers.effectmodifiers.AbstractEffectModifier; |
|
|
|
import java.util.HashSet; |
|
import java.util.concurrent.atomic.AtomicBoolean; |
|
|
|
|
|
public class Effect { |
|
|
|
private JobContainer jc; |
|
|
|
//Fail Conditions |
|
private boolean cancelOnAttack; |
|
private boolean cancelOnAttackSwing; |
|
private boolean cancelOnCast; |
|
private boolean cancelOnCastSpell; |
|
private boolean cancelOnEquipChange; |
|
private boolean cancelOnLogout; |
|
private boolean cancelOnMove; |
|
private boolean cancelOnNewCharm; |
|
private boolean cancelOnSit; |
|
private boolean cancelOnTakeDamage; |
|
private boolean cancelOnTerritoryClaim; |
|
private boolean cancelOnUnEquip; |
|
private boolean cancelOnStun; |
|
private boolean bakedInStat = false; |
|
private boolean isStatic = false; |
|
private int effectSourceType = 0; |
|
private int effectSourceID = 0; |
|
|
|
|
|
private EffectsBase eb; |
|
private int trains; |
|
private float damageAmount = 0f; |
|
|
|
private AtomicBoolean cancel = new AtomicBoolean(false); |
|
|
|
//private AbstractWorldObject owner; |
|
|
|
/** |
|
* Generic Constructor |
|
*/ |
|
public Effect(JobContainer jc, EffectsBase eb, int trains) { |
|
this.jc = jc; |
|
this.cancelOnAttack = false; |
|
this.cancelOnAttackSwing = false; |
|
this.cancelOnCast = false; |
|
this.cancelOnCastSpell = false; |
|
this.cancelOnEquipChange = false; |
|
this.cancelOnLogout = false; |
|
this.cancelOnMove = false; |
|
this.cancelOnNewCharm = false; |
|
this.cancelOnSit = false; |
|
this.cancelOnTakeDamage = false; |
|
this.cancelOnTerritoryClaim = false; |
|
this.cancelOnUnEquip = false; |
|
this.cancelOnStun = false; |
|
this.eb = eb; |
|
this.trains = trains; |
|
} |
|
|
|
public Effect(JobContainer jc, EffectsBase eb, int trains, boolean isStatic) { |
|
this.jc = jc; |
|
this.cancelOnAttack = false; |
|
this.cancelOnAttackSwing = false; |
|
this.cancelOnCast = false; |
|
this.cancelOnCastSpell = false; |
|
this.cancelOnEquipChange = false; |
|
this.cancelOnLogout = false; |
|
this.cancelOnMove = false; |
|
this.cancelOnNewCharm = false; |
|
this.cancelOnSit = false; |
|
this.cancelOnTakeDamage = false; |
|
this.cancelOnTerritoryClaim = false; |
|
this.cancelOnUnEquip = false; |
|
this.cancelOnStun = false; |
|
this.eb = eb; |
|
this.trains = trains; |
|
this.isStatic = isStatic; |
|
} |
|
|
|
private static void blankFill(ByteBufferWriter writer) { |
|
writer.putInt(0); |
|
writer.putInt(0); |
|
writer.putInt(0); |
|
writer.put((byte) 0); |
|
writer.putInt(0); |
|
writer.putInt(0); |
|
writer.putInt(0); |
|
} |
|
|
|
//called when effect ends. Send message to client to remove effect |
|
public void endEffect() { |
|
if (this.jc != null) { |
|
AbstractJob aj = jc.getJob(); |
|
if (aj == null) |
|
return; |
|
if (aj instanceof AbstractEffectJob) { |
|
((AbstractEffectJob) aj).setSkipCancelEffect(false); |
|
((AbstractEffectJob) aj).endEffect(); |
|
} |
|
} |
|
} |
|
|
|
public void endEffectNoPower() { |
|
if (this.jc != null) { |
|
AbstractJob aj = jc.getJob(); |
|
if (aj == null) |
|
return; |
|
if (aj instanceof AbstractEffectJob) { |
|
((AbstractEffectJob) aj).setSkipCancelEffect(false); |
|
((AbstractEffectJob) aj).endEffectNoPower(); |
|
} |
|
} |
|
} |
|
|
|
//Called when effect ends before timer done |
|
public void cancelJob() { |
|
if (this.jc != null) { |
|
AbstractJob aj = jc.getJob(); |
|
if (aj == null) |
|
return; |
|
if (aj instanceof AbstractEffectJob) |
|
((AbstractEffectJob) aj).setSkipCancelEffect(false); |
|
if (aj instanceof AbstractScheduleJob) { |
|
((AbstractScheduleJob) aj).cancelJob(); |
|
} |
|
} |
|
} |
|
|
|
public void cancelJob(boolean skipEffect) { |
|
if (this.jc != null) { |
|
AbstractJob aj = jc.getJob(); |
|
if (aj == null) |
|
return; |
|
if (skipEffect && aj instanceof AbstractEffectJob) { |
|
((AbstractEffectJob) aj).setSkipCancelEffect(skipEffect); |
|
} |
|
if (aj instanceof AbstractScheduleJob) { |
|
((AbstractScheduleJob) aj).cancelJob(); |
|
} |
|
} |
|
} |
|
|
|
public boolean applyBonus(Item item) { |
|
if (this.jc == null) |
|
return false; |
|
AbstractJob aj = jc.getJob(); |
|
if (aj == null) |
|
return false; |
|
if (aj instanceof AbstractEffectJob) { |
|
AbstractEffectJob aej = (AbstractEffectJob) aj; |
|
EffectsBase eb = aej.getEffect(); |
|
if (eb == null) |
|
return false; |
|
HashSet<AbstractEffectModifier> aems = eb.getModifiers(); |
|
for (AbstractEffectModifier aem : aems) |
|
aem.applyBonus(item, aej.getTrains()); |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
public boolean applyBonus(Building building) { |
|
if (this.jc == null) |
|
return false; |
|
AbstractJob aj = jc.getJob(); |
|
if (aj == null) |
|
return false; |
|
if (aj instanceof AbstractEffectJob) { |
|
AbstractEffectJob aej = (AbstractEffectJob) aj; |
|
EffectsBase eb = aej.getEffect(); |
|
if (eb == null) |
|
return false; |
|
HashSet<AbstractEffectModifier> aems = eb.getModifiers(); |
|
for (AbstractEffectModifier aem : aems) |
|
aem.applyBonus(building, aej.getTrains()); |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
public boolean applyBonus(AbstractCharacter ac) { |
|
if (this.jc == null) |
|
return false; |
|
AbstractJob aj = jc.getJob(); |
|
if (aj == null) |
|
return false; |
|
if (aj instanceof AbstractEffectJob) { |
|
AbstractEffectJob aej = (AbstractEffectJob) aj; |
|
EffectsBase eb = aej.getEffect(); |
|
if (eb == null) |
|
return false; |
|
HashSet<AbstractEffectModifier> aems = eb.getModifiers(); |
|
for (AbstractEffectModifier aem : aems) |
|
aem.applyBonus(ac, aej.getTrains()); |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
public boolean applyBonus(Item item, AbstractCharacter ac) { |
|
if (this.jc == null) |
|
return false; |
|
AbstractJob aj = jc.getJob(); |
|
if (aj == null) |
|
return false; |
|
if (aj instanceof AbstractEffectJob) { |
|
AbstractEffectJob aej = (AbstractEffectJob) aj; |
|
EffectsBase eb = aej.getEffect(); |
|
if (eb == null) |
|
return false; |
|
HashSet<AbstractEffectModifier> aems = eb.getModifiers(); |
|
for (AbstractEffectModifier aem : aems) { |
|
aem.applyBonus(item, aej.getTrains()); |
|
aem.applyBonus(ac, aej.getTrains()); |
|
} |
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
public HashSet<AbstractEffectModifier> getEffectModifiers() { |
|
if (this.jc == null) |
|
return null; |
|
AbstractJob aj = jc.getJob(); |
|
if (aj == null) |
|
return null; |
|
if (aj instanceof AbstractEffectJob) { |
|
AbstractEffectJob aej = (AbstractEffectJob) aj; |
|
EffectsBase eb = aej.getEffect(); |
|
if (eb == null) |
|
return null; |
|
return eb.getModifiers(); |
|
} |
|
return null; |
|
} |
|
|
|
//Send this effect to a client when loading a player |
|
public void sendEffect(ClientConnection cc) { |
|
if (this.jc == null || this.eb == null || cc == null) |
|
return; |
|
AbstractJob aj = this.jc.getJob(); |
|
if (aj == null || (!(aj instanceof AbstractEffectJob))) |
|
return; |
|
this.eb.sendEffect((AbstractEffectJob) aj, (this.jc.timeToExecutionLeft() / 1000), cc); |
|
} |
|
|
|
public void sendEffectNoPower(ClientConnection cc) { |
|
if (this.jc == null || this.eb == null || cc == null) |
|
return; |
|
AbstractJob aj = this.jc.getJob(); |
|
if (aj == null || (!(aj instanceof AbstractEffectJob))) |
|
return; |
|
this.eb.sendEffectNoPower((AbstractEffectJob) aj, (this.jc.timeToExecutionLeft() / 1000), cc); |
|
} |
|
|
|
public void sendSpireEffect(ClientConnection cc, boolean onEnter) { |
|
if (this.jc == null || this.eb == null || cc == null) |
|
return; |
|
AbstractJob aj = this.jc.getJob(); |
|
if (aj == null || (!(aj instanceof AbstractEffectJob))) |
|
return; |
|
int duration = 45; |
|
if (onEnter) |
|
duration = -1; |
|
this.eb.sendEffectNoPower((AbstractEffectJob) aj, duration, cc); |
|
} |
|
|
|
public void serializeForItem(ByteBufferWriter writer, Item item) { |
|
if (this.jc == null) { |
|
blankFill(writer); |
|
return; |
|
} |
|
AbstractJob aj = this.jc.getJob(); |
|
if (aj == null || (!(aj instanceof AbstractEffectJob))) { |
|
blankFill(writer); |
|
return; |
|
} |
|
AbstractEffectJob aej = (AbstractEffectJob) aj; |
|
PowersBase pb = aej.getPower(); |
|
ActionsBase ab = aej.getAction(); |
|
if (this.eb == null) { |
|
blankFill(writer); |
|
return; |
|
} else if (pb == null && !(this.jc.noTimer())) { |
|
blankFill(writer); |
|
return; |
|
} |
|
if (this.jc.noTimer()) { |
|
if (pb == null) |
|
writer.putInt(this.eb.getToken()); |
|
else |
|
writer.putInt(pb.getToken()); |
|
writer.putInt(aej.getTrains()); |
|
writer.putInt(1); |
|
writer.put((byte) 1); |
|
writer.putInt(item.getObjectType().ordinal()); |
|
writer.putInt(item.getObjectUUID()); |
|
|
|
writer.putString(item.getName()); |
|
writer.putFloat(-1000f); |
|
} else { |
|
float duration = this.jc.timeToExecutionLeft() / 1000; |
|
writer.putInt(this.eb.getToken()); |
|
writer.putInt(aej.getTrains()); |
|
writer.putInt(0); |
|
writer.put((byte) 0); |
|
writer.putInt(pb.getToken()); |
|
writer.putString(pb.getName()); |
|
writer.putFloat(duration); |
|
} |
|
} |
|
|
|
public void serializeForClientMsg(ByteBufferWriter writer) { |
|
AbstractJob aj = this.jc.getJob(); |
|
if (aj == null || (!(aj instanceof AbstractEffectJob))) { |
|
//TODO put error message here |
|
blankFill(writer); |
|
return; |
|
} |
|
AbstractEffectJob aej = (AbstractEffectJob) aj; |
|
PowersBase pb = aej.getPower(); |
|
ActionsBase ab = aej.getAction(); |
|
if (ab == null || pb == null || this.eb == null) { |
|
//TODO put error message here |
|
blankFill(writer); |
|
return; |
|
} |
|
|
|
if (aej instanceof PersistentAoeJob) { |
|
blankFill(writer); |
|
return; |
|
} |
|
|
|
float duration = this.jc.timeToExecutionLeft() / 1000; |
|
if (aej instanceof DamageOverTimeJob) |
|
duration = ab.getDurationInSeconds(aej.getTrains()) - (((DamageOverTimeJob) aej).getIteration() * 5); |
|
|
|
|
|
writer.putInt(pb.getToken()); |
|
writer.putInt(aej.getTrains()); |
|
writer.putInt(0); |
|
writer.put((byte) 0); |
|
writer.putInt(this.eb.getToken()); |
|
writer.putString(pb.getName()); |
|
writer.putFloat(duration); |
|
} |
|
|
|
public boolean serializeForLoad(ByteBufferWriter writer) { |
|
AbstractJob aj = this.jc.getJob(); |
|
if (aj == null || (!(aj instanceof AbstractEffectJob))) { |
|
return false; |
|
} |
|
|
|
|
|
AbstractEffectJob aej = (AbstractEffectJob) aj; |
|
PowersBase pb = aej.getPower(); |
|
ActionsBase ab = aej.getAction(); |
|
if (this.eb == null) { |
|
return false; |
|
} |
|
if (aej instanceof PersistentAoeJob) { |
|
return false; |
|
} |
|
|
|
|
|
float duration = this.jc.timeToExecutionLeft() / 1000; |
|
if (aej instanceof DamageOverTimeJob) |
|
if (ab != null) |
|
duration = ab.getDurationInSeconds(aej.getTrains()) - (((DamageOverTimeJob) aej).getIteration() * 5); |
|
if (aej instanceof NoTimeJob) |
|
duration = -1; |
|
|
|
int sendToken = this.getEffectToken(); |
|
|
|
if (aej.getAction() != null) |
|
if (aej.getAction().getPowerAction() != null |
|
&& PowersManager.ActionTokenByIDString.containsKey(aej.getAction().getPowerAction().getIDString())) |
|
try { |
|
sendToken = PowersManager.ActionTokenByIDString.get(aej.getAction().getPowerAction().getIDString()); |
|
} catch (Exception e) { |
|
sendToken = this.getEffectToken(); |
|
} |
|
|
|
|
|
writer.putInt(sendToken); |
|
writer.putInt(this.trains); |
|
writer.putInt(0); //? |
|
if (aej.getEffectSourceID() != 0) { |
|
writer.put((byte) 1); |
|
writer.putInt(aej.getEffectSourceType()); |
|
writer.putInt(aej.getEffectSourceID()); |
|
} else { |
|
writer.put((byte) 0); |
|
writer.putInt(pb != null ? pb.getToken() : 0); |
|
} |
|
writer.putString(pb != null ? pb.getName() : eb.getName()); |
|
|
|
writer.putFloat(duration); |
|
return true; |
|
} |
|
|
|
public float getDuration() { |
|
float duration = 0f; |
|
if (this.jc != null) |
|
duration = this.jc.timeToExecutionLeft() / 1000; |
|
return duration; |
|
} |
|
|
|
public boolean containsSource(EffectSourceType source) { |
|
if (this.eb != null) |
|
return this.eb.containsSource(source); |
|
return false; |
|
} |
|
|
|
public JobContainer getJobContainer() { |
|
return this.jc; |
|
} |
|
|
|
public int getTrains() { |
|
return this.trains; |
|
} |
|
|
|
public void setTrains(int value) { |
|
this.trains = value; |
|
} |
|
|
|
public float getDamageAmount() { |
|
return this.damageAmount; |
|
} |
|
|
|
public AbstractJob getJob() { |
|
if (this.jc == null) |
|
return null; |
|
return jc.getJob(); |
|
} |
|
|
|
public boolean bakedInStat() { |
|
return this.bakedInStat; |
|
} |
|
|
|
public void setBakedInStat(boolean value) { |
|
this.bakedInStat = value; |
|
} |
|
|
|
public PowersBase getPower() { |
|
if (this.jc == null) |
|
return null; |
|
AbstractJob aj = jc.getJob(); |
|
if (aj == null || (!(aj instanceof AbstractEffectJob))) |
|
return null; |
|
return ((AbstractEffectJob) aj).getPower(); |
|
} |
|
|
|
public int getPowerToken() { |
|
if (this.jc == null) |
|
return 0; |
|
AbstractJob aj = jc.getJob(); |
|
if (aj == null || (!(aj instanceof AbstractEffectJob))) |
|
return 0; |
|
PowersBase pb = ((AbstractEffectJob) aj).getPower(); |
|
if (pb == null) |
|
return 0; |
|
return pb.getToken(); |
|
} |
|
|
|
public int getEffectToken() { |
|
if (this.eb != null) |
|
return this.eb.getToken(); |
|
return 0; |
|
} |
|
|
|
public EffectsBase getEffectsBase() { |
|
return this.eb; |
|
} |
|
|
|
public String getName() { |
|
if (this.jc == null) |
|
return ""; |
|
AbstractJob aj = this.jc.getJob(); |
|
if (aj == null || !(aj instanceof AbstractEffectJob)) |
|
return ""; |
|
AbstractEffectJob aej = (AbstractEffectJob) aj; |
|
PowersBase pb = aej.getPower(); |
|
if (pb == null) |
|
return ""; |
|
return pb.getName(); |
|
} |
|
|
|
public boolean cancel() { |
|
return this.cancel.compareAndSet(false, true); |
|
} |
|
|
|
public boolean canceled() { |
|
return this.cancel.get(); |
|
} |
|
|
|
public boolean cancelOnAttack() { |
|
if (this.eb == null) |
|
return true; |
|
return this.eb.cancelOnAttack(); |
|
} |
|
|
|
public boolean cancelOnAttackSwing() { |
|
if (this.eb == null) |
|
return true; |
|
return this.eb.cancelOnAttackSwing(); |
|
} |
|
|
|
public boolean cancelOnCast() { |
|
if (this.eb == null) |
|
return true; |
|
return this.eb.cancelOnCast(); |
|
} |
|
|
|
public boolean cancelOnCastSpell() { |
|
if (this.eb == null) |
|
return true; |
|
return this.eb.cancelOnCastSpell(); |
|
} |
|
|
|
public boolean cancelOnEquipChange() { |
|
if (this.eb == null) |
|
return true; |
|
return this.eb.cancelOnEquipChange(); |
|
} |
|
|
|
public boolean cancelOnLogout() { |
|
if (this.eb == null) |
|
return true; |
|
return this.eb.cancelOnLogout(); |
|
} |
|
|
|
public boolean cancelOnMove() { |
|
if (this.eb == null || this.cancelOnMove) |
|
return true; |
|
return this.eb.cancelOnMove(); |
|
} |
|
|
|
public boolean cancelOnNewCharm() { |
|
if (this.eb == null) |
|
return true; |
|
return this.eb.cancelOnNewCharm(); |
|
} |
|
|
|
public boolean cancelOnSit() { |
|
if (this.eb == null) |
|
return true; |
|
return this.eb.cancelOnSit(); |
|
} |
|
|
|
public boolean cancelOnStun() { |
|
if (this.eb == null) |
|
return true; |
|
return this.cancelOnStun; |
|
} |
|
|
|
public boolean cancelOnTakeDamage() { |
|
if (this.eb == null) |
|
return true; |
|
if (this.eb.damageTypeSpecific()) { |
|
return false; //handled in call from resists |
|
} else { |
|
return this.eb.cancelOnTakeDamage(); |
|
} |
|
} |
|
|
|
//Used for verifying when damage absorbers fails |
|
public boolean cancelOnTakeDamage(DamageType type, float amount) { |
|
if (!this.eb.cancelOnTakeDamage()) |
|
return false; |
|
if (this.eb == null || amount < 0f) |
|
return false; |
|
if (this.eb.damageTypeSpecific()) { |
|
if (type == null) |
|
return false; |
|
if (this.eb.containsDamageType(type)) { |
|
this.damageAmount += amount; |
|
return this.damageAmount > this.eb.getDamageAmount(this.trains); |
|
} else |
|
return false; |
|
} else |
|
return false; //handled by call from AbstractCharacter |
|
} |
|
|
|
public boolean isDamageAbsorber() { |
|
if (this.eb == null) |
|
return false; |
|
if (!this.eb.cancelOnTakeDamage()) |
|
return false; |
|
return this.eb.damageTypeSpecific(); |
|
} |
|
|
|
public boolean cancelOnTerritoryClaim() { |
|
if (this.eb == null) |
|
return true; |
|
return this.eb.cancelOnTerritoryClaim(); |
|
} |
|
|
|
public boolean cancelOnUnEquip() { |
|
if (this.eb == null) |
|
return true; |
|
return this.eb.cancelOnUnEquip(); |
|
} |
|
|
|
public void setPAOE() { |
|
this.cancelOnStun = true; |
|
this.cancelOnMove = true; |
|
} |
|
|
|
public boolean isStatic() { |
|
return isStatic; |
|
} |
|
|
|
public void setIsStatic(boolean isStatic) { |
|
this.isStatic = isStatic; |
|
|
|
} |
|
|
|
public int getEffectSourceID() { |
|
return effectSourceID; |
|
} |
|
|
|
public void setEffectSourceID(int effectSourceID) { |
|
this.effectSourceID = effectSourceID; |
|
} |
|
|
|
public int getEffectSourceType() { |
|
return effectSourceType; |
|
} |
|
|
|
public void setEffectSourceType(int effectSourceType) { |
|
this.effectSourceType = effectSourceType; |
|
} |
|
|
|
|
|
} |