package HomingProjectile import public Entity import Projectile public enum HOMING none // wut attract // Direct homing angular // Chaning angle forced // pushed homing (warlock-like) public interface OnReachedListener function run(Entity target) public class HomingProjectile extends Projectile HOMING htype = HOMING.none Entity target = null var homingSpeed = 0. var radii = 0. var dampeningFactor = 0.98 private OnReachedListener onTargetReached = null construct(vec3 pos, real radius, player owner, angle xyAngle, string fxpath) super(pos, radius, owner, xyAngle, fxpath) function setTarget(Entity e, HOMING htype, real homingspeed) target = e this.htype = htype homingSpeed = homingspeed radii = radius * radius + e.radius * e.radius activate() function onTargetReached(OnReachedListener listener) this.onTargetReached = listener override function update() let tpos = target.getPos() let dist = pos.distanceToSq(tpos + vec3(0, 0, target.radius)) let anglexy = pos.angleTo2d(tpos) if not done and onTargetReached != null and dist < radii onTargetReached.run(target) if not done switch htype case HOMING.none skip case HOMING.attract vel = (tpos - this.pos).setLength(homingSpeed) case HOMING.angular var df1 = (anglexy - getXYAngle()).radians() let df2 = (PI2 + anglexy.radians()) - getXYAngle().radians() var ns = homingSpeed 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 = getXYAngle().radians() d += ns if d >= PI2 d -= PI2 else if d < 0 d += PI2 var newAngle = getXYAngle() newAngle.radians = d vel = newAngle.toVec(getSpeed()).toVec3() setXYAngle(newAngle) case HOMING.forced vel *= dampeningFactor let hforce = ZERO2.polarOffset(anglexy, homingSpeed) vel += hforce if vel.length() > getSpeed() vel.setLength(getSpeed()) super.update() ondestroy if onTargetReached != null destroy onTargetReached