Public Repository for the Magicbane Shadowbane Emulator
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

// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.objects;
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.mbEnums;
import engine.mbEnums.EffectSourceType;
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(mbEnums.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;
}
}