package Collider import Fx import TimedLoop import LinkedList constant real DEFAULT_COLLISION_SIZE = 50.0 // These are defaults, on one hand you can change them constant real DEFAULT_MAX_SPEED = 1500.0 // on the other hand, if a spell relies on the defaults constant real DEFAULT_EXPIRATION_TIME = 5.0 // changing them would make the behavior vary... public enum Angle NO_MOVEMENT HOMING_UNIT HOMING_POINT ROTATING public abstract class Collider use TimedLoop Fx fx real expirationTime = DEFAULT_EXPIRATION_TIME real speed = 0.0 real acceleration = 0.0 real maxSpeed = DEFAULT_MAX_SPEED real minSpeed = 0.0 real angleSpeed = 0.0 real collisionSize = DEFAULT_COLLISION_SIZE private boolean silent = false private LinkedList seenIds = new LinkedList() private boolean dead = false private Angle angleMode = Angle.NO_MOVEMENT private unit homingTargetUnit = null private vec2 homingTarget construct( vec2 pos, angle dir, string _fxPath ) fx = new Fx( pos, dir ) startTimedLoop() abstract function onUnitHit( unit hitTarget ) abstract function loopControl() function setDirection( angle v ) fx.setXYAngle( v ) function setTarget( unit u ) if u == null angleMode = Angle.NO_MOVEMENT else angleMode = Angle.HOMING_UNIT homingTargetUnit = u function setTarget( vec2 target ) angleMode = Angle.HOMING_POINT homingTarget = target function forgetTarget() angleMode = Angle.NO_MOVEMENT function isRotating() returns boolean return angleMode == Angle.ROTATING function setRotating( boolean val ) if val angleMode = Angle.ROTATING else if angleMode == Angle.ROTATING angleMode = Angle.NO_MOVEMENT override function onTimedLoop() expirationTime -= ANIMATION_PERIOD if dead or expirationTime <= 0.0 destroy this else let anglexy = angleBetweenCoords(fx.getPos2().x, fx.getPos2().y, homingTarget.x, homingTarget.y) var df1 = (anglexy - fx.getXYAngle()).radians() var df2 = (PI2 + anglexy.radians()) - fx.getXYAngle().radians() var ns = angleSpeed if ns != 0.0 if angleMode == Angle.HOMING_UNIT if ( GetUnitTypeId(homingTargetUnit) == 0 ) or IsUnitType( homingTargetUnit, UNIT_TYPE_DEAD ) angleMode = Angle.NO_MOVEMENT homingTargetUnit = null else homingTarget = homingTargetUnit.getPos() if not angleMode == Angle.ROTATING and angleMode != Angle.NO_MOVEMENT if ns <= 0. ns = -ns if df1 <= 0 if df2 <= 0 if df2 >= df1 df1 = df2 else if -df1 >= df2 df1 = df2 else if df2 <= 0 if -df2 <= df1 df1 = df2 else if df2 <= df1 df1 = df2 if df1 <= 0 if -df1 >= ns ns = -ns else ns = df1 else if df1 <= ns ns = df1 var d = fx.getXYAngle().radians() d += ns if d >= PI2 d -= PI2 else if d < 0 d += PI2 fx.setXYAngle(angle(d)) ns = speed + acceleration * ANIMATION_PERIOD if ns < minSpeed ns = minSpeed else if ns > maxSpeed ns = maxSpeed let dt = ((speed + ns) /2) * ANIMATION_PERIOD speed = ns let newP = vec2( fx.getX()+dt*fx.getXYAngle().cos(), fx.getY()+dt*fx.getXYAngle().sin()) fx.setXY(newP) GroupEnumUnitsInRange( ENUM_GROUP, newP.x, newP.y, collisionSize + MAX_COLLISION_SIZE, null) let itr = ENUM_GROUP.iterator() for u from itr if not IsUnitType(u, UNIT_TYPE_DEAD) and not(dead) and (GetUnitTypeId(u) != DUMMY_UNIT_ID) and IsUnitInRangeXY(u, newP.x, newP.y, collisionSize) if not seenIds.contains(u.getHandleId() ) onUnitHit(u) itr.close() ENUM_GROUP.clear() if not dead loopControl() function terminate() dead = true function hiddenDestroy() silent = true dead = true ondestroy destroy seenIds if silent fx.hiddenDestroy() else destroy fx stopTimedLoop()