package NET.worlds.scape; import NET.worlds.console.Console; import NET.worlds.core.Std; import NET.worlds.network.URL; import java.io.IOException; import java.util.Enumeration; import java.util.Vector; public class HoloPilot extends Pilot implements AnimatedActionHandler, AnimatedActionCallback { private Camera cam; private SmoothDriver smoothDriver; private boolean cameraIsFree = false; private AnimatedActionHandlerImp handler; private HandsOffDriver hod; String lastName; Transform lastInverse; Point3 lastCamWorldPos; float lastCamRadius; float lastCamYaw; int lastDrawTime; int framesSinceMoved = 0; Room lastCamRoom; Transform defaultTransform = Transform.make(); Point3 aimPoint = new Point3(0.0F, 0.0F, 0.0F); float defaultCameraYaw = 0.0F; float defaultCameraRadius = 0.0F; public static final int CAM_MODE_VEHICLE = 99; public static final int CAM_MODE_FIRST_PERSON = 1; public static final int CAM_MODE_LOW_FIRST_PERSON = 2; public static final int CAM_MODE_WAIST = 3; public static final int CAM_MODE_SHOULDER = 4; public static final int CAM_MODE_HEAD = 5; public static final int CAM_MODE_OVERHEAD = 6; public static final int CAM_MODE_BEHIND = 7; public static final int CAM_MODE_WIDESHOT = 8; public static final int CAM_MODE_ORTHOGRAPHIC = 9; public static final int CAM_SPEED_SLOW = 1; public static final int CAM_SPEED_MEDIUM = 2; public static final int CAM_SPEED_FAST = 3; public static final int CAM_SPEED_LOCKED = 4; private boolean substWarned = false; protected Point3 boxLo = new Point3(); protected Point3 boxHi = new Point3(); protected float stepHeight = 30.0F; private static Object classCookie = new Object(); public HoloPilot(URL movURL) { this.setSourceURL(movURL); this.loadInit(); } @Override public void setSleepMode(String mode) { Drone d = this.getInternalDrone(); if (d != null) { d.setSleepMode(mode); } } @Override public float animate(String action) { super.animate(action); Drone d = this.getInternalDrone(); return d != null ? d.animate(action) : 0.0F; } @Override public Vector getAnimationList() { Vector v = super.getAnimationList(); Drone d = this.getInternalDrone(); if (d == null) { return v; } else { Vector v2 = (Vector)d.getAnimationList().clone(); for (int i = 0; i < v.size(); i++) { v2.addElement(v.elementAt(i)); } return v2; } } public HoloPilot() { } @Override public void loadInit() { this.smoothDriver = new SmoothDriver(); this.smoothDriver.setEyeHeight(0.0F); this.cam = new Camera(); this.add(this.cam); Drone selfImage = Drone.make(null, null); this.add(selfImage); selfImage.setAvatarNow(this.getSourceURL()); this.addHandler(this.smoothDriver); this.addHandler(new PitchDriver()); this.handler = new AnimatedActionHandlerImp(); this.setEyeHeight(150.0F); } @Override public void addCallback(AnimatedActionCallback c) { assert this.handler != null; this.handler.addCallback(c); } @Override public void removeCallback(AnimatedActionCallback c) { assert this.handler != null; this.handler.removeCallback(c); } @Override public void notifyCallbacks(int completionCode) { assert this.handler != null; this.handler.notifyCallbacks(completionCode); } public void walkTo(Point2 destPoint, float destYaw) { this.walkTo(destPoint, destYaw, 80.0F); } public void walkTo(Point2 destPoint, float yaw, float velocity) { this.removeHandler(this.smoothDriver); this.hod = new HandsOffDriver(); this.hod.setDestPos(destPoint, yaw, velocity); this.hod.addCallback(this); this.addHandler(this.hod); } public void removeSmoothDriver() { this.removeHandler(this.smoothDriver); } public void returnSmoothDriver() { this.addHandler(this.smoothDriver); } public SmoothDriver getSmoothDriver() { return this.smoothDriver; } public void removeHandsOffDriver() { if (this.hod != null) { this.removeHandler(this.hod); this.hod = null; } } public void returnHandsOffDriver() { if (this.hod == null) { this.hod = new HandsOffDriver(); this.addHandler(this.hod); } } @Override public void motionComplete(int completionCode) { this.removeHandler(this.hod); this.hod = null; this.addHandler(this.smoothDriver); this.notifyCallbacks(completionCode); } public void updateName() { String name = this.getLongID(); if (name != null) { if (this.lastName == null || !this.lastName.equals(name)) { this.lastName = name; Drone d = this.getInternalDrone(); if (d != null) { d.setName(name); } } } } public Drone getInternalDrone() { Enumeration e = this.getContents(); while (e.hasMoreElements()) { Object o = e.nextElement(); if (o instanceof Drone) { return (Drone)o; } } return null; } private void setLastInverse(Transform t) { if (this.lastInverse != null) { this.lastInverse.recycle(); } this.lastInverse = t; } @Override protected void transferFrom(Pilot old) { if (old != null && old instanceof HoloPilot) { HoloPilot o = (HoloPilot)old; this.setOutsideCameraMode(o.getOutsideCameraMode(), o.getOutsideCameraSpeed()); super.transferFrom(old); if (o.lastCamWorldPos != null) { this.setLastInverse(o.lastInverse.getTransform()); this.lastCamWorldPos = new Point3(o.lastCamWorldPos); } this.lastCamRoom = o.lastCamRoom; this.lastCamRadius = o.lastCamRadius; this.lastCamYaw = o.lastCamYaw; this.lastDrawTime = o.lastDrawTime; this.framesSinceMoved = this.framesSinceMoved; } else { super.transferFrom(old); } } @Override public void aboutToDraw() { if (this.cameraMode == 1 || this.cameraMode == 2) { this.lastCamWorldPos = null; this.cam.makeIdentity(); } else if (!this.cameraIsFree) { Transform world = this.getObjectToWorldMatrix(); int thisDrawTime = Std.getRealTime(); Room thisCamRoom = this.getRoom(); Transform inv = world.getTransform().invert(); float radius; float yaw; if (this.lastCamWorldPos == null || this.cameraSpeed == 4 || this.cameraMode == 99) { this.lastCamWorldPos = new Point3(); radius = this.defaultCameraRadius; yaw = this.defaultCameraYaw; } else if (thisCamRoom != this.lastCamRoom) { yaw = this.lastCamYaw; radius = this.lastCamRadius; } else { Point3 p = this.lastCamWorldPos; p.times(inv); radius = (float)Math.sqrt(p.x * p.x + p.y * p.y); if (radius > this.defaultCameraRadius + 10.0F) { radius = this.defaultCameraRadius + 10.0F; } if (this.cameraSpeed == 3) { radius = this.defaultCameraRadius; } yaw = (float)(Math.atan2(p.y, p.x) * 180.0 / Math.PI); this.lastInverse.post(world); float yawMove = this.lastInverse.getYaw(); if (yawMove > 180.0F) { yawMove -= 360.0F; } Point3Temp lip = this.lastInverse.getPosition(); if (this.cameraSpeed != 1 || Math.abs(yawMove) < 1.0F && lip.x * lip.x + lip.y * lip.y < 1.0F) { if (++this.framesSinceMoved > 2) { float dyaw = this.defaultCameraYaw - yaw; if (dyaw < -180.0F) { dyaw += 360.0F; } else if (dyaw > 180.0F) { dyaw -= 360.0F; } float drad = this.defaultCameraRadius - radius; float dtime = thisDrawTime - this.lastDrawTime; float maxYawCorrection = 0.04F; float maxRadCorrection = 0.03F; if (Math.abs(dyaw) > 1500.0F * maxYawCorrection) { maxYawCorrection *= 1.5F; } maxYawCorrection *= dtime; if (dyaw < -maxYawCorrection) { dyaw = -maxYawCorrection; } else if (dyaw > maxYawCorrection) { dyaw = maxYawCorrection; } maxRadCorrection *= dtime; if (drad < -maxRadCorrection) { drad = -maxRadCorrection; } else if (drad > maxRadCorrection) { drad = maxRadCorrection; } yaw += dyaw; radius += drad; if (this.cameraSpeed == 3) { if (yaw > this.defaultCameraYaw + 40.0F) { yaw = this.defaultCameraYaw + 40.0F; } else if (yaw < this.defaultCameraYaw - 40.0F) { yaw = this.defaultCameraYaw - 40.0F; } } } } else { this.framesSinceMoved = 0; } } this.setLastInverse(inv); float hackedZ = this.aimPoint.z; float hackedYaw = yaw; float hackedRadius = radius; if (this.hod != null) { hackedYaw = yaw + this.hod.getCameraPan(); hackedRadius = radius + this.hod.getCameraZoom(); if (hackedRadius < this.defaultCameraRadius) { hackedZ -= (this.defaultCameraRadius - hackedRadius) * this.smoothDriver.getEyeHeight() / this.defaultCameraRadius; } } this.cam.makeIdentity().post(this.defaultTransform); this.cam.moveBy(hackedRadius, 0.0F, 0.0F); this.cam.postspin(0.0F, 0.0F, 1.0F, hackedYaw); this.cam.moveBy(this.aimPoint.x, this.aimPoint.y, hackedZ); this.lastCamRadius = radius; this.lastCamYaw = yaw; double angle = yaw * Math.PI / 180.0; this.lastCamWorldPos.x = (float)(radius * Math.cos(angle)); this.lastCamWorldPos.y = (float)(radius * Math.sin(angle)); this.lastCamWorldPos.z = 0.0F; this.lastCamWorldPos.times(world); this.lastCamWorldPos.z = 0.0F; this.lastDrawTime = thisDrawTime; this.lastCamRoom = thisCamRoom; world.recycle(); } } @Override public void setOutsideCameraMode(int camMode, int camSpeed) { this.defaultTransform.makeIdentity(); this.aimPoint.x = 0.0F; this.aimPoint.y = 0.0F; this.aimPoint.z = 0.0F; this.setEyeHeight(150.0F); if (this.getInternalDrone() != null && this.getInternalDrone() instanceof PosableDrone) { PosableShape ps = ((PosableDrone)this.getInternalDrone()).getInternalPosableShape(); if (ps != null && ps instanceof VehicleShape) { VehicleShape vs = (VehicleShape)ps; if (vs.fixedCamera) { this.defaultTransform .moveTo(vs.camX, vs.camY, vs.camZ) .postspin(1.0F, 0.0F, 0.0F, vs.camRoll) .postspin(0.0F, 1.0F, 0.0F, vs.camYaw) .postspin(0.0F, 0.0F, 1.0F, vs.camPitch); this.aimPoint.x = vs.camAimX; this.aimPoint.y = vs.camAimY; this.aimPoint.z = vs.camAimZ; this.setEyeHeight(vs.eyeHeight); camMode = 99; } } } this.cam.setAlwaysClearBackground(false); this.cam.setBumpable(true); switch (camMode) { case 1: case 99: break; case 2: this.setEyeHeight(100.0F); break; case 3: this.defaultTransform.moveTo(0.0F, -120.0F, -60.0F).postspin(1.0F, 0.0F, 0.0F, -10.0F).postspin(0.0F, 0.0F, 1.0F, 30.0F); this.aimPoint.x = 15.0F; this.aimPoint.z = -10.0F; break; case 4: this.defaultTransform.moveTo(0.0F, -140.0F, -40.0F).postspin(1.0F, 0.0F, 0.0F, -10.0F).postspin(0.0F, 0.0F, 1.0F, 15.0F); this.aimPoint.x = 15.0F; this.aimPoint.z = 10.0F; break; case 5: this.defaultTransform.moveTo(0.0F, -140.0F, 0.0F).postspin(1.0F, 0.0F, 0.0F, -10.0F).postspin(0.0F, 0.0F, 1.0F, 15.0F); this.aimPoint.x = 15.0F; this.aimPoint.z = 10.0F; break; case 6: this.defaultTransform.moveTo(0.0F, -100.0F, 0.0F).postspin(1.0F, 0.0F, 0.0F, -30.0F).postspin(0.0F, 0.0F, 1.0F, 30.0F); this.aimPoint.x = 15.0F; this.aimPoint.z = 10.0F; break; case 7: this.defaultTransform.moveTo(0.0F, -140.0F, 0.0F).postspin(1.0F, 0.0F, 0.0F, -10.0F); break; case 8: this.defaultTransform.moveTo(0.0F, -220.0F, -40.0F).postspin(1.0F, 0.0F, 0.0F, -30.0F).postspin(0.0F, 0.0F, 1.0F, 30.0F); this.aimPoint.x = 15.0F; this.aimPoint.z = 10.0F; break; case 9: this.defaultTransform.moveTo(0.0F, -140.0F, 300.0F).postspin(1.0F, 0.0F, 0.0F, -10.0F); this.aimPoint.x = 0.0F; this.aimPoint.z = 300.0F; this.cam.setAlwaysClearBackground(true); this.cam.setBumpable(false); camSpeed = 4; break; default: camMode = 1; camSpeed = 3; this.defaultCameraRadius = 0.0F; this.defaultCameraYaw = 0.0F; } if (camMode != 1 && camMode != 2) { float x = this.defaultTransform.getX(); float y = this.defaultTransform.getY(); this.aimPoint.z = this.aimPoint.z + this.defaultTransform.getZ(); this.defaultCameraRadius = (float)Math.sqrt(x * x + y * y); this.defaultCameraYaw = (float)(Math.atan2(y, x) * 180.0 / Math.PI); this.defaultTransform.moveTo(0.0F, 0.0F, 0.0F); this.defaultTransform.postspin(0.0F, 0.0F, 1.0F, -this.defaultCameraYaw); } super.setOutsideCameraMode(camMode, camSpeed); } @Override public void resetAvatarNow() { URL to = this.getSourceURL(); Drone d = this.getInternalDrone(); d.setAvatarNow(to); if (!d.shouldBeForcedHuman() || PosableShape.getHuman(to).equals(to)) { this.substWarned = false; } else if (!this.substWarned) { this.substWarned = true; Console.println(Console.message("Sub-human")); } } public void setEyeHeight(float h) { float hOld = this.smoothDriver.getEyeHeight(); if (h != hOld) { this.smoothDriver.setEyeHeight(h); this.getInternalDrone().moveBy(0.0F, 0.0F, hOld - h); this.setLocalBoundBox(Point3Temp.make(-30.0F, -30.0F, -h), Point3Temp.make(30.0F, 50.0F, 20.0F)); } } public BoundBoxTemp getLocalBoundBox() { return BoundBoxTemp.make(this.boxLo, this.boxHi); } public void setLocalBoundBox(BoundBoxTemp b) { this.boxLo = new Point3(b.lo); this.boxHi = new Point3(b.hi); } public void setLocalBoundBox(Point3Temp lo, Point3Temp hi) { this.setLocalBoundBox(BoundBoxTemp.make(lo, hi)); } @Override public BoundBoxTemp getBoundBox() { Point3Temp lo = Point3Temp.make(this.boxLo); lo.z = lo.z + this.stepHeight; Point3Temp hi = this.boxHi; Transform xfrm = this.getObjectToWorldMatrix(); Point3Temp p = Point3Temp.make(lo).times(xfrm); BoundBoxTemp w = BoundBoxTemp.make(p, p); w.encompass(Point3Temp.make(hi).times(xfrm)); w.encompass(Point3Temp.make(lo.x, lo.y, hi.z).times(xfrm)); w.encompass(Point3Temp.make(lo.x, hi.y, lo.z).times(xfrm)); w.encompass(Point3Temp.make(lo.x, hi.y, hi.z).times(xfrm)); w.encompass(Point3Temp.make(hi.x, lo.y, lo.z).times(xfrm)); w.encompass(Point3Temp.make(hi.x, lo.y, hi.z).times(xfrm)); w.encompass(Point3Temp.make(hi.x, hi.y, lo.z).times(xfrm)); xfrm.recycle(); return w; } @Override public float getFootHeight() { if (this.isActive()) { Transform t = this.getObjectToWorldMatrix(); float pitch = t.getPitch(); t.pitch(-pitch); float ret = Point3Temp.make(this.boxLo).times(t).z; t.recycle(); return ret; } else { return 0.0F; } } public float getStepHeight() { return this.stepHeight; } public void setStepHeight(float h) { this.stepHeight = h; } public void releaseCamera() { this.cameraIsFree = true; } public void reclaimCamera() { this.cameraIsFree = false; } public Camera getCamera() { return this.cam; } @Override public Object properties(int index, int offset, int mode, Object value) throws NoSuchPropertyException { Object ret = null; switch (index - offset) { case 0: if (mode == 0) { ret = Point3PropertyEditor.make(new Property(this, index, "Bump Box Start")); } else if (mode == 1) { ret = new Point3(this.boxLo); } else if (mode == 2) { this.boxLo = new Point3((Point3)value); } break; case 1: if (mode == 0) { ret = Point3PropertyEditor.make(new Property(this, index, "Bump Box End")); } else if (mode == 1) { ret = new Point3(this.boxHi); } else if (mode == 2) { this.boxHi = new Point3((Point3)value); } break; case 2: if (mode == 0) { ret = FloatPropertyEditor.make(new Property(this, index, "Step Height")); } else if (mode == 1) { ret = new Float(this.getStepHeight()); } else if (mode == 2) { this.setStepHeight((Float)value); } break; default: ret = super.properties(index, offset + 3, mode, value); } return ret; } @Override public void saveState(Saver s) throws IOException { s.saveVersion(0, classCookie); super.saveState(s); s.saveFloat(this.stepHeight); s.save(this.boxLo); s.save(this.boxHi); } @Override public void restoreState(Restorer r) throws IOException, TooNewException { switch (r.restoreVersion(classCookie)) { case 0: super.restoreState(r); this.stepHeight = r.restoreFloat(); this.boxLo = (Point3)r.restore(); this.boxHi = (Point3)r.restore(); return; default: throw new TooNewException(); } } }