package HealbackTower import Assets import Tower import Projectile import TextTagEntity import Creep import ClosureForGroups import DamageEvent public constant HEALBACK_TOWER_ID = 'h02A' constant HEALBACK_MULTIPLIERS = [1.75, 1.5, 2.0, 1.95] constant HEALBACK_MISSILE_COUNTS = [1, 2, 2, 3] constant HEALBACK_RANGES = [865., 885., 915., 950.] tuple HealbackTarget(UnitEntity e, real distance) public class HealbackTower extends Tower var level = 1 construct(Tower t) super(t) static function getMultiplier(int level) returns real return HEALBACK_MULTIPLIERS[level - 1] static function getMissileCount(int level) returns int return HEALBACK_MISSILE_COUNTS[level - 1] static function getRange(int level) returns real return HEALBACK_RANGES[level - 1] static constant nearEntities = new LinkedList() static var statSource = ZERO2 static Comparator comparator = (e1, e2) -> e1.distSq - e2.distSq static function getNearestBuilding(vec2 source, int count, real range) returns LinkedList statSource = source forUnitsInRange(source, range) u -> var viable = true // filter structureds if not IsUnitType(u, UNIT_TYPE_STRUCTURE) or not u.isAlive() viable = false // filter player owner if viable and pDatas[u.getOwner().getId()] == null viable = false // filter if wall or tower building if viable let e = u.getEntity() if not (e instanceof Wall or e instanceof Tower) viable = false // filter out full hp if u.getHP() == u.getMaxHP() viable = false if viable nearEntities.add(new EntityWithDist(u.getEntity(), statSource.distanceToSq(u.getPos()))) nearEntities.sortWith(comparator) let targets = new LinkedList() nearEntities.forEach() e -> if targets.size() < count targets.add(e.ue) destroy e nearEntities.clear() return targets override function onUpgrade() level++ function launchHealback(UnitEntity attacked, real damage) let creepPos = attacked.actor.getPos3Real() let targets = HealbackTower.getNearestBuilding(creepPos.toVec2(), getMissileCount(level), getRange(level)) for target in targets new HealbackMissile(creepPos.add(0, 0, 48), owner, damage, target) destroy targets override function onAttack(UnitEntity target) if DamageEvent.getAmount() > 0 and target.owner == CREEP_OWNER launchHealback(target, DamageEvent.getAmount() * getMultiplier(level)) class EntityWithDist UnitEntity ue int distSq construct(UnitEntity ue, real dist) this.ue = ue this.distSq = dist.toInt() constant HEALBACK_RADIUS = 32. constant HEALBACK_EFFECT = Abilities.vampiricAuraTarget constant HEALBACK_MISSILE_EFFECT = Abilities.faerieDragonMissile public class HealbackMissile extends Projectile private real heal private UnitEntity targetEntity private vec3 startPos private real distanceToTravelSq construct(vec3 pos, player owner, real heal, UnitEntity target) super(pos, HEALBACK_RADIUS, owner, pos.angleTo2d(target.getPos()), HEALBACK_MISSILE_EFFECT) fx.setTint(colorA(0, 255, 0, 255)) this.heal = heal this.targetEntity = target startPos = pos this.distanceToTravelSq = (target.getPos()).distanceToSq(startPos) this.setTarget(target.actor.getPos3Real().add(0, 0, 32.), 19.25) fx.setTint(colorA(215, 255, 215, 168)) setRanged(2000.) override function update() super.update() if not pos.inBounds() terminate() if startPos.distanceToSq(pos) > distanceToTravelSq onReachTarget() terminate() function onReachTarget() if this.targetEntity != null and this.targetEntity.actor.isAlive() flashEffect(HEALBACK_EFFECT, targetEntity.pos.add(0, 0, 50)) this.targetEntity.actor.addHP(this.heal) new TextTagEntity(pos, vec3(GetRandomReal(-1, 1),0, GetRandomReal(7,9)), this.heal.toInt().toString(), 8, .75, colorA(223, 255, 52, 255))