package Hero import OnCast public module Hero abstract static function onCast(int abilId, thistype caster, int lvl) abstract static function onPointCast(int abildId, thistype caster, int lvl, vec2 tpos) abstract static function onUnitCast(int abildId, thistype caster, int lvl, unit target) abstract static function onEndCast(int abilId, thistype caster, int lvl ) static function evalCast() returns boolean let u = GetTriggerUnit() let id = GetSpellAbilityId() let tx = GetSpellTargetX() let ty = GetSpellTargetY() let tu = GetSpellTargetUnit() if tx == 0 and tu == null onCast(id, u.getUserData() castTo thistype, GetUnitAbilityLevel(u, id) ) else if tu == null onPointCast(id, u.getUserData() castTo thistype, GetUnitAbilityLevel(u, id), vec2(tx,ty)) else onUnitCast(id, u.getUserData() castTo thistype, GetUnitAbilityLevel(u, id), tu) return false static function evalPointCast() returns boolean let u = GetTriggerUnit() let id = GetSpellAbilityId() onCast(id, u.getUserData() castTo thistype, GetUnitAbilityLevel(u, id) ) return false static function evalEndcast() returns boolean let u = GetTriggerUnit() let id = GetSpellAbilityId() onEndCast(id, u.getUserData() castTo thistype, GetUnitAbilityLevel(u, id) ) return false static function registerEvents(unit u) var t = CreateTrigger() t.registerUnitEvent(u, EVENT_UNIT_SPELL_EFFECT) t.addCondition(Condition(function Hero.evalCast) ) t = CreateTrigger() t.registerUnitEvent(u, EVENT_UNIT_SPELL_ENDCAST) t.addCondition(Condition(function Hero.evalEndcast) ) endpackage package HeroNAdept import Hero import Entity import initlater SpellEnergyBarrier // Angelica public class HeroNAdept extends UnitEntity use Hero construct(vec3 pos, player owner) super(pos, 64., CreateUnit(owner, '0000', pos.x, pos.y, 0.)) registerEvents(actor) override static function onCast(int abilId, thistype caster, int lvl) BarrierBuff.onCast(caster, lvl) override static function onPointCast(int abildId, thistype caster, int lvl, vec2 tpos) override static function onUnitCast(int abildId, thistype caster, int lvl, unit target) override static function onEndCast(int abilId, thistype caster, int lvl ) endpackage package SpellEnergyBarrier import Entity import HeroNAdept import TimedLoop import Texttag ChannelData cdata class ChannelData use TimedLoop texttag tt real currentAmount = 0. real incAmount = 0. UnitEntity caster construct(real inc, UnitEntity caster) incAmount = inc this.caster = caster tt = createTTEx(caster.getPos(), vec2(0,0), "0", 12, 10, colorA(90,200,80,200)) startTimedLoop() override function onTimedLoop() currentAmount += incAmount tt.setText(currentAmount.toString(), 15 * 0.0023) public class BarrierBuff UnitEntity victim construct(UnitEntity victim, real dur, real amount) skip function defenseModifier() static function onCast(UnitEntity caster, int lvl) cdata = new ChannelData(lvl*1.5, caster) static function onEndCast(int abilId, UnitEntity caster, int lvl ) cdata.stopTimedLoop() new BarrierBuff(cdata.caster, 20., cdata.currentAmount) endpackage package Entity import LinkedListModule import Terrain import Fx import Angle import public LinkedList /** Base Entity Class */ public abstract class Entity use LinkedListModule /** 3d vector position */ protected vec3 pos /** 3d vector velocity */ protected vec3 vel /** radius */ real radius = 0. /** speed factor (multiplies to added velocity) */ real speedFactor = 1. /** owning player */ player owner /** flag for being static */ boolean isStatic = false /** sleeping or active? */ boolean active = true /** for removing */ boolean done = false /** even if the Entites pos.z might be > 0, it still can be below terrainZ */ boolean flying = false construct( vec3 pos, player owner ) this.pos = pos this.vel = vec3(0,0,0) this.owner = owner construct( vec3 pos, real radius, player owner ) this.pos = pos this.vel = vec3(0,0,0) this.owner = owner this.radius = radius construct( vec3 pos, vec3 vel, player owner ) this.pos = pos this.vel = vel this.owner = owner construct( vec3 pos, vec3 vel, real radius, player owner ) this.pos = pos this.vel = vel this.owner = owner this.radius = radius function getPos() returns vec3 return pos function setPos( vec3 pos ) this.pos = pos function addPos( vec3 pos ) this.pos += pos function getVel() returns vec3 return vel function setVel( vec3 vel ) this.vel = vel function addVel( vec3 vel ) this.vel += vel function setTarget( vec3 tpos, real speed ) var t = pos.distanceTo2d(tpos) / speed let tangle = pos.angleTo2d(tpos) let e = getTerrainZ(tpos.x,tpos.y) if t < 1. t = 1./speed let startZVelocity = ((-0.7 * t) / 2 - pos.z/t + e/t) this.setVel( vec3( Cos(tangle.radians()) * speed, Sin(tangle.radians()) * speed, startZVelocity) ) function terminate() done = true /** This function is called every ANIMATION_PERIOD tick if the Entity is active */ abstract function update() abstract public class UnitEntity extends Entity static trigger dmgTrig = CreateTrigger() protected unit actor construct( vec3 pos, unit actor ) super(pos, actor.getOwner()) this.actor = actor actor..setUserData(this castTo int)..addAbility(HEIGHT_ENABLER)..removeAbility(HEIGHT_ENABLER) dmgTrig.registerUnitEvent(actor, EVENT_UNIT_DAMAGED) construct( vec3 pos, real radius, unit actor ) super(pos, radius, actor.getOwner()) this.actor = actor actor..setUserData(this castTo int)..addAbility(HEIGHT_ENABLER)..removeAbility(HEIGHT_ENABLER) dmgTrig.registerUnitEvent(actor, EVENT_UNIT_DAMAGED) override function update() pos = vec3(actor.getX(), actor.getY(), 0.) function setNewActor(unit u) actor.remove() actor = u actor.setUserData(this castTo int) override function setPos(vec3 tpos) pos = tpos actor.setPos(tpos.x,tpos.y) actor.setFlyHeight(tpos.z - getTerrainZ(tpos.x, tpos.y), 0) function setXY(vec3 tpos) pos = tpos actor.setXY(tpos.toVec2()) static function onDamage() let victimData = GetTriggerUnit().getUserData() castTo UnitEntity let attackerData = GetAttacker().getUserData() castTo UnitEntity init UnitEntity.dmgTrig.addAction(function UnitEntity.onDamage) abstract public class FxEntity extends Entity protected Fx fx construct( vec3 pos, real radius, player owner, angle xyAngle, string sfxpath ) super(pos, radius, owner) fx = new Fx(pos, xyAngle, sfxpath) construct( vec3 pos, real radius, player owner, angle xyAngle ) super(pos, radius, owner) fx = new Fx(pos, xyAngle) construct( vec3 pos, player owner, angle xyAngle ) super(pos, 0., owner) fx = new Fx(pos, xyAngle) override function update() pos += (vel*speedFactor) fx.setXYZ(pos) function setFx(string sfxpath) fx.setFx(sfxpath) override function setPos(vec3 tpos) pos = tpos fx.setXY(tpos.toVec2()) endpackage package OnCast import public Vectors public module OnPointCast private static trigger t = null private static integer spellId abstract static function onPointCast(unit caster, int level, vec2 target ) private static function actions() returns boolean if GetSpellAbilityId() == spellId onPointCast(GetSpellAbilityUnit(), GetUnitAbilityLevel(GetSpellAbilityUnit(), spellId), vec2(GetSpellTargetX(), GetSpellTargetY())) return false static function registerSpellEvent(int p_spellId) spellId = p_spellId CreateTrigger() ..registerAnyUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT) ..addCondition(Condition(function actions)) public module OnCast private static trigger t = null private static integer spellId abstract static function onCast(unit caster, int level) private static function actions() returns boolean if GetSpellAbilityId() == spellId onCast(GetSpellAbilityUnit(), GetUnitAbilityLevel(GetSpellAbilityUnit(), spellId)) return false static function registerSpellEvent(int p_spellId) spellId = p_spellId CreateTrigger() ..registerAnyUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT) ..addCondition(Condition(function actions)) public module OnUnitTargetCast private static trigger t = null private static integer spellId abstract static function onUnitTargetCast(unit caster, int level, unit target) private static function actions() returns boolean if GetSpellAbilityId() == spellId onUnitTargetCast(GetSpellAbilityUnit(), GetUnitAbilityLevel(GetSpellAbilityUnit(), spellId), GetSpellTargetUnit()) return false static function registerSpellEvent(int p_spellId) spellId = p_spellId CreateTrigger() ..registerAnyUnitEvent(EVENT_PLAYER_UNIT_SPELL_EFFECT) ..addCondition(Condition(function actions)) endpackage package TimedLoop // TimedLoop // originally created by Vexorian // augmented by some ideas from "Constant Timer Loop 32" by Nestharus timer timedLoopTimer = CreateTimer() trigger timedLoopTrig = CreateTrigger() int conditionCount = 0 function evaluateTimedLoopTrig() TriggerEvaluate(timedLoopTrig) if conditionCount == 0 timedLoopTimer.pause() enum Mode RUNNING PAUSED STOPPED STOPPED_FOR_GOOD public module TimedLoop static private thistype array instances // The array static private integer instanceCount = 0 // The count static private triggercondition triggerCond = null // the triggerCondition for this static private conditionfunc cond = Condition(function onExpire) // TODO this should be private but does not work currently private Mode mode = Mode.PAUSED abstract function onTimedLoop() private static function onExpire() returns boolean int i = instanceCount - 1 while i >= 0 thistype t = instances[i] t.onTimedLoop() if t.mode != Mode.RUNNING instanceCount-- instances[i] = instances[instanceCount] if t.mode == Mode.STOPPED_FOR_GOOD t.mode = Mode.PAUSED destroy t else t.mode = Mode.PAUSED i-- if instanceCount == 0 TriggerRemoveCondition(timedLoopTrig, triggerCond) triggerCond = null conditionCount-- return false function stopTimedLoop() mode = Mode.STOPPED function stopTimedLoopAndDestroy() mode = Mode.STOPPED_FOR_GOOD function startTimedLoop() instances[instanceCount] = this instanceCount++ if instanceCount == 1 if triggerCond == null triggerCond = TriggerAddCondition(timedLoopTrig, cond) conditionCount++ if conditionCount == 1 timedLoopTimer.startPeriodic(ANIMATION_PERIOD, function evaluateTimedLoopTrig) mode = Mode.RUNNING ondestroy if mode != Mode.PAUSED stopTimedLoop() endpackage package Terrain import NoWurst import Item constant real MAX_RANGE = 10. constant integer DUMMY_ITEM_ID = 'wolg' location tempLoc = Location(0.,0.) item dItem = null rect find = null item array hid integer hidMax = 0 vec2 tempPos = vec2(0,0) init find = Rect(0., 0., 128., 128.) dItem = CreateItem(DUMMY_ITEM_ID, 0, 0) SetItemVisible(dItem, false) /** Returns the (not normalised) terrain-normal at the given point */ public function getTerrainNormal( real x, real y, real sampleRadius) returns vec3 MoveLocation(tempLoc, x-sampleRadius, y) var zx = GetLocationZ(tempLoc) MoveLocation(tempLoc, x+sampleRadius, y) zx -= GetLocationZ(tempLoc) MoveLocation(tempLoc, x, y-sampleRadius) var zy = GetLocationZ(tempLoc) MoveLocation(tempLoc, x, y+sampleRadius) zy -= GetLocationZ(tempLoc) let sampleRadius2 = 2*sampleRadius return vec3( zx*sampleRadius2, zy*sampleRadius2, sampleRadius2*sampleRadius2 ) public function getTerrainZ2(real x, real y) returns real MoveLocation( tempLoc, x, y ) return GetLocationZ( tempLoc ) public function getTerrainZ(vec2 v) returns real MoveLocation( tempLoc, v.x, v.y ) return GetLocationZ( tempLoc ) public function vec2.withTerrainZ() returns vec3 return vec3(this.x, this.y, getTerrainZ(this.x, this.y)) public function vec2.withTerrainZ(real zoffset) returns vec3 return vec3(this.x, this.y, getTerrainZ(this.x, this.y) + zoffset) public function vec3.withTerrainZ() returns vec3 return vec3(this.x, this.y, getTerrainZ(this.x, this.y)) public function vec3.withTerrainZ(real zoffset) returns vec3 return vec3(this.x, this.y, getTerrainZ(this.x, this.y) + zoffset) public function isTerrainDeepWater(real x, real y) returns boolean return not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY) public function isTerrainShallowWater(real x, real y) returns boolean return not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY) and IsTerrainPathable(x, y, PATHING_TYPE_BUILDABILITY) public function isTerrainLand(real x, real y) returns boolean return IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) public function isTerrainPlatform(real x, real y) returns boolean return not IsTerrainPathable(x, y, PATHING_TYPE_FLOATABILITY) and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY) and not IsTerrainPathable(x, y, PATHING_TYPE_BUILDABILITY) function hideItem() if IsItemVisible(GetEnumItem()) hid[hidMax] = GetEnumItem() SetItemVisible(hid[hidMax], false) hidMax++ public function isTerrainWalkable(real x, real y) returns boolean //Hide any items in the area to avoid conflicts with our item MoveRectTo(find, x, y) EnumItemsInRect(find ,null, function hideItem) //Try to move the test item and get its coords SetItemPosition(dItem, x, y) //Unhides the item tempPos = dItem.getPos() SetItemVisible(dItem, false)//Hide it again //Unhide any items hidden at the start while hidMax > 0 hidMax-- SetItemVisible(hid[hidMax], true) hid[hidMax] = null //Return walkability return (tempPos.x-x)*(tempPos.x-x)+(tempPos.y-y)*(tempPos.y-y) <= MAX_RANGE*MAX_RANGE and not IsTerrainPathable(x, y, PATHING_TYPE_WALKABILITY) endpackage