/** * A package to apply status effects like stun and silence. * This package counts the amount of applied and removed status effects, * therefore you have to care yourself about how many times you add or * remove a status effect from a unit. To use this, you will need a * Unit Indexer and have to implement the function in the config file. */ package StatusHandler import StatusHandlerConfig import DummyCaster constant DummyCaster STUN_DUMMY_CASTER = new DummyCaster(STUN_ABILITY_ID, "firebolt", DUMMY_PLAYER, false) constant DummyCaster SILENCE_DUMMY_CASTER = new DummyCaster(SILENCE_ABILITY_ID, "soulburn", DUMMY_PLAYER, false) constant DummyCaster DISARM_BOTH_DUMMY_CASTER = new DummyCaster(DISARM_BOTH_ABILITY_ID, "drunkenhaze", DUMMY_PLAYER, false) constant DummyCaster DISARM_MELEE_DUMMY_CASTER = new DummyCaster(DISARM_MELEE_ABILITY_ID, "drunkenhaze", DUMMY_PLAYER, false) constant DummyCaster DISARM_RANGED_DUMMY_CASTER = new DummyCaster(DISARM_RANGED_ABILITY_ID, "drunkenhaze", DUMMY_PLAYER, false) constant DummyCaster ENSNARE_DUMMY_CASTER = new DummyCaster(ENSNARE_ABILITY_ID, "ensnare", DUMMY_PLAYER, false) /** * A class which holds all informations about the status effect of the given unit. */ public class Status protected static Status array status protected timer stunTimer protected int stunCounter protected timer silenceTimer protected int silenceCounter protected timer ensnareTimer protected int ensnareCounter protected timer disarmBothTimer protected int disarmBothCounter protected timer disarmMeleeTimer protected int disarmMeleeCounter protected timer disarmRangedTimer protected int disarmRangedCounter /** * Constructs a Status object with the given unit. * * unit u - the unit whose Status object is being created */ construct(unit u) int i = u.getIndex() status[i] = this stunTimer = null stunCounter = 0 silenceTimer = null silenceCounter = 0 ensnareTimer = null ensnareCounter = 0 disarmBothTimer = null disarmBothCounter = 0 disarmMeleeTimer = null disarmMeleeCounter = 0 disarmRangedTimer = null disarmRangedCounter = 0 ondestroy if stunTimer != null stunTimer.release() if silenceTimer != null silenceTimer.release() if ensnareTimer != null ensnareTimer.release() if disarmBothTimer != null disarmBothTimer.release() if disarmMeleeTimer != null disarmMeleeTimer.release() if disarmRangedTimer != null disarmRangedTimer.release() /** * Returns a boolean indicating if the unit is stunned. * * returns true if the unit is stunned, false otherwise */ public function unit.isStunned() returns boolean return Status.status[this.getIndex()].stunCounter > 0 /** * Applys a stun to the given unit. The duration is infinite. Hence you have to * remove it yourself. The function will count the amount of calls and will therefore * last till you removed all stuns which have been applied before. */ public function unit.addStun() if not this.isStunned() STUN_DUMMY_CASTER.castOnTarget(this) Status.status[this.getIndex()].stunCounter++ /** * Applies a timed stun to the given unit. If there is already a timed stun on this unit, * the stun with the longer duration will be used. * * real timeout - the stun duration */ public function unit.addStunTimed(real timeout) int i = this.getIndex() if Status.status[i].stunTimer != null and Status.status[i].stunTimer.getRemaining() >= timeout return if Status.status[i].stunTimer == null Status.status[i].stunTimer = getTimer()..setData(i) this.addStun() Status.status[i].stunTimer.start(timeout, () -> begin int j = GetExpiredTimer().getData() j.getUnit().removeStun() Status.status[j].stunTimer.release() Status.status[j].stunTimer = null end) /** * Reduces the timed stun duration by the given amount. If the duration is smaller * then the given amount the timed stun is getting removed. * * real timeout - the amount the duration is getting reduced */ public function unit.reduceTimedStun(real timeout) int i = this.getIndex() if Status.status[i].stunTimer == null return if Status.status[i].stunTimer.getRemaining() - timeout > 0. Status.status[i].stunTimer.start(Status.status[i].stunTimer.getRemaining() - timeout, () -> begin int j = GetExpiredTimer().getData() j.getUnit().removeStun() Status.status[j].stunTimer.release() Status.status[j].stunTimer = null end) else this.removeStun() Status.status[i].stunTimer.release() Status.status[i].stunTimer = null /** * Removes one stun stack from the given unit. It is possible that the unit * is still stunned afterwards. Throws a warning if a non-existing stun is being * removed. */ public function unit.removeStun() Status.status[this.getIndex()].stunCounter-- if Status.status[this.getIndex()].stunCounter < 0 printWarning("StatusHandler: tried removing a non-existing stun.") Status.status[this.getIndex()].stunCounter = 0 if not this.isStunned() this.removeAbility(STUN_BUFF_ID) /** * Removes the current timed stun from the given unit. This only removes * the timed stun. Stuns applied with addStun() might still exist. Throws * a warning if there is no timed stun active. */ public function unit.removeTimedStun() int i = this.getIndex() if Status.status[i].stunTimer != null i.getUnit().removeStun() Status.status[i].stunTimer.release() Status.status[i].stunTimer = null else printWarning("StatusHandler: tried removing a non-existing timed stun.") /** * Removes all stun stacks and the timed stun from the given unit. Afterwards * the unit is not stunned anymore. */ public function unit.clearStun() int i = this.getIndex() if not this.isStunned() this.removeAbility(STUN_BUFF_ID) Status.status[i].stunCounter = 0 if Status.status[i].stunTimer != null i.getUnit().removeStun() Status.status[i].stunTimer.release() Status.status[i].stunTimer = null /** * Returns a boolean indicating if the unit is silenced. * * returns true if the unit is silenced, false otherwise */ public function unit.isSilenced() returns boolean return Status.status[this.getIndex()].silenceCounter > 0 /** * Applys a silence to the given unit. The duration is infinite. Hence you have to * remove it yourself. The function will count the amount of calls and will therefore * last till you removed all silences which have been applied before. */ public function unit.addSilence() if not this.isSilenced() SILENCE_DUMMY_CASTER.castOnTarget(this) Status.status[this.getIndex()].silenceCounter++ /** * Applies a timed silence to the given unit. If there is already a timed silence on this unit, * the silence with the longer duration will be used. * * real timeout - the silence duration */ public function unit.addSilenceTimed(real timeout) int i = this.getIndex() if Status.status[i].silenceTimer != null and Status.status[i].silenceTimer.getRemaining() >= timeout return if Status.status[i].silenceTimer == null Status.status[i].silenceTimer = getTimer()..setData(i) this.addSilence() Status.status[i].silenceTimer.start(timeout, () -> begin int j = GetExpiredTimer().getData() j.getUnit().removeSilence() Status.status[j].silenceTimer.release() Status.status[j].silenceTimer = null end) /** * Reduces the timed silence duration by the given amount. If the duration is smaller * then the given amount the timed silence is getting removed. * * real timeout - the amount the duration is getting reduced */ public function unit.reduceTimedSilence(real timeout) int i = this.getIndex() if Status.status[i].silenceTimer == null return if Status.status[i].silenceTimer.getRemaining() - timeout > 0. Status.status[i].silenceTimer.start(Status.status[i].silenceTimer.getRemaining() - timeout, () -> begin int j = GetExpiredTimer().getData() j.getUnit().removeSilence() Status.status[j].silenceTimer.release() Status.status[j].silenceTimer = null end) else this.removeSilence() Status.status[i].silenceTimer.release() Status.status[i].silenceTimer = null /** * Removes one silence stack from the given unit. It is possible that the unit * is still silenced afterwards. Throws a warning if a non-existing silence is being * removed. */ public function unit.removeSilence() Status.status[this.getIndex()].silenceCounter-- if Status.status[this.getIndex()].silenceCounter < 0 printWarning("StatusHandler: tried removing a non-existing silence.") Status.status[this.getIndex()].silenceCounter = 0 if not this.isSilenced() this.removeAbility(SILENCE_BUFF_ID) /** * Removes the current timed silence from the given unit. This only removes * the timed silence. Silences applied with addSilence() might still exist. Throws * a warning if there is no timed silence active. */ public function unit.removeTimedSilence() int i = this.getIndex() if Status.status[i].silenceTimer != null i.getUnit().removeSilence() Status.status[i].silenceTimer.release() Status.status[i].silenceTimer = null else printWarning("StatusHandler: tried removing a non-existing timed silence.") /** * Removes all silence stacks and the timed silence from the given unit. Afterwards * the unit is not silenced anymore. */ public function unit.clearSilence() int i = this.getIndex() if not this.isSilenced() this.removeAbility(SILENCE_BUFF_ID) Status.status[i].silenceCounter = 0 if Status.status[i].silenceTimer != null i.getUnit().removeSilence() Status.status[i].silenceTimer.release() Status.status[i].silenceTimer = null /** * Returns a boolean indicating if the unit is ensnared. * * returns true if the unit is ensnared, false otherwise */ public function unit.isEnsnared() returns boolean return Status.status[this.getIndex()].ensnareCounter > 0 /** * Ensnares the given unit. The duration is infinite. Hence you have to * remove it yourself. The function will count the amount of calls and will therefore * last till you removed all ensnares which have been applied before. */ public function unit.addEnsnare() if not this.isEnsnared() ENSNARE_DUMMY_CASTER.castOnTarget(this) Status.status[this.getIndex()].ensnareCounter++ /** * Applies a timed ensnare to the given unit. If there is already a timed ensnare on this unit, * the ensnare with the longer duration will be used. * * real timeout - the ensnare duration */ public function unit.addEnsnareTimed(real timeout) int i = this.getIndex() if Status.status[i].ensnareTimer != null and Status.status[i].ensnareTimer.getRemaining() >= timeout return if Status.status[i].ensnareTimer == null Status.status[i].ensnareTimer = getTimer()..setData(i) this.addEnsnare() Status.status[i].ensnareTimer.start(timeout, () -> begin int j = GetExpiredTimer().getData() j.getUnit().removeEnsnare() Status.status[j].ensnareTimer.release() Status.status[j].ensnareTimer = null end) /** * Reduces the timed ensnare duration by the given amount. If the duration is smaller * then the given amount the timed ensnare is getting removed. * * real timeout - the amount the duration is getting reduced */ public function unit.reduceTimedEnsnare(real timeout) int i = this.getIndex() if Status.status[i].ensnareTimer == null return if Status.status[i].ensnareTimer.getRemaining() - timeout > 0. Status.status[i].ensnareTimer.start(Status.status[i].ensnareTimer.getRemaining() - timeout, () -> begin int j = GetExpiredTimer().getData() j.getUnit().removeEnsnare() Status.status[j].ensnareTimer.release() Status.status[j].ensnareTimer = null end) else this.removeEnsnare() Status.status[i].ensnareTimer.release() Status.status[i].ensnareTimer = null /** * Removes the current timed ensnare from the given unit. This only removes * the timed ensnare. Ensnares applied with addEnsnare() might still exist. Throws * a warning if there is no timed ensnare active. */ public function unit.removeTimedEnsnare() int i = this.getIndex() if Status.status[i].ensnareTimer != null i.getUnit().removeEnsnare() Status.status[i].ensnareTimer.release() Status.status[i].ensnareTimer = null else printWarning("StatusHandler: tried removing a non-existing timed ensnare.") /** * Removes all ensnare stacks and the timed ensnare from the given unit. Afterwards * the unit is not ensnared anymore. */ public function unit.clearEnsnare() int i = this.getIndex() if not this.isEnsnared() this.removeAbility(ENSNARE1_BUFF_ID) this.removeAbility(ENSNARE2_BUFF_ID) Status.status[i].ensnareCounter = 0 if Status.status[i].ensnareTimer != null i.getUnit().removeEnsnare() Status.status[i].ensnareTimer.release() Status.status[i].ensnareTimer = null /** * Removes one ensnare stack from the given unit. It is possible that the unit * is still ensnared afterwards. Throws a warning if a non-existing ensnare is being * removed. */ public function unit.removeEnsnare() Status.status[this.getIndex()].ensnareCounter-- if Status.status[this.getIndex()].ensnareCounter < 0 printWarning("StatusHandler: tried removing a non-existing ensnare.") Status.status[this.getIndex()].ensnareCounter = 0 if not this.isEnsnared() this.removeAbility(ENSNARE1_BUFF_ID) this.removeAbility(ENSNARE2_BUFF_ID) /** * Returns a boolean indicating if the unit is disarmed. * * returns true if the unit is disarmed, false otherwise */ public function unit.isDisarmedBoth() returns boolean return Status.status[this.getIndex()].disarmBothCounter > 0 /** * Disarms the given unit. The duration is infinite. Hence you have to * remove it yourself. The function will count the amount of calls and will therefore * last till you removed all disarmbuffs which have been applied before. */ public function unit.addDisarmBoth() if not this.isDisarmedBoth() DISARM_BOTH_DUMMY_CASTER.castOnTarget(this) Status.status[this.getIndex()].disarmBothCounter++ /** * Applies a timed disarm to the given unit. If there is already a timed disarm on this unit, * the disarm with the longer duration will be used. * * real timeout - the disarm duration */ public function unit.addDisarmBothTimed(real timeout) int i = this.getIndex() if Status.status[i].disarmBothTimer != null and Status.status[i].disarmBothTimer.getRemaining() >= timeout return if Status.status[i].disarmBothTimer == null Status.status[i].disarmBothTimer = getTimer()..setData(i) this.addDisarmBoth() Status.status[i].disarmBothTimer.start(timeout, () -> begin int j = GetExpiredTimer().getData() j.getUnit().removeDisarmBoth() Status.status[j].disarmBothTimer.release() Status.status[j].disarmBothTimer = null end) /** * Reduces the timed disarm duration by the given amount. If the duration is smaller * then the given amount the timed disarm is getting removed. * * real timeout - the amount the duration is getting reduced */ public function unit.reduceTimedDisarmBoth(real timeout) int i = this.getIndex() if Status.status[i].disarmBothTimer == null return if Status.status[i].disarmBothTimer.getRemaining() - timeout > 0. Status.status[i].disarmBothTimer.start(Status.status[i].disarmBothTimer.getRemaining() - timeout, () -> begin int j = GetExpiredTimer().getData() j.getUnit().removeDisarmBoth() Status.status[j].disarmBothTimer.release() Status.status[j].disarmBothTimer = null end) else this.removeDisarmBoth() Status.status[i].disarmBothTimer.release() Status.status[i].disarmBothTimer = null /** * Removes one disarm stack from the given unit. It is possible that the unit * is still disarmed afterwards. Throws a warning if a non-existing disarmbuff is being * removed. */ public function unit.removeDisarmBoth() Status.status[this.getIndex()].disarmBothCounter-- if Status.status[this.getIndex()].disarmBothCounter < 0 printWarning("StatusHandler: tried removing a non-existing disarm both.") Status.status[this.getIndex()].disarmBothCounter = 0 if not this.isDisarmedBoth() this.removeAbility(DISARM_BOTH_BUFF_ID) /** * Removes the current timed disarm from the given unit. This only removes * the timed disarm. Disarms applied with addDisarmBoth() might still exist. Throws * a warning if there is no timed disarm active. */ public function unit.removeTimedDisarmBoth() int i = this.getIndex() if Status.status[i].disarmBothTimer != null i.getUnit().removeDisarmBoth() Status.status[i].disarmBothTimer.release() Status.status[i].disarmBothTimer = null else printWarning("StatusHandler: tried removing a non-existing timed disarm both.") /** * Removes all disarm stacks and the timed disarm from the given unit. Afterwards * the unit is not disarmed anymore. */ public function unit.clearDisarmBoth() int i = this.getIndex() if not this.isDisarmedBoth() this.removeAbility(DISARM_BOTH_BUFF_ID) Status.status[i].disarmBothCounter = 0 if Status.status[i].disarmBothTimer != null i.getUnit().removeDisarmBoth() Status.status[i].disarmBothTimer.release() Status.status[i].disarmBothTimer = null /** * Returns a boolean indicating if the unit is melee-disarmed. * * returns true if the unit is melee-disarmed, false otherwise */ public function unit.isDisarmedMelee() returns boolean return Status.status[this.getIndex()].disarmMeleeCounter > 0 /** * Disarms the given melee unit. The duration is infinite. Hence you have to * remove it yourself. The function will count the amount of calls and will therefore * last till you removed all melee-disarms which have been applied before. */ public function unit.addDisarmMelee() if not this.isDisarmedMelee() DISARM_MELEE_DUMMY_CASTER.castOnTarget(this) Status.status[this.getIndex()].disarmMeleeCounter++ /** * Applies a timed melee-disarm to the given unit. If there is already a timed melee-disarm on this unit, * the melee-disarm with the longer duration will be used. * * real timeout - the melee-disarm duration */ public function unit.addDisarmMeleeTimed(real timeout) int i = this.getIndex() if Status.status[i].disarmMeleeTimer != null and Status.status[i].disarmMeleeTimer.getRemaining() >= timeout return if Status.status[i].disarmMeleeTimer == null Status.status[i].disarmMeleeTimer = getTimer()..setData(i) this.addDisarmMelee() Status.status[i].disarmMeleeTimer.start(timeout, () -> begin int j = GetExpiredTimer().getData() j.getUnit().removeDisarmMelee() Status.status[j].disarmMeleeTimer.release() Status.status[j].disarmMeleeTimer = null end) /** * Reduces the timed melee-disarm duration by the given amount. If the duration is smaller * then the given amount the timed melee-disarm is getting removed. * * real timeout - the amount the duration is getting reduced */ public function unit.reduceTimedDisarmMelee(real timeout) int i = this.getIndex() if Status.status[i].disarmMeleeTimer == null return if Status.status[i].disarmMeleeTimer.getRemaining() - timeout > 0. Status.status[i].disarmMeleeTimer.start(Status.status[i].disarmMeleeTimer.getRemaining() - timeout, () -> begin int j = GetExpiredTimer().getData() j.getUnit().removeDisarmMelee() Status.status[j].disarmMeleeTimer.release() Status.status[j].disarmMeleeTimer = null end) else this.removeDisarmMelee() Status.status[i].disarmMeleeTimer.release() Status.status[i].disarmMeleeTimer = null /** * Removes one melee-disarm stack from the given unit. It is possible that the unit * is still melee-disarmed afterwards. Throws a warning if a non-existing melee-disarm is being * removed. */ public function unit.removeDisarmMelee() Status.status[this.getIndex()].disarmMeleeCounter-- if Status.status[this.getIndex()].disarmMeleeCounter < 0 printWarning("StatusHandler: tried removing a non-existing disarm melee.") Status.status[this.getIndex()].disarmMeleeCounter = 0 if not this.isDisarmedMelee() this.removeAbility(DISARM_MELEE_BUFF_ID) /** * Removes the current timed melee-disarm from the given unit. This only removes * the timed melee-disarm. Melee-disarms applied with addDisarmMelee() might still exist. Throws * a warning if there is no timed melee-disarm active. */ public function unit.removeTimedDisarmMelee() int i = this.getIndex() if Status.status[i].disarmMeleeTimer != null i.getUnit().removeDisarmMelee() Status.status[i].disarmMeleeTimer.release() Status.status[i].disarmMeleeTimer = null else printWarning("StatusHandler: tried removing a non-existing timed disarm melee.") /** * Removes all melee-disarm stacks and the timed melee-disarm from the given unit. Afterwards * the unit is not melee-disarmed anymore. */ public function unit.clearDisarmMelee() int i = this.getIndex() if not this.isDisarmedMelee() this.removeAbility(DISARM_MELEE_BUFF_ID) Status.status[i].disarmMeleeCounter = 0 if Status.status[i].disarmMeleeTimer != null i.getUnit().removeDisarmMelee() Status.status[i].disarmMeleeTimer.release() Status.status[i].disarmMeleeTimer = null /** * Returns a boolean indicating if the unit is range-disarmed. * * returns true if the unit is range-disarmed, false otherwise */ public function unit.isDisarmedRanged() returns boolean return Status.status[this.getIndex()].disarmRangedCounter > 0 /** * Disarms the given ranged unit. The duration is infinite. Hence you have to * remove it yourself. The function will count the amount of calls and will therefore * last till you removed all range-disarms which have been applied before. */ public function unit.addDisarmRanged() if not this.isDisarmedRanged() DISARM_RANGED_DUMMY_CASTER.castOnTarget(this) Status.status[this.getIndex()].disarmRangedCounter++ /** * Applies a timed range-disarm to the given unit. If there is already a timed range-disarm on this unit, * the range-disarm with the longer duration will be used. * * real timeout - the range-disarm duration */ public function unit.addDisarmRangedTimed(real timeout) int i = this.getIndex() if Status.status[i].disarmRangedTimer != null and Status.status[i].disarmRangedTimer.getRemaining() >= timeout return if Status.status[i].disarmRangedTimer == null Status.status[i].disarmRangedTimer = getTimer()..setData(i) this.addDisarmRanged() Status.status[i].disarmRangedTimer.start(timeout, () -> begin int j = GetExpiredTimer().getData() j.getUnit().removeDisarmRanged() Status.status[j].disarmRangedTimer.release() Status.status[j].disarmRangedTimer = null end) /** * Reduces the timed range-disarm duration by the given amount. If the duration is smaller * then the given amount the timed range-disarm is getting removed. * * real timeout - the amount the duration is getting reduced */ public function unit.reduceTimedDisarmRanged(real timeout) int i = this.getIndex() if Status.status[i].disarmRangedTimer == null return if Status.status[i].disarmRangedTimer.getRemaining() - timeout > 0. Status.status[i].disarmRangedTimer.start(Status.status[i].disarmRangedTimer.getRemaining() - timeout, () -> begin int j = GetExpiredTimer().getData() j.getUnit().removeDisarmRanged() Status.status[j].disarmRangedTimer.release() Status.status[j].disarmRangedTimer = null end) else this.removeDisarmRanged() Status.status[i].disarmRangedTimer.release() Status.status[i].disarmRangedTimer = null /** * Removes one range-disarm stack from the given unit. It is possible that the unit * is still range-disarmed afterwards. Throws a warning if a non-existing range-disarm is being * removed. */ public function unit.removeDisarmRanged() Status.status[this.getIndex()].disarmRangedCounter-- if Status.status[this.getIndex()].disarmRangedCounter < 0 printWarning("StatusHandler: tried removing a non-existing disarm ranged.") Status.status[this.getIndex()].disarmRangedCounter = 0 if not this.isDisarmedRanged() this.removeAbility(DISARM_RANGED_BUFF_ID) /** * Removes the current timed range-disarm from the given unit. This only removes * the timed range-disarm. Range-disarms applied with addDisarmRanged() might still exist. Throws * a warning if there is no timed range-disarm active. */ public function unit.removeTimedDisarmRanged() int i = this.getIndex() if Status.status[i].disarmRangedTimer != null i.getUnit().removeDisarmRanged() Status.status[i].disarmRangedTimer.release() Status.status[i].disarmRangedTimer = null else printWarning("StatusHandler: tried removing a non-existing timed disarm ranged.") /** * Removes all range-disarm stacks and the timed range-disarm from the given unit. Afterwards * the unit is not range-disarmed anymore. */ public function unit.clearDisarmRanged() int i = this.getIndex() if not this.isDisarmedRanged() this.removeAbility(DISARM_RANGED_BUFF_ID) Status.status[i].disarmRangedCounter = 0 if Status.status[i].disarmRangedTimer != null i.getUnit().removeDisarmRanged() Status.status[i].disarmRangedTimer.release() Status.status[i].disarmRangedTimer = null /** * Removes all status effects. This includes the stacks and the timed effects. Afterwards * the unit has no status effect applied anymore. */ public function unit.clearAll() this.clearStun() this.clearSilence() this.clearEnsnare() this.clearDisarmBoth() this.clearDisarmMelee() this.clearDisarmRanged()