diff options
Diffstat (limited to 'NET/worlds/scape')
419 files changed, 51033 insertions, 0 deletions
diff --git a/NET/worlds/scape/ASFSoundPlayer.java b/NET/worlds/scape/ASFSoundPlayer.java new file mode 100644 index 0000000..1f87064 --- /dev/null +++ b/NET/worlds/scape/ASFSoundPlayer.java @@ -0,0 +1,108 @@ +package NET.worlds.scape; + +import NET.worlds.network.URL; + +public class ASFSoundPlayer extends MCISoundPlayer { + float ang; + float dist; + float vol; + int leftToRepeat; + int running; + private URL url; + + public ASFSoundPlayer(Sound owner) { + super(owner); + } + + @Override + public boolean open(float volume, float stopDist, boolean atten, boolean pan) { + return true; + } + + @Override + public void close() { + this.stop(); + } + + @Override + public boolean position(Point3Temp cam, Point3Temp obj, Point3Temp out, Point3Temp up) { + Point3Temp toObj = Point3Temp.make(obj).minus(cam); + Point3Temp right = Point3Temp.make(out).cross(up); + float y = toObj.dot(out); + float x = toObj.dot(right); + this.ang = (float)(Math.atan2(y, x) / Math.PI); + this.dist = toObj.length(); + return this.setVolume(this.vol); + } + + @Override + public boolean setVolume(float v) { + return true; + } + + @Override + public int getState() { + this.gotFinished(!ASFThread.isActive()); + return this.running != 0 ? 0 : 1; + } + + @Override + public synchronized void start(int repeatCount) { + if (repeatCount == 0) { + this.running = 0; + } else { + this.leftToRepeat = repeatCount; + if (this.leftToRepeat > 0) { + this.leftToRepeat--; + } + + this.running = 1; + URL myURL = this.owner == null ? this.url : this.owner.getURL(); + this.running = 2; + new ASFThread(myURL, this); + } + } + + @Override + public synchronized void start(URL u) { + this.url = u; + this.start(1); + } + + public static void pauseSystem() { + ASFThread.pauseASF(); + WavSoundPlayer.pauseSystemExceptASF(); + } + + public static void resumeSystem() { + ASFThread.resumeASF(); + WavSoundPlayer.resumeSystemExceptASF(); + } + + @Override + synchronized void gotFinished(boolean f) { + if (f && this.running == 2) { + this.start(this.leftToRepeat); + } + } + + @Override + public synchronized void stop() { + this.leftToRepeat = 0; + ASFThread.stopASF(); + } + + @Override + public void volume(float left, float right) { + } + + public static synchronized boolean isActive() { + return ASFThread.isActive(); + } + + static synchronized void shutdown() { + ASFThread.stopASF(); + } + + static native boolean nativePlay(String var0); +} diff --git a/NET/worlds/scape/ASFThread.java b/NET/worlds/scape/ASFThread.java new file mode 100644 index 0000000..a9e043f --- /dev/null +++ b/NET/worlds/scape/ASFThread.java @@ -0,0 +1,83 @@ +package NET.worlds.scape; + +import NET.worlds.network.Cache; +import NET.worlds.network.CacheFile; +import NET.worlds.network.URL; + +class ASFThread extends Thread { + private URL url; + private ASFSoundPlayer player; + private static ASFThread asfThread; + private static boolean paused; + + ASFThread(URL url, ASFSoundPlayer player) { + this.url = url; + this.player = player; + setASF(this); + } + + @Override + public void run() { + CacheFile cf = Cache.getFile(this.url); + cf.waitUntilLoaded(); + if (cf.error()) { + this.player.running = 3; + releaseASF(this); + } else if (!paused) { + String localName = cf.getLocalName().replace('/', '\\'); + if (!ASFSoundPlayer.nativePlay(localName)) { + this.player.running = 3; + } + + releaseASF(this); + } + } + + static synchronized void pauseASF() { + if (!paused && asfThread != null) { + ASFThread t = asfThread; + stopASF(); + paused = true; + new ASFThread(t.url, t.player); + } + + paused = true; + } + + static synchronized void resumeASF() { + if (paused) { + ASFThread t = asfThread; + paused = false; + if (t != null) { + new ASFThread(t.url, t.player); + } + } + } + + static synchronized void releaseASF(ASFThread t) { + if (asfThread == t) { + asfThread = null; + } + } + + static synchronized void setASF(ASFThread t) { + if (asfThread == null || !asfThread.url.equals(t.url)) { + asfThread = t; + asfThread.setDaemon(true); + asfThread.start(); + } + } + + static synchronized void stopASF() { + if (asfThread != null) { + asfThread = null; + if (!paused) { + ASFSoundPlayer.nativePlay(""); + } + } + } + + static boolean isActive() { + return asfThread != null; + } +} diff --git a/NET/worlds/scape/Action.java b/NET/worlds/scape/Action.java new file mode 100644 index 0000000..98abf35 --- /dev/null +++ b/NET/worlds/scape/Action.java @@ -0,0 +1,70 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public abstract class Action extends SuperRoot { + public String rightMenuLabel; + private static Object classCookie = new Object(); + + public abstract Persister trigger(Event var1, Persister var2); + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(4, classCookie); + s.saveString(this.rightMenuLabel); + super.saveState(s); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 1: + r.restoreInt(); + this.setName(r.restoreString()); + case 0: + r.setOldFlag(); + break; + case 2: + r.setOldFlag(); + super.restoreState(r); + r.restoreInt(); + break; + case 4: + this.rightMenuLabel = r.restoreString(); + case 3: + super.restoreState(r); + break; + default: + throw new TooNewException(); + } + } + + @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 = BooleanPropertyEditor.make(new Property(this, index, "Trigger Now"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(false); + } else if (mode == 2 && (Boolean)value) { + RunningActionHandler.trigger(this, this.getWorld(), null); + } + break; + case 1: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Right Menu Label").allowSetNull()); + } else if (mode == 1) { + ret = this.rightMenuLabel; + } else if (mode == 2) { + this.rightMenuLabel = (String)value; + } + break; + default: + ret = super.properties(index, offset + 2, mode, value); + } + + return ret; + } +} diff --git a/NET/worlds/scape/Action_Animation.java b/NET/worlds/scape/Action_Animation.java new file mode 100644 index 0000000..615cea3 --- /dev/null +++ b/NET/worlds/scape/Action_Animation.java @@ -0,0 +1,24 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class Action_Animation extends Action { + @Override + public Persister trigger(Event e, Persister seqID) { + return null; + } + + @Override + public void saveState(Saver s) throws IOException { + assert false; + } + + @Override + public void restoreState(Restorer r) throws IOException { + AnimateAction a = new AnimateAction(); + r.replace(this, a); + a.cycleTime = (int)r.restoreFloat(); + a.cycles = r.restoreInt(); + a.frameList = r.restoreString(); + } +} diff --git a/NET/worlds/scape/Action_Motion.java b/NET/worlds/scape/Action_Motion.java new file mode 100644 index 0000000..b7eaaa0 --- /dev/null +++ b/NET/worlds/scape/Action_Motion.java @@ -0,0 +1,38 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class Action_Motion extends Action { + @Override + public Persister trigger(Event e, Persister seqID) { + return null; + } + + @Override + public void saveState(Saver s) throws IOException { + assert false; + } + + @Override + public void restoreState(Restorer r) throws IOException { + MoveAction a = new MoveAction(); + r.replace(this, a); + a.cycleTime = (int)r.restoreFloat(); + a.cycles = r.restoreInt(); + + try { + a.extentPoint.restoreState(r); + a.startPoint.restoreState(r); + a.extentScale.restoreState(r); + a.startScale.restoreState(r); + a.extentSpin.restoreState(r); + a.startSpin.restoreState(r); + } catch (Exception var4) { + } + + a.extentRotation = r.restoreFloat(); + a.startRotation = r.restoreFloat(); + a.extentPoint.minus(a.startPoint); + a.extentScale.dividedBy(a.startScale); + } +} diff --git a/NET/worlds/scape/Action_Toggle.java b/NET/worlds/scape/Action_Toggle.java new file mode 100644 index 0000000..4be876b --- /dev/null +++ b/NET/worlds/scape/Action_Toggle.java @@ -0,0 +1,23 @@ +package NET.worlds.scape; + +import java.io.IOException; + +class Action_Toggle extends Action { + @Override + public Persister trigger(Event e, Persister seqID) { + return null; + } + + @Override + public void saveState(Saver s) throws IOException { + assert false; + } + + @Override + public void restoreState(Restorer r) throws IOException { + SetVisibleBumpableAction a = new SetVisibleBumpableAction(); + r.replace(this, a); + a.targetBumpable = r.restoreBoolean(); + a.targetVisible = r.restoreBoolean(); + } +} diff --git a/NET/worlds/scape/AddObjectAction.java b/NET/worlds/scape/AddObjectAction.java new file mode 100644 index 0000000..2a43f2d --- /dev/null +++ b/NET/worlds/scape/AddObjectAction.java @@ -0,0 +1,69 @@ +package NET.worlds.scape; + +import java.io.IOException; +import java.util.Vector; + +public class AddObjectAction extends SetPropertyAction { + private SuperRoot _value; + private static Object classCookie = new Object(); + + @Override + public Persister trigger(Event e, Persister seqID) { + assert !this.useParam(); + + this.add((Object)this._value); + return null; + } + + @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) { + VectorProperty vp = new VectorProperty(this, index, "Object to Add"); + if (this._value != null) { + vp.allowSetNull(); + ret = vp; + } + } else if (mode == 1) { + ret = new Vector(1); + if (this._value != null) { + ((Vector)ret).addElement(this._value); + } + } else if (mode == 4) { + assert value == this._value; + + this._value = null; + } else if (mode == 3) { + assert this._value == null; + + this._value = (SuperRoot)value; + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + super.saveState(s); + s.saveMaybeNull(this._value); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 1: + super.restoreState(r); + this._value = (SuperRoot)r.restoreMaybeNull(); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/AdvancingAction.java b/NET/worlds/scape/AdvancingAction.java new file mode 100644 index 0000000..909b1b2 --- /dev/null +++ b/NET/worlds/scape/AdvancingAction.java @@ -0,0 +1,114 @@ +package NET.worlds.scape; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.Vector; + +public class AdvancingAction extends Action { + private Vector actions = new Vector(); + private int nextAction = 0; + boolean singleTrigger = true; + boolean inProgress = false; + private static Object classCookie = new Object(); + + @Override + public Persister trigger(Event evt, Persister seqID) { + if (this.singleTrigger && this.inProgress && seqID == null) { + return null; + } else { + if (this.nextAction >= this.actions.size()) { + this.nextAction = 0; + } + + Action act = (Action)this.actions.elementAt(this.nextAction); + Persister id = null; + if (act != null) { + id = act.trigger(evt, seqID); + this.inProgress = id != null; + } + + if (id == null || !this.singleTrigger) { + this.nextAction++; + } + + return id; + } + } + + public void addComponent(Action act) { + this.actions.addElement(act); + } + + public void insertComponent(Action act, int index) { + this.actions.insertElementAt(act, index); + } + + public boolean removeComponent(Action act) { + return this.actions.removeElement(act); + } + + public Enumeration getComponents() { + return this.actions.elements(); + } + + @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) { + VectorProperty vp = new VectorProperty(this, index, "Components"); + vp.allowSorting(false); + ret = ObjectPropertyAdder.make(vp, this.getRoot(), "NET.worlds.scape.Action"); + } else if (mode == 1) { + ret = this.actions.clone(); + } else if (mode == 4) { + this.actions.removeElement(value); + } else if (mode == 3) { + this.actions.addElement((Action)value); + } + break; + case 1: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Prevent overlapping actions"), "Overlapping", "One at a time"); + } else if (mode == 1) { + ret = new Boolean(this.singleTrigger); + } else if (mode == 2) { + this.singleTrigger = (Boolean)value; + } + break; + default: + ret = super.properties(index, offset + 2, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + super.saveState(s); + s.saveVector(this.actions); + s.saveInt(this.nextAction); + s.saveBoolean(this.singleTrigger); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this.actions = r.restoreVector(); + this.nextAction = r.restoreInt(); + break; + case 1: + super.restoreState(r); + this.actions = r.restoreVector(); + this.nextAction = r.restoreInt(); + this.singleTrigger = r.restoreBoolean(); + break; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/Animatable.java b/NET/worlds/scape/Animatable.java new file mode 100644 index 0000000..d5fb63e --- /dev/null +++ b/NET/worlds/scape/Animatable.java @@ -0,0 +1,7 @@ +package NET.worlds.scape; + +public interface Animatable { + boolean hasClump(); + + void setMaterial(Material var1); +} diff --git a/NET/worlds/scape/AnimateAction.java b/NET/worlds/scape/AnimateAction.java new file mode 100644 index 0000000..44f2520 --- /dev/null +++ b/NET/worlds/scape/AnimateAction.java @@ -0,0 +1,202 @@ +package NET.worlds.scape; + +import NET.worlds.core.Std; +import java.io.IOException; + +public class AnimateAction extends Action { + int startTime; + public int cycleTime = 1000; + public String frameList = ""; + protected int frameListCount = 0; + protected Material[] frameMaterialArray = null; + public int cycles = 0; + public boolean infiniteLoop = false; + protected int cycleNo; + protected int currentFrameNo; + private boolean running = false; + private static Object classCookie = new Object(); + + public AnimateAction() { + this.startAnimation(); + } + + public void startAnimation() { + this.cycleNo = 0; + this.currentFrameNo = -1; + this.startTime = Std.getRealTime(); + } + + public void preprocessFrameList(String frameList) { + this.frameMaterialArray = AnimatingDoor.namesToMaterialArray(this, frameList); + this.frameListCount = this.frameMaterialArray == null ? 0 : this.frameMaterialArray.length; + } + + @Override + public void detach() { + if (this.frameMaterialArray != null) { + int i = this.frameMaterialArray.length; + + while (--i >= 0) { + this.frameMaterialArray[i].setKeepLoaded(false); + } + + this.frameMaterialArray = null; + this.frameListCount = 0; + } + + super.detach(); + } + + @Override + public Persister trigger(Event e, Persister seqID) { + Object owner = this.getOwner(); + if (!(owner instanceof Animatable)) { + this.frameMaterialArray = null; + this.frameListCount = 0; + return null; + } else { + Animatable o = (Animatable)owner; + if (!o.hasClump()) { + this.frameMaterialArray = null; + this.frameListCount = 0; + return seqID; + } else { + if (this.frameMaterialArray == null) { + this.preprocessFrameList(this.frameList); + } + + if (seqID == null) { + if (this.running && !this.infiniteLoop) { + return null; + } + + this.startAnimation(); + } + + int nextFrameNo = 0; + if (this.frameListCount != 0 && this.cycleTime > 0) { + int runTime = Std.getRealTime() - this.startTime; + long frameNo = (long)this.frameListCount * runTime / this.cycleTime; + this.cycleNo = (int)(frameNo / this.frameListCount); + nextFrameNo = (int)(frameNo - this.cycleNo * this.frameListCount); + } else { + this.cycleNo = 1000000000; + } + + if (this.cycleNo >= this.cycles && !this.infiniteLoop) { + nextFrameNo = this.frameListCount - 1; + this.running = false; + } else { + this.running = true; + } + + if (nextFrameNo != this.currentFrameNo) { + this.currentFrameNo = nextFrameNo; + if (o.hasClump() && this.currentFrameNo >= 0) { + o.setMaterial(this.frameMaterialArray[this.currentFrameNo]); + } + } + + return this.running ? this : null; + } + } + } + + @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 = IntegerPropertyEditor.make(new Property(this, index, "Cycle Time")); + } else if (mode == 1) { + ret = new Integer(this.cycleTime); + } else if (mode == 2) { + this.cycleTime = (Integer)value; + } + break; + case 1: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Cycles")); + } else if (mode == 1) { + ret = new Integer(this.cycles); + } else if (mode == 2) { + this.cycles = (Integer)value; + } + break; + case 2: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Infinite Loop"), "False", "True"); + } else if (mode == 1) { + ret = new Boolean(this.infiniteLoop); + } else if (mode == 2) { + this.infiniteLoop = (Boolean)value; + } + break; + case 3: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Frame List")); + } else if (mode == 1) { + ret = new String(this.frameList); + } else if (mode == 2) { + this.frameList = ((String)value).toString().trim().toLowerCase(); + this.preprocessFrameList(this.frameList); + } + break; + default: + ret = super.properties(index, offset + 4, mode, value); + } + + return ret; + } + + @Override + public String toString() { + String ret = super.toString() + "[cycleTime " + this.cycleTime + ", cycles " + this.cycles + ","; + if (!this.infiniteLoop) { + ret = ret + " not "; + } + + return ret + "Infinite ]"; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(3, classCookie); + super.saveState(s); + s.saveBoolean(this.infiniteLoop); + s.saveInt(this.cycleTime); + s.saveInt(this.cycles); + s.saveString(this.frameList); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 1: + super.restoreState(r); + case 0: + this.cycleTime = (int)r.restoreFloat(); + this.cycles = r.restoreInt(); + this.infiniteLoop = this.cycles == 0; + this.frameList = r.restoreString(); + break; + case 2: + super.restoreState(r); + this.cycleTime = r.restoreInt(); + this.cycles = r.restoreInt(); + this.infiniteLoop = this.cycles == 0; + this.frameList = r.restoreString(); + break; + case 3: + super.restoreState(r); + this.infiniteLoop = r.restoreBoolean(); + this.cycleTime = r.restoreInt(); + this.cycles = r.restoreInt(); + this.frameList = r.restoreString(); + break; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/AnimatedAction.java b/NET/worlds/scape/AnimatedAction.java new file mode 100644 index 0000000..95e6d23 --- /dev/null +++ b/NET/worlds/scape/AnimatedAction.java @@ -0,0 +1,203 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.DefaultConsole; +import NET.worlds.core.Timer; +import NET.worlds.core.TimerCallback; +import NET.worlds.network.URL; +import java.util.Vector; + +public class AnimatedAction implements AnimatedActionCallback, TimerCallback { + static final int noAction = 0; + static final int addToInventory = 1; + static final int removeObject = 2; + static final int animateObject = 3; + static final int moveObjectTo = 4; + static final int playSound = 5; + static final int obtainConsent = 0; + static final int zoomOut = 1; + static final int moveToObject = 2; + static final int preAnimateAction = 3; + static final int actOnObject1 = 4; + static final int simulAnimateAction = 5; + static final int postAnimateAction = 6; + static final int actOnObject2 = 7; + static final int zoomBack = 8; + static String[] actions = new String[]{"noAction", "addToInventory", "removeObject", "animateObject", "moveObjectTo", "playSound"}; + String actionName; + Vector avatarNames; + Vector targetObjects; + Shape _targetShape = null; + boolean consentRequired; + Point2 targetRelPosition; + Point2 targetPosition; + double targetRelYaw; + float targetYaw; + int preAnimationAction; + String preAnimationParameter; + String actionName1; + int simultaneousAction; + String simultaneousParameter; + int postAnimationAction; + String postAnimationParameter; + String actionName2; + int _oldMode; + int _oldSpeed; + private int _state; + private HoloPilot _pilot; + private float _waitTime; + + AnimatedAction() { + this.avatarNames = new Vector(); + this.targetObjects = new Vector(); + } + + public static int getAction(String action) { + for (int i = 0; i < actions.length; i++) { + if (action.equals(actions[i])) { + return i; + } + } + + return 0; + } + + void setTargetShape(Shape s) { + this._targetShape = s; + Point3Temp objVec = Point3Temp.make(this.targetRelPosition.x, this.targetRelPosition.y, 0.0F); + this.targetYaw = this._targetShape.getObjectToWorldMatrix().getYaw(); + Transform t = new Transform(); + t.yaw(-this.targetYaw); + objVec.vectorTimes(t); + t.recycle(); + Point3Temp shapePos = this._targetShape.getWorldPosition(); + objVec.plus(shapePos); + this.targetPosition = new Point2(objVec.x, objVec.y); + } + + public void execute(HoloPilot pilot) { + if (this._targetShape == null) { + System.out.println("No target shape for action " + this.actionName); + } else { + this._targetShape.setBumpable(false); + this._pilot = pilot; + this._state = 0; + this.stateChanged(); + } + } + + @Override + public void motionComplete(int completionCode) { + this._state++; + this.stateChanged(); + } + + @Override + public void timerDone() { + this.motionComplete(0); + } + + private void stateChanged() { + switch (this._state) { + case 0: + this.motionComplete(0); + break; + case 1: + Console c = Console.getActive(); + if (c instanceof DefaultConsole) { + Pilot p = Pilot.getActive(); + this._oldMode = p.getOutsideCameraMode(); + this._oldSpeed = p.getOutsideCameraSpeed(); + p.setOutsideCameraMode(8, 1); + } + + this.motionComplete(0); + break; + case 2: + double newYaw = this.targetYaw + this.targetRelYaw; + this._pilot.addCallback(this); + this._pilot.walkTo(new Point2(this.targetPosition.x, this.targetPosition.y), (float)newYaw); + break; + case 3: + this._pilot.removeSmoothDriver(); + this._pilot.returnHandsOffDriver(); + this.doAction(this.preAnimationAction, this.preAnimationParameter); + this.motionComplete(0); + break; + case 4: + case 7: + String actionName; + if (this._state == 4) { + actionName = this.actionName1; + } else { + actionName = this.actionName2; + } + + this._waitTime = this._pilot.animate(actionName); + this.motionComplete(0); + break; + case 5: + this.doAction(this.simultaneousAction, this.simultaneousParameter + "|sender|" + this.actionName1); + Timer tm = new Timer(this._waitTime, this); + tm.start(); + break; + case 6: + this.doAction(this.postAnimationAction, this.postAnimationParameter); + this.motionComplete(0); + break; + case 8: + Console c = Console.getActive(); + if (c instanceof DefaultConsole) { + Pilot p = Pilot.getActive(); + p.setOutsideCameraMode(this._oldMode, this._oldSpeed); + } + + this._pilot.removeHandsOffDriver(); + this._pilot.returnSmoothDriver(); + AnimatedActionManager.get().actionCompleted(this); + this.motionComplete(0); + } + } + + public void abort() { + this._state = 8; + this.stateChanged(); + } + + private void doAction(int action, String parameter) { + switch (action) { + case 5: + Sound s = new Sound(URL.make(parameter)); + this._pilot.add(s); + s.trigger(null, null); + case 3: + Drone targetDrone = null; + if (this._targetShape != null && this._targetShape instanceof PosableShape) { + SuperRoot owner = this._targetShape.getOwner(); + if (owner instanceof Drone) { + targetDrone = (Drone)owner; + } + } + + if (targetDrone != null) { + Pilot.sendText(targetDrone.getLongID(), "&|+action2>" + parameter); + } + + if (this._targetShape instanceof PosableShape) { + String actionName = null; + int idx = parameter.indexOf("|sender|"); + if (idx != -1) { + actionName = parameter.substring(0, idx); + } else { + actionName = parameter; + } + + ((PosableShape)this._targetShape).animate(actionName); + } + case 0: + case 1: + case 2: + case 4: + } + } +} diff --git a/NET/worlds/scape/AnimatedActionCallback.java b/NET/worlds/scape/AnimatedActionCallback.java new file mode 100644 index 0000000..516ff6f --- /dev/null +++ b/NET/worlds/scape/AnimatedActionCallback.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface AnimatedActionCallback { + void motionComplete(int var1); +} diff --git a/NET/worlds/scape/AnimatedActionHandler.java b/NET/worlds/scape/AnimatedActionHandler.java new file mode 100644 index 0000000..7fdea88 --- /dev/null +++ b/NET/worlds/scape/AnimatedActionHandler.java @@ -0,0 +1,9 @@ +package NET.worlds.scape; + +public interface AnimatedActionHandler { + void addCallback(AnimatedActionCallback var1); + + void removeCallback(AnimatedActionCallback var1); + + void notifyCallbacks(int var1); +} diff --git a/NET/worlds/scape/AnimatedActionHandlerImp.java b/NET/worlds/scape/AnimatedActionHandlerImp.java new file mode 100644 index 0000000..2b32de3 --- /dev/null +++ b/NET/worlds/scape/AnimatedActionHandlerImp.java @@ -0,0 +1,37 @@ +package NET.worlds.scape; + +import java.util.Enumeration; +import java.util.Vector; + +public class AnimatedActionHandlerImp implements AnimatedActionHandler { + Vector callbacks = new Vector(); + + AnimatedActionHandlerImp() { + } + + @Override + public void addCallback(AnimatedActionCallback c) { + assert this.callbacks != null; + + this.callbacks.addElement(c); + } + + @Override + public void removeCallback(AnimatedActionCallback c) { + assert this.callbacks != null; + + this.callbacks.removeElement(c); + } + + @Override + public void notifyCallbacks(int completionCode) { + assert this.callbacks != null; + + Enumeration e = this.callbacks.elements(); + + while (e.hasMoreElements()) { + AnimatedActionCallback c = (AnimatedActionCallback)e.nextElement(); + c.motionComplete(completionCode); + } + } +} diff --git a/NET/worlds/scape/AnimatedActionManager.java b/NET/worlds/scape/AnimatedActionManager.java new file mode 100644 index 0000000..5ab97a9 --- /dev/null +++ b/NET/worlds/scape/AnimatedActionManager.java @@ -0,0 +1,329 @@ +package NET.worlds.scape; + +import NET.worlds.core.IniFile; +import NET.worlds.network.NetUpdate; +import NET.worlds.network.URL; +import java.awt.Menu; +import java.awt.MenuItem; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.Enumeration; +import java.util.StringTokenizer; +import java.util.Vector; + +public class AnimatedActionManager implements ActionListener, BGLoaded { + private AnimatedAction _currentAction = null; + static final String actionFile = "actions/actions.dat"; + static final String localActionFile = "actions.dat"; + static final String version = "VERSION"; + static final String action = "ACTION"; + private Vector actionList; + private Vector currentMenuActions; + private static AnimatedActionManager theAnimatedActionManager = null; + + public static AnimatedActionManager get() { + if (theAnimatedActionManager == null) { + theAnimatedActionManager = new AnimatedActionManager(); + } + + return theAnimatedActionManager; + } + + private Vector getActionList(URL avatar, URL object) { + if (this.actionList != null && avatar != null && object != null) { + String av = PosableShape.getBodyType(avatar); + if (av == null) { + return null; + } else { + String ob = object.toString(); + int dot = ob.lastIndexOf("."); + if (dot != -1) { + ob = ob.substring(0, dot); + } + + Vector ret = new Vector(); + Enumeration e = this.actionList.elements(); + + while (e.hasMoreElements()) { + AnimatedAction a = (AnimatedAction)e.nextElement(); + if (this.vectorCheck(av, a.avatarNames) && this.vectorCheck(ob, a.targetObjects)) { + ret.addElement(a); + } + } + + return ret; + } + } else { + return null; + } + } + + private boolean vectorCheck(String s, Vector v) { + Enumeration e = v.elements(); + + while (e.hasMoreElements()) { + String element = (String)e.nextElement(); + if (s.toLowerCase().endsWith(element.toLowerCase())) { + return true; + } + + if (element.equals("any")) { + return true; + } + } + + return false; + } + + public boolean buildActionMenu(Menu m, Shape target) { + assert m != null; + + if (this._currentAction != null) { + return false; + } else { + SuperRoot ultimateOwner = target; + + while (ultimateOwner.getOwner() != null) { + ultimateOwner = ultimateOwner.getOwner(); + if (ultimateOwner instanceof PosableShape) { + target = (Shape)ultimateOwner; + break; + } + } + + Pilot p = Pilot.getActive(); + if (p == null) { + return false; + } else if (!(p instanceof HoloPilot)) { + return false; + } else { + HoloPilot hp = (HoloPilot)p; + if (hp.getInternalDrone().getRoom() != target.getRoom()) { + return false; + } else { + Vector v = this.getActionList(hp.getInternalDrone().getCurrentURL(), target.getURL()); + this.currentMenuActions = v; + if (v == null) { + return false; + } else if (v.size() == 0) { + return false; + } else { + Enumeration e = v.elements(); + + while (e.hasMoreElements()) { + AnimatedAction a = (AnimatedAction)e.nextElement(); + a.setTargetShape(target); + int idx = a.actionName.indexOf("\\"); + if (idx != -1) { + String action = a.actionName.substring(idx + 1); + String submenu = a.actionName.substring(0, idx); + int items = m.getItemCount(); + boolean inserted = false; + + for (int i = 0; i < items; i++) { + MenuItem item = m.getItem(i); + if (item.getLabel().equals(submenu) && item instanceof Menu) { + ((Menu)item).add(action); + inserted = true; + break; + } + } + + if (!inserted) { + Menu sm = new Menu(submenu); + sm.addActionListener(this); + sm.add(action); + m.add(sm); + } + } else { + m.add(a.actionName); + } + } + + return true; + } + } + } + } + } + + public boolean processMenuClick(String actionName) { + if (this.currentMenuActions == null) { + return false; + } else { + Enumeration e = this.currentMenuActions.elements(); + + while (e.hasMoreElements()) { + AnimatedAction a = (AnimatedAction)e.nextElement(); + String thisAction = a.actionName; + int idx = thisAction.indexOf(92); + if (idx != -1) { + thisAction = thisAction.substring(idx + 1); + } + + if (thisAction.equals(actionName)) { + Pilot p = Pilot.getActive(); + if (p == null) { + return false; + } + + if (!(p instanceof HoloPilot)) { + return false; + } + + HoloPilot hp = (HoloPilot)p; + if (this._currentAction != null) { + this._currentAction.abort(); + } + + this._currentAction = a; + a.execute(hp); + return true; + } + } + + return false; + } + } + + public void actionCompleted(AnimatedAction a) { + assert a == this._currentAction; + + this._currentAction = null; + } + + @Override + public void actionPerformed(ActionEvent e) { + this.processMenuClick(e.getActionCommand()); + } + + private AnimatedActionManager() { + System.out.println("Loading action manager"); + this.actionList = new Vector(); + this.loadActionsFile(); + } + + private void loadActionsFile() { + File f = new File("actions.dat"); + if (f.exists()) { + this.parseActionFile("actions.dat"); + } + + String serv = NetUpdate.getUpgradeServerURL(); + String s = IniFile.override().getIniString("actionFile", "actions/actions.dat"); + BackgroundLoader.get(this, URL.make(serv + s)); + } + + @Override + public synchronized Object asyncBackgroundLoad(String localName, URL remoteURL) { + return localName; + } + + @Override + public boolean syncBackgroundLoad(Object obj, URL remoteURL) { + System.out.println("Got actions file "); + String localName = (String)obj; + if (localName != null && new File(localName).exists()) { + this.parseActionFile(localName); + } + + return false; + } + + @Override + public Room getBackgroundLoadRoom() { + return null; + } + + private String getLine(RandomAccessFile fIn) throws IOException { + while (fIn.getFilePointer() < fIn.length()) { + String line = fIn.readLine().trim(); + if (line == null) { + return null; + } + + if (!line.startsWith("//") && line.length() != 0) { + return line; + } + } + + return null; + } + + private void parseActionFile(String fileName) { + int verNum = 0; + + assert this.actionList != null; + + this.actionList.removeAllElements(); + + try { + RandomAccessFile fIn = new RandomAccessFile(fileName, "r"); + + String line; + while ((line = this.getLine(fIn)) != null) { + StringTokenizer tok = new StringTokenizer(line); + String firstWord = tok.nextToken(); + if (firstWord.equals("VERSION")) { + String ver = tok.nextToken(); + if (ver.equals("1")) { + verNum = 1; + } else { + if (!ver.equals("2")) { + throw new Exception("Bad version."); + } + + verNum = 2; + } + } else if (firstWord.equals("ACTION")) { + if (verNum == 0) { + throw new Exception("Actions file version not specified."); + } + + AnimatedAction a = new AnimatedAction(); + a.actionName = line.substring("ACTION".length() + 1); + this.readVector(fIn, a.avatarNames); + this.readVector(fIn, a.targetObjects); + if (verNum > 1) { + a.consentRequired = this.getLine(fIn).toLowerCase().equals("consent"); + } + + StringTokenizer tok2 = new StringTokenizer(this.getLine(fIn)); + Float x = new Float(tok2.nextToken()); + Float y = new Float(tok2.nextToken()); + a.targetRelPosition = new Point2(x, y); + Float yaw = new Float(this.getLine(fIn)); + a.targetRelYaw = yaw.floatValue(); + a.preAnimationAction = AnimatedAction.getAction(this.getLine(fIn)); + a.preAnimationParameter = this.getLine(fIn); + a.actionName1 = this.getLine(fIn); + if (verNum > 1) { + a.simultaneousAction = AnimatedAction.getAction(this.getLine(fIn)); + a.simultaneousParameter = this.getLine(fIn); + } + + a.postAnimationAction = AnimatedAction.getAction(this.getLine(fIn)); + a.postAnimationParameter = this.getLine(fIn); + a.actionName2 = this.getLine(fIn); + this.actionList.addElement(a); + } + } + + fIn.close(); + } catch (Exception var12) { + System.out.println("Error reading actions.dat: " + var12.toString()); + } + } + + private void readVector(RandomAccessFile fIn, Vector v) throws IOException { + String line = this.getLine(fIn); + StringTokenizer tok = new StringTokenizer(line); + + while (tok.hasMoreTokens()) { + v.addElement(tok.nextToken()); + } + } +} diff --git a/NET/worlds/scape/AnimatingDoor.java b/NET/worlds/scape/AnimatingDoor.java new file mode 100644 index 0000000..5a974f9 --- /dev/null +++ b/NET/worlds/scape/AnimatingDoor.java @@ -0,0 +1,301 @@ +package NET.worlds.scape; + +import NET.worlds.core.Std; +import NET.worlds.network.URL; +import java.io.IOException; +import java.net.MalformedURLException; +import java.util.StringTokenizer; +import java.util.Vector; + +public class AnimatingDoor extends Portal implements FrameHandler { + public String frameList = ""; + protected transient Material[] frames = null; + float perFrame = 100.0F; + private URL openSound; + private URL closeSound; + private transient float state; + private transient int lastUpdate; + private transient boolean wasSameRoom; + private transient int lastFrame = -1; + private Point3 start = new Point3(-0.5F, -1.0F, 0.0F); + private Point3 end = new Point3(1.5F, 0.0F, 1.0F); + private static Object classCookie = new Object(); + + public AnimatingDoor() { + this.flags |= 262208; + } + + @Override + public void detach() { + if (this.frames != null) { + int i = this.frames.length; + + while (--i >= 0) { + this.frames[i].setKeepLoaded(false); + } + + this.frames = null; + } + + super.detach(); + } + + @Override + public boolean handle(FrameEvent e) { + Pilot pilot = Pilot.getActive(); + Room pilotRoom = pilot.getRoom(); + boolean sameRoom = pilotRoom == this.getRoom(); + boolean inRange = false; + Point3Temp pos = pilot.getPosition(); + if (sameRoom) { + BoundBoxTemp bbt = BoundBoxTemp.make(Point3Temp.make(this.start).times(this), Point3Temp.make(this.end).times(this)); + inRange = bbt.contains(pos); + } + + Portal far = this.farSide(); + if (far != null && far instanceof AnimatingDoor) { + AnimatingDoor afar = (AnimatingDoor)far; + if (!inRange) { + Room farRoom = afar.getRoom(); + if (farRoom == null) { + this.animate(sameRoom, inRange); + return true; + } + + if (afar.getRoom() == pilotRoom) { + if (!sameRoom) { + return true; + } + + BoundBoxTemp bbt = BoundBoxTemp.make(Point3Temp.make(afar.start).times(afar), Point3Temp.make(afar.end).times(afar)); + inRange = bbt.contains(pos); + } + } + + afar.animate(sameRoom, inRange); + } + + this.animate(sameRoom, inRange); + return true; + } + + private void animate(boolean sameRoom, boolean inRange) { + int now = Std.getFastTime(); + float oldState = this.state; + if (this.frames == null) { + this.frames = namesToMaterialArray(this, this.frameList); + this.lastFrame = -1; + } + + int numMovingFrames = this.frames.length - 2; + boolean wasSameRoom = this.wasSameRoom; + this.wasSameRoom = sameRoom; + if (!sameRoom) { + this.state = 0.0F; + } else if (!wasSameRoom) { + this.state = inRange ? 1.0F : 0.0F; + } else if (this.state == 0.0F) { + if (!inRange) { + return; + } + + this.state = 1.0E-4F; + } else if (this.state == 1.0F) { + if (inRange) { + return; + } + + this.playSound(this.closeSound); + this.state = 0.999F; + } else { + if (this.state == 1.0E-4F && inRange) { + if (this.active()) { + this.playSound(this.openSound); + this.state = 2.0E-4F; + } else { + this.lastUpdate = now; + } + } + + float totalTime = numMovingFrames * this.perFrame; + if (totalTime > 0.0F && now != this.lastUpdate) { + float distMoved = (now - this.lastUpdate) / totalTime; + if (inRange) { + if ((this.state += distMoved) >= 1.0F) { + this.state = 1.0F; + } + } else if ((this.state -= distMoved) <= 0.0F) { + this.state = 0.0F; + } + } + } + + if (oldState != 0.0F && this.state == 0.0F) { + this.flags |= 262144; + this.reset(); + } else if (oldState == 0.0F && this.state != 0.0F) { + this.flags &= -262145; + this.reset(); + this.triggerLoad(); + } + + this.lastUpdate = now; + int frame = 0; + if (numMovingFrames >= 0) { + if (this.state <= 2.0E-4F) { + frame = 0; + } else if (this.state == 1.0F) { + frame = numMovingFrames + 1; + } else { + frame = 1 + (int)(this.state * numMovingFrames); + } + } else if (numMovingFrames == -2) { + return; + } + + this.setFrame(frame); + } + + private void setFrame(int frame) { + if (frame != this.lastFrame && this.frames != null && this.frames.length > frame) { + this.setMaterial(this.frames[frame]); + this.lastFrame = frame; + } + } + + private void playSound(URL url) { + if (url != null && this.getRoom() == Pilot.getActive().getRoom()) { + WavSoundPlayer wavPlayer = new WavSoundPlayer(null); + wavPlayer.open(1.0F, 0.0F, false, false); + wavPlayer.start(url); + } + } + + public static Material[] namesToMaterialArray(SuperRoot base, String str) { + Vector v = new Vector(); + StringTokenizer st = new StringTokenizer(str); + + while (st.hasMoreTokens()) { + v.addElement(st.nextToken()); + } + + int count = v.size(); + Material[] mats = new Material[count]; + int i = count; + + while (--i >= 0) { + String s = (String)v.elementAt(i); + + URL url; + try { + url = new URL(base, s); + } catch (MalformedURLException var10) { + url = URL.make("error:\"" + s + '"'); + } + + mats[i] = new Material(url); + mats[i].setKeepLoaded(true); + } + + return mats; + } + + @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 = StringPropertyEditor.make(new Property(this, index, "Frame List")); + } else if (mode == 1) { + ret = this.frameList; + } else if (mode == 2) { + this.frameList = ((String)value).toString().trim(); + this.frames = null; + } + break; + case 1: + if (mode == 0) { + ret = Point3PropertyEditor.make(new Property(this, index, "Start")); + } else if (mode == 1) { + ret = new Point3(this.start); + } else if (mode == 2) { + this.start = (Point3)value; + } + break; + case 2: + if (mode == 0) { + ret = Point3PropertyEditor.make(new Property(this, index, "End")); + } else if (mode == 1) { + ret = new Point3(this.end); + } else if (mode == 2) { + this.end = (Point3)value; + } + break; + case 3: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Time Per Frame")); + } else if (mode == 1) { + ret = new Float(this.perFrame); + } else if (mode == 2) { + this.perFrame = (Float)value; + } + break; + case 4: + if (mode == 0) { + ret = URLPropertyEditor.make(new Property(this, index, "Open Sound URL").allowSetNull(), "wav;mid;ram;ra;rm"); + } else if (mode == 1) { + ret = this.openSound; + } else if (mode == 2) { + this.openSound = (URL)value; + } + break; + case 5: + if (mode == 0) { + ret = URLPropertyEditor.make(new Property(this, index, "Close Sound URL").allowSetNull(), "wav;mid;ram;ra;rm"); + } else if (mode == 1) { + ret = this.closeSound; + } else if (mode == 2) { + this.closeSound = (URL)value; + } + break; + default: + ret = super.properties(index, offset + 6, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + this.setFrame(0); + s.saveVersion(0, classCookie); + int f = this.flags; + this.flags |= 262144; + super.saveState(s); + this.flags = f; + s.saveString(this.frameList); + s.saveFloat(this.perFrame); + s.save(this.start); + s.save(this.end); + URL.save(s, this.openSound); + URL.save(s, this.closeSound); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this.frameList = r.restoreString(); + this.perFrame = r.restoreFloat(); + this.start = (Point3)r.restore(); + this.end = (Point3)r.restore(); + this.openSound = URL.restore(r); + this.closeSound = URL.restore(r); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/Animation.java b/NET/worlds/scape/Animation.java new file mode 100644 index 0000000..1f27085 --- /dev/null +++ b/NET/worlds/scape/Animation.java @@ -0,0 +1,285 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.network.URL; +import java.io.IOException; +import java.net.MalformedURLException; +import java.text.MessageFormat; +import java.util.Date; + +class Animation extends TriggeredSwitchableBehavior implements FrameHandler, Persister, MouseDownHandler, BumpHandler { + long startFrameTime; + protected float cycleTime; + protected String frameList; + protected int cycles; + protected int cycleNo = 0; + protected String[] frameListArray; + protected Material[] frameMaterialArray; + protected int frameListCount; + protected int currentFrameNo; + protected boolean animationEnd = true; + + public Animation() { + this.cycleTime = 1000.0F; + this.frameList = new String(""); + this.trigger = new String("none"); + this.externalTriggerTag = new String(""); + this.cycles = 0; + this.frameListArray = new String[200]; + this.frameMaterialArray = new Material[200]; + this.frameListCount = 0; + this.startAnimation(); + } + + @Override + public void ExternalTrigger(Trigger trigger_source, int sequence_no, int event_no) { + this.trigger_source = trigger_source; + this.sequence_no = sequence_no; + this.event_no = event_no; + this.startAnimation(); + } + + public void startAnimation() { + Date timer = new Date(); + this.startFrameTime = timer.getTime(); + this.cycleNo = 0; + this.currentFrameNo = 0; + this.animationEnd = false; + } + + public float getCycleTime() { + return this.cycleTime; + } + + public void setCycleTime(float t) { + this.cycleTime = t; + } + + public int getNextFrameNo() { + Date timer = new Date(); + int nextFrameNo = 0; + if (this.frameListCount > 0) { + nextFrameNo = (int)(this.frameListCount * ((float)(timer.getTime() - this.startFrameTime) % this.cycleTime) / (this.cycleTime + 1.0F) + 1.0F); + if (this.currentFrameNo > nextFrameNo) { + this.cycleNo++; + } + } + + return nextFrameNo; + } + + public void preprocessFrameList(String frameList) { + int currentIndex = 1; + int currentSeparator = 0; + int nextSeparator = 0; + int lastSeparator = frameList.lastIndexOf(" "); + if (lastSeparator != -1 || frameList.length() != 0) { + if (lastSeparator == -1) { + this.frameListArray[currentIndex] = frameList; + } else { + nextSeparator = frameList.indexOf(" "); + this.frameListArray[currentIndex] = frameList.substring(0, nextSeparator); + currentIndex++; + + while (nextSeparator != lastSeparator) { + currentSeparator = nextSeparator; + nextSeparator = frameList.indexOf(" ", nextSeparator + 1); + this.frameListArray[currentIndex] = frameList.substring(currentSeparator + 1, nextSeparator); + currentIndex++; + } + + this.frameListArray[currentIndex] = frameList.substring(nextSeparator + 1); + this.frameListCount = currentIndex; + } + } + + for (int var11 = 1; var11 <= this.frameListCount; var11++) { + String s = this.frameListArray[var11]; + + URL url; + try { + url = new URL(this, s); + } catch (MalformedURLException var9) { + url = URL.make("error:\"" + s + '"'); + } + + this.frameMaterialArray[var11] = new Material(url); + } + } + + @Override + public boolean handle(FrameEvent e) { + if (this.enabled && e.receiver instanceof Rect) { + int nextFrameNo = this.getNextFrameNo(); + if (this.cycleNo >= this.cycles && this.cycles != 0) { + if (this.currentFrameNo != this.frameListCount) { + Rect Wall = (Rect)e.receiver; + Wall.setMaterial(this.frameMaterialArray[this.frameListCount]); + this.currentFrameNo = this.frameListCount; + } + } else if (nextFrameNo > 0 && nextFrameNo != this.currentFrameNo) { + this.currentFrameNo = nextFrameNo; + Rect Wall = (Rect)e.receiver; + Wall.setMaterial(this.frameMaterialArray[this.currentFrameNo]); + } + + if (this.cycleNo >= this.cycles && this.cycles != 0 && !this.animationEnd) { + this.animationEnd = true; + if (this.trigger_source != null) { + this.trigger_source.registerFinishedTriggerTag(this.sequence_no, this.event_no); + } + } + } + + return true; + } + + @Override + public boolean handle(MouseDownEvent e) { + if (this.enabled && this.trigger.equals("click")) { + this.startAnimation(); + } + + return true; + } + + @Override + public boolean handle(BumpEventTemp e) { + if (this.enabled && this.trigger.equals("bump")) { + this.startAnimation(); + } + + return true; + } + + @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 = new ClassProperty(this, index, "Animation"); + } + break; + case 1: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Cycle Time")); + } else if (mode == 1) { + ret = new Float(this.cycleTime); + } else if (mode == 2) { + this.cycleTime = (Float)value; + } + break; + case 2: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Cycles")); + } else if (mode == 1) { + ret = new Integer(this.cycles); + } else if (mode == 2) { + this.cycles = (Integer)value; + } + break; + case 3: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Trigger")); + } else if (mode == 1) { + ret = new String(this.trigger); + } else if (mode == 2) { + this.trigger = ((String)value).toString().trim(); + if (this.trigger.equals("external")) { + Trigger.TriggeredSwitchableBehaviorList[Trigger.TriggeredSwitchableBehaviorListCount] = this; + Trigger.TriggeredSwitchableBehaviorListCount++; + } + } + break; + case 4: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "External Trigger Tag")); + } else if (mode == 1) { + ret = new String(this.externalTriggerTag); + } else if (mode == 2) { + this.externalTriggerTag = ((String)value).toString().trim(); + } + break; + case 5: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Frame List")); + } else if (mode == 1) { + ret = new String(this.frameList); + } else if (mode == 2) { + this.frameList = ((String)value).toString().trim().toLowerCase(); + this.preprocessFrameList(this.frameList); + } + break; + default: + ret = super.properties(index, offset + 6, mode, value); + } + + if (mode == 2 && this.trigger.equals("none")) { + this.startAnimation(); + } + + return ret; + } + + @Override + public String toString() { + return "Animation: cycleTime " + + this.cycleTime + + ", cycles " + + this.cycles + + ", enabled " + + this.enabled + + ", trigger " + + this.trigger + + ", externalTriggerTag " + + this.externalTriggerTag + + ", frameList " + + this.frameList; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveFloat(this.cycleTime); + s.saveInt(this.cycles); + s.saveString(this.trigger); + s.saveString(this.externalTriggerTag); + s.saveString(this.frameList); + } + + @Override + public void restoreState(Restorer r) throws IOException { + this.cycleTime = r.restoreFloat(); + this.cycles = r.restoreInt(); + this.trigger = r.restoreString(); + if (this.trigger.equals("external")) { + Trigger.TriggeredSwitchableBehaviorList[Trigger.TriggeredSwitchableBehaviorListCount] = this; + Trigger.TriggeredSwitchableBehaviorListCount++; + } + + this.externalTriggerTag = r.restoreString(); + if (!this.trigger.equals("none")) { + this.cycleNo = this.cycles; + } else { + this.startAnimation(); + } + + this.frameList = r.restoreString(); + this.preprocessFrameList(this.frameList); + } + + @Override + public void postRestore(int version) { + String name = this.getName(); + String arg1 = name == null ? "<null>" : name; + SuperRoot owner = this.getOwner(); + String oname = ""; + if (owner != null) { + oname = owner.getName(); + } + + String arg2 = oname == null ? "<null>" : oname; + Object[] arguments = new Object[]{new String(arg1), new String(arg2)}; + Console.println(MessageFormat.format(Console.message("Animation-obs"), arguments)); + } +} diff --git a/NET/worlds/scape/Attribute.java b/NET/worlds/scape/Attribute.java new file mode 100644 index 0000000..12d2304 --- /dev/null +++ b/NET/worlds/scape/Attribute.java @@ -0,0 +1,383 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.network.InfiniteWaitException; +import NET.worlds.network.NetworkObject; +import NET.worlds.network.ObjID; +import NET.worlds.network.PacketTooLargeException; +import NET.worlds.network.WorldServer; +import NET.worlds.network.propReqCmd; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Vector; + +public abstract class Attribute extends Sensor { + public int _shorthandVersion = this.getMaxShorthandVersion(); + int _attrID; + byte[] _serverData; + boolean _waitingForFeedback; + byte[] _outgoing; + boolean loaded; + Vector<LoadedAttribute> callbacks; + private Attribute _to; + private int _storedForwardAttrID = -1; + protected int _propertyFlags = 208; + protected int _accessFlags = 0; + private static Object classCookie = new Object(); + + public int getMaxShorthandVersion() { + return 0; + } + + public void load(LoadedAttribute callback) { + if (this.loaded) { + if (callback != null) { + callback.loadedAttribute(this, null); + } + } else { + Sharer s = (Sharer)this.getOwner(); + if (s != null && s.isShared()) { + if (callback != null) { + if (this.callbacks == null) { + this.callbacks = new Vector<LoadedAttribute>(); + } + + this.callbacks.addElement(callback); + } + + Attribute f = this.getForwardAttribute(); + if (f != null) { + f.load(null); + } else { + assert (s.getMode() & 1) == 0; + + Object served = s.getOwner(); + + try { + WorldServer servr; + String id; + if (served instanceof Room) { + servr = ((Room)served).getServer(); + id = ((Room)served).getNetworkRoom().getLongID(); + } else { + servr = ((NetworkObject)served).getServer(); + id = ((NetworkObject)served).getLongID(); + } + + servr.sendNetworkMsg(new propReqCmd(new ObjID(id), this._attrID)); + } catch (InfiniteWaitException var7) { + } catch (PacketTooLargeException var8) { + assert false; + } + } + } else { + if (callback != null) { + callback.loadedAttribute(this, "unshared"); + } + } + } + } + + public int getAttrID() { + return this._attrID; + } + + public Attribute(int attrID) { + this._attrID = attrID; + } + + public Attribute() { + } + + public void setAttrID(int newID) { + this.flushBuffers(); + Sharer sharer = (Sharer)this.getOwner(); + if (sharer == null) { + this._attrID = newID; + } else { + sharer.resetAttributeID(this, newID); + } + } + + private void flushBuffers() { + this._serverData = null; + this._waitingForFeedback = false; + this._outgoing = null; + } + + public int getForwardAttrID() { + return this._to != null ? this._to._attrID : this._storedForwardAttrID; + } + + public void unforward() { + if (this._to != null) { + this._storedForwardAttrID = this._to.getAttrID(); + Sharer s = (Sharer)this._to.getOwner(); + if (s != null) { + s.removeAttribute(this._to); + } + } + + this.flushBuffers(); + } + + public boolean isForwarded() { + return this._to != null; + } + + public Attribute getForwardAttribute() { + return this._to; + } + + public void setForwardAttrID(int newID) { + if (this._to != null) { + this._to.setAttrID(newID); + } else { + this._storedForwardAttrID = newID; + } + } + + public void noteChange() { + Sharer sharer = (Sharer)this.getOwner(); + if (sharer != null) { + sharer.noteChange(this, this.actions.size() > 0); + } + } + + public void addForwarding() { + if (!this.isForwarded()) { + Sharer s = (Sharer)this.getOwner(); + + assert ((WObject)s.getOwner()).getSharerMode() == 3; + + WObject terminal = ((WObject)s.getOwner()).getServed(); + if (terminal != null) { + if (this.getOwner().getOwner() != terminal) { + ForwardAttribute fwd = new ForwardAttribute(this, this._storedForwardAttrID); + terminal.addShareableAttribute(fwd); + this._to = fwd; + } + } + } + } + + public abstract void generateNetData(DataOutputStream var1) throws IOException; + + public abstract void setFromNetData(DataInputStream var1, int var2) throws IOException; + + @Override + public void detach() { + super.detach(); + this.unforward(); + } + + public int getFlags() { + return this._propertyFlags; + } + + public void setFlag(int flag, boolean onoff) { + if (onoff) { + this._propertyFlags |= flag; + } else { + this._propertyFlags &= ~flag; + } + } + + public void setFinger(boolean onoff) { + this.setFlag(32, onoff); + } + + public boolean getFinger() { + return (this.getFlags() & 32) != 0; + } + + public void setAutoUpdate(boolean onoff) { + this.setFlag(64, onoff); + } + + public boolean getAutoUpdate() { + return (this.getFlags() & 64) != 0; + } + + public void setDatabase(boolean onoff) { + this.setFlag(128, onoff); + } + + public boolean getDatabase() { + return (this.getFlags() & 128) != 0; + } + + public void setBinary(boolean onoff) { + this.setFlag(16, onoff); + } + + public boolean getBinary() { + return (this.getFlags() & 16) != 0; + } + + public int getAccessFlags() { + return this._accessFlags; + } + + public void setAccessFlags(int flags) { + this._accessFlags = flags; + } + + @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 = IntegerPropertyEditor.make(new Property(this, index, "Attribute ID")); + } else if (mode == 1) { + ret = new Integer(this._attrID); + } else if (mode == 2) { + int id = (Integer)value; + if (id >= 0 && id <= 255) { + this.setAttrID(id); + } else { + Console.println(Console.message("Attribute-id")); + } + } + break; + case 1: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Fingerable"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.getFinger()); + } else if (mode == 2) { + this.setFinger((Boolean)value); + } + break; + case 2: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Auto Update"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.getAutoUpdate()); + } else if (mode == 2) { + this.setAutoUpdate((Boolean)value); + } + break; + case 3: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Store in Database"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.getDatabase()); + } else if (mode == 2) { + this.setDatabase((Boolean)value); + } + break; + case 4: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Shorthand version")); + } else if (mode == 1) { + ret = new Integer(this._shorthandVersion); + } else if (mode == 2) { + int id = (Integer)value; + if (id >= 0 && id <= this.getMaxShorthandVersion()) { + this._shorthandVersion = id; + } else { + Console.println(Console.message("Shorthand-version") + " " + this.getMaxShorthandVersion()); + } + } + break; + case 5: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Forwarder attrID")); + } else if (mode == 1) { + ret = new Integer(this.getForwardAttrID()); + } else if (mode == 2) { + int id = (Integer)value; + if (id >= 0 && id <= 255) { + this.setForwardAttrID(id); + } else { + Console.println(Console.message("Attribute-id")); + } + } + break; + case 6: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Load Now"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(false); + } else if (mode == 2 && (Boolean)value) { + this.load(null); + } + break; + default: + ret = super.properties(index, offset + 7, mode, value); + } + + return ret; + } + + @Override + public Object propertyParent() { + return this.getOwner().getOwner(); + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(5, classCookie); + super.saveState(s); + s.saveInt(this._attrID); + s.saveInt(this.getForwardAttrID()); + s.saveInt(this._propertyFlags); + s.saveInt(this._shorthandVersion); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + this._attrID = r.restoreInt(); + if (r.restoreBoolean()) { + this._storedForwardAttrID = r.restoreInt(); + } else { + r.restoreInt(); + } + break; + case 1: + this._attrID = r.restoreInt(); + this._storedForwardAttrID = r.restoreInt(); + break; + case 2: + this._attrID = r.restoreInt(); + this._storedForwardAttrID = r.restoreInt(); + this._propertyFlags = r.restoreInt(); + break; + case 3: + this.restoreStateSuperRoot(r); + this._attrID = r.restoreInt(); + this._storedForwardAttrID = r.restoreInt(); + this._propertyFlags = r.restoreInt(); + break; + case 4: + this.restoreStateSuperRoot(r); + this._attrID = r.restoreInt(); + this._storedForwardAttrID = r.restoreInt(); + this._propertyFlags = r.restoreInt(); + this._shorthandVersion = r.restoreInt(); + break; + case 5: + super.restoreState(r); + this._attrID = r.restoreInt(); + this._storedForwardAttrID = r.restoreInt(); + this._propertyFlags = r.restoreInt(); + this._shorthandVersion = r.restoreInt(); + break; + default: + throw new TooNewException(); + } + } + + @Override + public String toString() { + return this.isForwarded() ? super.toString() + "[forwarded to " + this._to.getName() + "]" : super.toString(); + } + + public void releaseAuxilaryData() { + } +} diff --git a/NET/worlds/scape/AudibilityFilter.java b/NET/worlds/scape/AudibilityFilter.java new file mode 100644 index 0000000..78b6331 --- /dev/null +++ b/NET/worlds/scape/AudibilityFilter.java @@ -0,0 +1,292 @@ +package NET.worlds.scape; + +import java.util.Vector; + +public class AudibilityFilter { + WObject owner; + Room listenerRoom; + AudibleParams ownerPos; + AudibleParams localPos; + Vector roomList = new Vector(); + int maxHopcount = 1; + private boolean listenerOn = false; + private boolean emitterOn = false; + Sound sound; + Vector breadthQueue = null; + int breadthLevel; + int breadthNextLevelIndex; + int breadthIndex; + + public AudibilityFilter(Sound s, WObject o, int maxHops) { + this.debugOut(9, "AudibilityFilter::AudibilityFilter in"); + this.sound = s; + this.owner = o; + this.maxHopcount = maxHops; + if (this.owner.getRoom() != null) { + this.floodFillRooms(); + this.updateListenerState(); + } + } + + void fillOwnerEntry() { + this.debugOut(9, "aud fillOwnerEntry called " + this.sound.getURL()); + this.ownerPos = new AudibleParams(); + this.ownerPos.room = this.owner.getRoom(); + this.ownerPos.position = new Point3(this.owner.getPosition()); + this.ownerPos.transform = Transform.make(); + this.ownerPos.hopcount = 0; + this.roomList.addElement(this.ownerPos); + } + + private void debugOut(int level, String str) { + if (Sound.debugLevel > level) { + System.out.println(str); + } + } + + public AudibilityFilter(Sound s, WObject o, int maxHops, float stopDistance) { + this(s, o, maxHops); + } + + public AudibilityFilter() { + } + + public void setHopcount(int i) { + this.debugOut(9, "AudibilityFilter::setHopcount"); + this.maxHopcount = i; + this.moveEmitter(); + } + + public int getHopcount() { + this.debugOut(9, "AudibilityFilter::getHopcount"); + return this.maxHopcount; + } + + void setEmitterOn(boolean flag) { + this.debugOut(9, "setting emitterOn to " + flag); + this.emitterOn = flag; + } + + void updateListenerState() { + assert this.sound != null; + + this.debugOut(6, "updateListenerState " + this.sound.getURL()); + Room newRoom = Pilot.getActiveRoom(); + if (this.listenerRoom != newRoom) { + this.listenerRoom = newRoom; + AudibleParams roomElement = this.getRoomElement(newRoom); + if (roomElement == null) { + this.listenerOn = false; + } else { + this.localPos = roomElement; + this.adjustEmitterLocation(); + if (!this.listenerOn) { + this.listenerOn = true; + if (this.emitterOn) { + RunningActionHandler.trigger(this.sound, this.owner.getWorld(), null); + } + } + } + } + } + + private void updateEmitterState() { + if (this.isEmitterMoved()) { + this.adjustEmitterLocation(); + } + } + + public boolean isAudible() { + this.updateListenerState(); + this.updateEmitterState(); + this.debugOut(6, "emitterOn " + this.emitterOn + " listenerOn " + this.listenerOn); + return this.emitterOn && this.listenerOn; + } + + void moveEmitter() { + this.debugOut(9, "moveEmitter"); + this.removeRooms(); + this.floodFillRooms(); + this.updateListenerState(); + } + + private void removeRooms() { + this.debugOut(9, "removeRooms for sound " + this.sound.getURL()); + + for (int roomIndex = this.roomList.size() - 1; roomIndex >= 0; roomIndex--) { + AudibleParams ap = (AudibleParams)this.roomList.elementAt(roomIndex); + Room room = ap.room; + room.removeAFilter(this); + this.debugOut(9, "removing room " + room.getName() + " from roomList"); + this.roomList.removeElementAt(roomIndex); + } + } + + private void floodFillRooms() { + this.debugOut(9, "floodFillRooms " + this.sound.getURL() + " count:" + this.maxHopcount); + + assert this.roomList != null; + + assert this.roomList.size() == 0; + + assert this.owner != null; + + if (this.owner != null && this.owner.getRoom() != null) { + this.breadthSearchStart(); + this.fillOwnerEntry(); + this.owner.getRoom().addAFilter(this); + this.breadthAddChildren(this.owner.getRoom()); + + for (Portal portal = this.breadthNextElement(); portal != null && this.breadthCurrentLevel() < this.maxHopcount; portal = this.breadthNextElement()) { + this.debugOut(6, " trying to add " + portal.farSideRoom().getName()); + if (this.getRoomElement(portal.farSideRoom()) == null) { + this.addRoomListEntry(portal, this.breadthCurrentLevel() + 1); + this.breadthAddChildren(portal.farSideRoom()); + } + } + + this.breadthSearchEnd(); + } + } + + private void breadthSearchStart() { + this.breadthQueue = new Vector(); + this.breadthLevel = 0; + this.breadthNextLevelIndex = 0; + this.breadthIndex = 0; + } + + private Portal breadthNextElement() { + if (this.breadthQueue != null && this.breadthIndex < this.breadthQueue.size()) { + if (this.breadthIndex == this.breadthNextLevelIndex) { + this.breadthLevel++; + this.breadthNextLevelIndex = this.breadthQueue.size(); + } + + Portal portal = (Portal)this.breadthQueue.elementAt(this.breadthIndex); + return (Portal)this.breadthQueue.elementAt(this.breadthIndex++); + } else { + return null; + } + } + + private void breadthAddChildren(Room room) { + assert this.breadthQueue != null; + + Vector next = room.getOutgoingPortals(); + + for (int j = 0; j < next.size(); j++) { + Portal portal = (Portal)next.elementAt(j); + Room r = portal.farSideRoom(); + if (r != null && r.isActive()) { + this.breadthQueue.addElement(portal); + } + } + } + + private int breadthCurrentLevel() { + return this.breadthLevel; + } + + private void breadthSearchEnd() { + this.breadthQueue = null; + } + + private void addRoomListEntry(Portal portal, int hopCount) { + this.debugOut(9, "addRoomListEntry " + portal.farSideRoom().getName()); + AudibleParams ap = this.getRoomElement(portal.getRoom()); + + assert ap != null; + + this.fillNewAP(ap, portal, hopCount); + portal.farSideRoom().addAFilter(this); + } + + AudibleParams getRoomElement(Room room) { + this.debugOut(6, "getRoomElement size " + this.roomList.size() + " room " + room.getName()); + if (room == null) { + return null; + } else { + for (int index = 0; index < this.roomList.size(); index++) { + Room newRoom = ((AudibleParams)this.roomList.elementAt(index)).room; + this.debugOut(9, " comparing to " + newRoom.getName()); + if (((AudibleParams)this.roomList.elementAt(index)).room == room) { + return (AudibleParams)this.roomList.elementAt(index); + } + } + + return null; + } + } + + void fillNewAP(AudibleParams connectingRoom, Portal bestPortal, int bestCount) { + this.debugOut(4, "AudibilityFilter::fillNewAP for room " + bestPortal.farSideRoom().getName()); + AudibleParams newAP = new AudibleParams(); + newAP.room = bestPortal.farSideRoom(); + newAP.hopcount = bestCount; + Transform xform; + if (bestPortal.p2pXform() != null) { + xform = bestPortal.p2pXform().getTransform(); + } else { + xform = Transform.make(); + this.debugOut(4, " xform incomplete"); + } + + newAP.transform = connectingRoom.transform.getTransform(); + newAP.transform.post(xform); + xform.recycle(); + newAP.position = new Point3(connectingRoom.position); + newAP.position.times(newAP.transform); + this.roomList.addElement(newAP); + } + + public boolean isEmitterMoved() { + assert this.ownerPos != null; + + if (!this.ownerPos.position.sameValue(this.owner.getPosition())) { + this.ownerPos.position = new Point3(this.owner.getPosition()); + return true; + } else { + return this.ownerPos.room != this.owner.getRoom(); + } + } + + public void adjustEmitterLocation() { + this.debugOut(4, "AudibilityFilter::adjustEmitterLocation"); + if (this.ownerPos.room != this.owner.getRoom()) { + this.debugOut(9, " moveEmitter because emitter changed rooms"); + this.moveEmitter(); + } else { + this.localPos.position = new Point3(this.ownerPos.position); + this.localPos.position.times(this.localPos.transform); + } + } + + public void getListenerPosition(Point3Temp pos, Point3Temp up, Point3Temp forward) { + this.debugOut(9, "getListenerPosition"); + Pilot pilot = Pilot.getActive(); + Transform t = pilot.getObjectToWorldMatrix(); + up.copy(Point3Temp.make(0.0F, 0.0F, 1.0F).vectorTimes(t).normalize()); + forward.copy(Point3Temp.make(0.0F, 1.0F, 0.0F).vectorTimes(t).normalize()); + pos.copy(pilot.getPosition()); + t.recycle(); + } + + public void getEmitterPosition(Point3Temp pos) { + this.debugOut(9, "getEmitterPosition"); + + assert this.localPos != null; + + pos.x = this.localPos.position.x; + pos.y = this.localPos.position.y; + pos.z = this.localPos.position.z; + } + + public float getEmitterVolume() { + this.debugOut(9, "getEmitterVolume"); + + assert this.localPos != null; + + return 1.0F; + } +} diff --git a/NET/worlds/scape/AudibleParams.java b/NET/worlds/scape/AudibleParams.java new file mode 100644 index 0000000..04e24cf --- /dev/null +++ b/NET/worlds/scape/AudibleParams.java @@ -0,0 +1,8 @@ +package NET.worlds.scape; + +class AudibleParams { + public Room room; + public Point3 position; + public Transform transform; + public int hopcount; +} diff --git a/NET/worlds/scape/BGLoaded.java b/NET/worlds/scape/BGLoaded.java new file mode 100644 index 0000000..ba1671a --- /dev/null +++ b/NET/worlds/scape/BGLoaded.java @@ -0,0 +1,11 @@ +package NET.worlds.scape; + +import NET.worlds.network.URL; + +public interface BGLoaded { + Object asyncBackgroundLoad(String var1, URL var2); + + boolean syncBackgroundLoad(Object var1, URL var2); + + Room getBackgroundLoadRoom(); +} diff --git a/NET/worlds/scape/BackgroundLoader.java b/NET/worlds/scape/BackgroundLoader.java new file mode 100644 index 0000000..8f337a0 --- /dev/null +++ b/NET/worlds/scape/BackgroundLoader.java @@ -0,0 +1,95 @@ +package NET.worlds.scape; + +import NET.worlds.console.Main; +import NET.worlds.console.MainCallback; +import NET.worlds.network.URL; +import java.util.Vector; + +public class BackgroundLoader implements MainCallback, Runnable { + private static BackgroundLoader bg = new BackgroundLoader(); + private BackgroundLoaderQueue readQueue = new BackgroundLoaderQueue(); + private BackgroundLoaderQueue asyncLoadQueue = new BackgroundLoaderQueue(); + private Vector syncLoadQueue = new Vector(); + private Thread asyncLoaderThread; + int nextSync = 0; + + public static void get(BGLoaded loader, String remoteName) { + get(loader, URL.make(remoteName), false); + } + + public static void get(BGLoaded loader, URL remoteName) { + get(loader, remoteName, false); + } + + public static void get(BGLoaded loader, URL remoteName, boolean highPri) { + new BackgroundLoaderElement(loader, remoteName, highPri); + } + + static void activeRoomChanged(Room room) { + bg.asyncLoadQueue.activeRoomChanged(room); + } + + static void asyncLoad(BackgroundLoaderElement ele) { + bg.asyncLoadQueue.add(ele); + } + + static void syncLoad(BackgroundLoaderElement ele) { + bg.syncLoadQueue.addElement(ele); + } + + private BackgroundLoader() { + this.asyncLoaderThread = new Thread(this); + this.asyncLoaderThread.setDaemon(true); + this.asyncLoaderThread.start(); + Main.register(this); + } + + @Override + public void run() { + if ($assertionsDisabled || Thread.currentThread() == this.asyncLoaderThread) { + while (true) { + BackgroundLoaderElement ele = this.asyncLoadQueue.getItem(); + ele.asyncLoad(); + synchronized (this) { + this.syncLoadQueue.addElement(ele); + + while (this.syncLoadQueue.size() > 0) { + try { + this.wait(); + } catch (InterruptedException var4) { + } + + if (this.asyncLoadQueue.hasHighPriorityItems()) { + break; + } + } + } + } + } + + throw new AssertionError(); + } + + @Override + public synchronized void mainCallback() { + if (this.syncLoadQueue.size() != 0) { + if (this.nextSync >= this.syncLoadQueue.size()) { + this.nextSync = 0; + } + + BackgroundLoaderElement ele = (BackgroundLoaderElement)this.syncLoadQueue.elementAt(this.nextSync); + if (!ele.syncLoad()) { + this.syncLoadQueue.removeElementAt(this.nextSync); + if (this.syncLoadQueue.size() == 0) { + this.notify(); + } + } else { + if (this.asyncLoadQueue.hasHighPriorityItems()) { + this.notify(); + } + + this.nextSync++; + } + } + } +} diff --git a/NET/worlds/scape/BackgroundLoaderElement.java b/NET/worlds/scape/BackgroundLoaderElement.java new file mode 100644 index 0000000..aba150a --- /dev/null +++ b/NET/worlds/scape/BackgroundLoaderElement.java @@ -0,0 +1,87 @@ +package NET.worlds.scape; + +import NET.worlds.console.Main; +import NET.worlds.core.IniFile; +import NET.worlds.network.Cache; +import NET.worlds.network.CacheFile; +import NET.worlds.network.URL; +import java.util.Observable; +import java.util.Observer; + +class BackgroundLoaderElement implements Observer { + private BGLoaded object; + private Object arg; + private URL url; + private Room room; + private boolean inAllRooms; + private CacheFile rfile; + private static boolean immedLoadLocals = IniFile.gamma().getIniInt("BackgroundLoadLocalFiles", 0) == 0; + + BackgroundLoaderElement(BGLoaded object, URL url, boolean inAllRooms) { + boolean isMain = Main.isMainThread(); + this.object = object; + this.url = url; + if (inAllRooms) { + this.inAllRooms = true; + } else { + this.getRoom(isMain); + } + + this.read(isMain); + } + + @Override + public void update(Observable o, Object url) { + BackgroundLoader.asyncLoad(this); + } + + private void read(boolean isMain) { + this.rfile = this.url != null && this.url.isRemote() ? Cache.getFile(this.url) : null; + if ((this.rfile == null || this.rfile.done()) && immedLoadLocals) { + this.asyncLoad(); + if (!isMain || this.syncLoad()) { + BackgroundLoader.syncLoad(this); + } + } else if (this.rfile == null) { + BackgroundLoader.asyncLoad(this); + } else { + this.rfile.callWhenLoaded(this); + } + } + + void asyncLoad() { + String name; + if (this.rfile == null) { + name = this.url.unalias(); + } else { + name = this.rfile.getLocalName(); + } + + this.arg = this.object.asyncBackgroundLoad(name, this.url); + } + + boolean syncLoad() { + if (this.object.syncBackgroundLoad(this.arg, this.url)) { + return true; + } else { + if (this.rfile != null) { + this.rfile.finalize(); + this.rfile = null; + } + + return false; + } + } + + boolean inAllRooms() { + return this.inAllRooms; + } + + Room getRoom(boolean isMainThread) { + if (this.room == null && !this.inAllRooms && isMainThread) { + this.room = this.object.getBackgroundLoadRoom(); + } + + return this.room; + } +} diff --git a/NET/worlds/scape/BackgroundLoaderQueue.java b/NET/worlds/scape/BackgroundLoaderQueue.java new file mode 100644 index 0000000..97eacd9 --- /dev/null +++ b/NET/worlds/scape/BackgroundLoaderQueue.java @@ -0,0 +1,158 @@ +package NET.worlds.scape; + +import NET.worlds.console.Main; +import NET.worlds.console.MainCallback; +import java.util.Enumeration; +import java.util.Hashtable; + +class BackgroundLoaderQueue implements MainCallback { + private Room activeRoom; + private int itemsInQueue; + private BackgroundLoaderVector inAllRooms = new BackgroundLoaderVector(); + private BackgroundLoaderVector inUnknownRoom = new BackgroundLoaderVector(); + private Hashtable rooms = new Hashtable(); + private boolean mainRan; + + synchronized void activeRoomChanged(Room room) { + this.activeRoom = room; + } + + public boolean hasHighPriorityItems() { + return this.inAllRooms.size() > 0; + } + + synchronized void add(BackgroundLoaderElement e) { + if (!this.addHelper(e, false)) { + if (e.inAllRooms()) { + this.inAllRooms.insertElementAt(e, 0); + } else { + this.inUnknownRoom.addElement(e); + } + } + + this.itemsInQueue++; + this.notify(); + } + + private boolean addHelper(BackgroundLoaderElement e, boolean isMainThread) { + Room r = e.getRoom(isMainThread); + if (r != null && r.isActive()) { + BackgroundLoaderVector v = (BackgroundLoaderVector)this.rooms.get(r); + if (v == null) { + this.rooms.put(r, v = new BackgroundLoaderVector()); + } + + v.addElement(e); + return true; + } else { + return false; + } + } + + private BackgroundLoaderElement getHelper(Room r) { + BackgroundLoaderElement e = null; + BackgroundLoaderVector v = (BackgroundLoaderVector)this.rooms.get(r); + if (v != null) { + e = v.removeFirst(); + if (v.isEmpty()) { + this.rooms.remove(r); + } + } + + return e; + } + + synchronized BackgroundLoaderElement getItem() { + BackgroundLoaderElement e = null; + + while (true) { + while (this.itemsInQueue == 0) { + try { + this.wait(); + } catch (InterruptedException var3) { + } + } + + if (this.inAllRooms.size() != 0) { + e = this.inAllRooms.removeFirst(); + break; + } + + if (this.activeRoom != null && (e = this.getHelper(this.activeRoom)) != null) { + break; + } + + this.mainRan = false; + Main.register(this); + + while (!this.mainRan) { + try { + this.wait(); + } catch (InterruptedException var4) { + } + } + + if (this.inAllRooms.size() == 0 && (this.activeRoom == null || this.rooms.get(this.activeRoom) == null)) { + if ((e = this.getClosestObject()) == null) { + if (this.inUnknownRoom.size() != 0) { + e = this.inUnknownRoom.removeFirst(); + } else { + Enumeration k = this.rooms.keys(); + + assert k.hasMoreElements(); + + e = this.getHelper((Room)k.nextElement()); + + assert e != null; + } + } + break; + } + } + + assert e != null; + + this.itemsInQueue--; + + assert this.itemsInQueue >= 0; + + return e; + } + + private BackgroundLoaderElement getClosestObject() { + synchronized (Pilot.visibleRooms) { + float minDist = Float.MAX_VALUE; + int minEle = -1; + int count = Pilot.visibleRoomInfo.size(); + + for (int i = 0; i < count; i++) { + RoomSubscribeInfo s = Pilot.visibleRoomInfo.elementAt(i); + if (s.d < minDist && this.rooms.get(Pilot.visibleRooms.elementAt(i)) != null) { + minDist = s.d; + minEle = i; + } + } + + return minEle == -1 ? null : this.getHelper(Pilot.visibleRooms.elementAt(minEle)); + } + } + + @Override + public synchronized void mainCallback() { + int count = this.inUnknownRoom.size(); + int i = 0; + + while (count-- != 0) { + BackgroundLoaderElement e = (BackgroundLoaderElement)this.inUnknownRoom.get(i); + if (this.addHelper(e, true)) { + this.inUnknownRoom.removeElementAt(i); + } else { + i++; + } + } + + this.mainRan = true; + Main.unregister(this); + this.notify(); + } +} diff --git a/NET/worlds/scape/BackgroundLoaderVector.java b/NET/worlds/scape/BackgroundLoaderVector.java new file mode 100644 index 0000000..91ae254 --- /dev/null +++ b/NET/worlds/scape/BackgroundLoaderVector.java @@ -0,0 +1,16 @@ +package NET.worlds.scape; + +import java.util.Vector; + +class BackgroundLoaderVector extends Vector { + BackgroundLoaderElement removeFirst() { + BackgroundLoaderElement ret = (BackgroundLoaderElement)this.elementAt(0); + this.removeElementAt(0); + return ret; + } + + @Override + public synchronized Object get(int i) { + return this.elementAt(i); + } +} diff --git a/NET/worlds/scape/BadFormatException.java b/NET/worlds/scape/BadFormatException.java new file mode 100644 index 0000000..013de24 --- /dev/null +++ b/NET/worlds/scape/BadFormatException.java @@ -0,0 +1,10 @@ +package NET.worlds.scape; + +public class BadFormatException extends Exception { + public BadFormatException() { + } + + public BadFormatException(String s) { + super(s); + } +} diff --git a/NET/worlds/scape/Billboard.java b/NET/worlds/scape/Billboard.java new file mode 100644 index 0000000..7c30a3b --- /dev/null +++ b/NET/worlds/scape/Billboard.java @@ -0,0 +1,428 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.DefaultConsole; +import NET.worlds.console.NoWebControlException; +import NET.worlds.console.WebControl; +import NET.worlds.console.WebControlFactory; +import NET.worlds.console.WebControlImp; +import NET.worlds.console.WebControlListener; +import NET.worlds.core.IniFile; +import NET.worlds.network.URL; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Billboard extends Attribute implements WebControlListener { + WebControlImp _wci = null; + TextureSurface _surface; + Texture[] _textures; + Material _material = null; + String _textureURL = "$SCRIPTSERVERgetad.pl?u=$USERNAME"; + String _adURL = "http://www.worlds.com/"; + String _defTextureURL = IniFile.override().getIniString("defaultAd", "adworlds.cmp"); + int _xPercent = 100; + int _yPercent = 100; + int _xSurface = 468; + int _ySurface = 60; + boolean _hasToolbar = true; + boolean _isFixed = false; + int _rows = 1; + int _refresh = 5; + boolean _passClicks = true; + boolean _isAdBanner = true; + boolean _retryURL = false; + int frameCnt = -1; + private static Object classCookie = new Object(); + + public Billboard(int attrID) { + super(attrID); + } + + public Billboard() { + } + + @Override + public final void noteChange() { + } + + @Override + protected void noteAddingTo(SuperRoot owner) { + Rect s = (Rect)((Sharer)owner).getOwner(); + s._billboardAttribute = this; + this.assignMaterial(s); + } + + private void assignMaterial(Rect s) { + int xTex = this._xSurface / 128; + if (xTex < 1) { + xTex = 1; + } + + int yTex = this._ySurface / 128; + if (yTex < 1) { + yTex = 1; + } + + this._surface = null; + if (this._wci != null) { + this._wci.detach(); + } + + this._wci = null; + this._rows = yTex; + this._material = new Material(URL.make(this._defTextureURL), xTex, yTex); + s.setMaterial(this._material); + this._textures = this._material.getTextures(); + this._surface = new TextureSurface(this._textures, yTex, this._xSurface, this._ySurface); + + try { + this._wci = WebControlFactory.createWebControlImp(this._surface.getHwnd(), false, this._isAdBanner); + } catch (NoWebControlException var5) { + System.out.println("Could not create MSIE control for billboard."); + this._wci = null; + return; + } + + if (!this._wci.setURL(this._textureURL)) { + this._retryURL = true; + } + + this._wci.addListener(this); + } + + private void setTexture() { + Sharer sh = (Sharer)this.getOwner(); + if (sh != null) { + Rect s = (Rect)sh.getOwner(); + this.assignMaterial(s); + } + } + + @Override + public void detach() { + Rect s = (Rect)((Sharer)this.getOwner()).getOwner(); + s._billboardAttribute = null; + if (this._wci != null) { + this._wci.detach(); + } + + super.detach(); + } + + @Override + public void finalize() { + this.releaseAuxilaryData(); + super.finalize(); + } + + public boolean getIsAdBanner() { + return this._isAdBanner; + } + + public void billboardClicked(Point2 pt) { + if (this._passClicks) { + double realX = (double)pt.x * this._surface.getWidth(); + double realY = (double)pt.y * this._surface.getHeight(); + realY = this._surface.getHeight() - realY; + this._surface.sendLeftClick((int)realX, (int)realY); + } else { + Console c = Console.getActive(); + if (c != null && c instanceof DefaultConsole) { + DefaultConsole dc = (DefaultConsole)c; + + try { + WebControl wc = new WebControl(dc.getRender(), this._xPercent, this._yPercent, this._hasToolbar, this._isFixed, false); + wc.activate(); + wc.setURL(this._adURL); + } catch (NoWebControlException var6) { + new SendURLAction(this._adURL).doIt(); + } + } + } + } + + public void billboardFrame(FrameEvent f) { + if (this._retryURL && this._wci != null) { + if (!this._wci.setURL(this._textureURL)) { + return; + } + + this._retryURL = false; + } + + if (this._surface != null) { + if (this.frameCnt <= this._refresh && this.frameCnt != -1) { + this.frameCnt++; + } else { + if (this.frameCnt != -1 && this._refresh == -1) { + return; + } + + this.frameCnt = 0; + this.draw(); + } + } + } + + public synchronized void draw() { + if (this._surface != null && this._wci != null) { + this._surface.setTextures(this._material.getTextures(), this._rows); + this._surface.draw(this._wci); + } + } + + @Override + public void webControlEvent(int eventID) { + if (eventID == 1 && this._refresh == -1) { + this.draw(); + } + } + + @Override + public void generateNetData(DataOutputStream s) throws IOException { + s.writeUTF(this._adURL); + s.writeUTF(this._textureURL); + s.writeInt(this._xPercent); + s.writeInt(this._yPercent); + s.writeInt(this._xSurface); + s.writeInt(this._ySurface); + s.writeInt(this._refresh); + s.writeInt(this._hasToolbar ? 1 : 0); + s.writeInt(this._isFixed ? 1 : 0); + s.writeInt(this._passClicks ? 1 : 0); + s.writeInt(this._isAdBanner ? 1 : 0); + } + + @Override + public void setFromNetData(DataInputStream ds, int len) throws IOException { + this._adURL = ds.readUTF(); + this._textureURL = ds.readUTF(); + this._xPercent = ds.readInt(); + this._yPercent = ds.readInt(); + this._xSurface = ds.readInt(); + this._ySurface = ds.readInt(); + this._refresh = ds.readInt(); + this._hasToolbar = ds.readInt() == 1; + this._isFixed = ds.readInt() == 1; + this._passClicks = ds.readInt() == 1; + this._isAdBanner = ds.readInt() == 1; + this.noteChange(); + this.setTexture(); + } + + @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 = StringPropertyEditor.make(new Property(this, index, "Target URL")); + } else if (mode == 1) { + ret = this._adURL; + } else if (mode == 2) { + this._adURL = (String)value; + } + break; + case 1: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Texture URL")); + } else if (mode == 1) { + ret = this._textureURL; + } else if (mode == 2) { + this._textureURL = (String)value; + this.setTexture(); + } + break; + case 2: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "X Overlay % or Width"), 0, 1024); + } else if (mode == 1) { + ret = new Integer(this._xPercent); + } else if (mode == 2) { + this._xPercent = (Integer)value; + } + break; + case 3: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Y Overlay % or Height"), 0, 1024); + } else if (mode == 1) { + ret = new Integer(this._yPercent); + } else if (mode == 2) { + this._yPercent = (Integer)value; + } + break; + case 4: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Has Toolbar"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this._hasToolbar); + } else if (mode == 2) { + this._hasToolbar = (Boolean)value; + } + break; + case 5: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Fixed size"), "No - Percentage specified", "Yes - Pixels specified"); + } else if (mode == 1) { + ret = new Boolean(this._isFixed); + } else if (mode == 2) { + this._isFixed = (Boolean)value; + } + break; + case 6: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Texture Width"), 0, 1024); + } else if (mode == 1) { + ret = new Integer(this._xSurface); + } else if (mode == 2) { + this._xSurface = (Integer)value; + this.setTexture(); + } + break; + case 7: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Texture Height"), 0, 1024); + } else if (mode == 1) { + ret = new Integer(this._ySurface); + } else if (mode == 2) { + this._ySurface = (Integer)value; + this.setTexture(); + } + break; + case 8: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Texture Refresh Rate"), -1, 1024); + } else if (mode == 1) { + ret = new Integer(this._refresh); + } else if (mode == 2) { + this._refresh = (Integer)value; + } + break; + case 9: + if (mode == 0) { + ret = BooleanPropertyEditor.make( + new Property(this, index, "Pass clicks"), "No - Click launches specified page", "Yes - Mouse events passed through to texture page" + ); + } else if (mode == 1) { + ret = new Boolean(this._passClicks); + } else if (mode == 2) { + this._passClicks = (Boolean)value; + } + break; + case 10: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Is Ad Banner"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this._isAdBanner); + } else if (mode == 2) { + this._isAdBanner = (Boolean)value; + } + break; + default: + ret = super.properties(index, offset + 11, mode, value); + } + + if (mode == 2) { + this.noteChange(); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(3, classCookie); + super.saveState(s); + s.saveString(this._adURL); + s.saveString(this._textureURL); + s.saveInt(this._xPercent); + s.saveInt(this._yPercent); + s.saveBoolean(this._hasToolbar); + s.saveBoolean(this._isFixed); + s.saveInt(this._xSurface); + s.saveInt(this._ySurface); + s.saveInt(this._refresh); + s.saveBoolean(this._passClicks); + s.saveBoolean(this._isAdBanner); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this._adURL = r.restoreString(); + this._textureURL = r.restoreString(); + this._xPercent = r.restoreInt(); + this._yPercent = r.restoreInt(); + this._hasToolbar = r.restoreBoolean(); + this.noteChange(); + break; + case 1: + super.restoreState(r); + this._adURL = r.restoreString(); + this._textureURL = r.restoreString(); + this._xPercent = r.restoreInt(); + this._yPercent = r.restoreInt(); + this._hasToolbar = r.restoreBoolean(); + this._isFixed = r.restoreBoolean(); + this.noteChange(); + break; + case 2: + super.restoreState(r); + this._adURL = r.restoreString(); + this._textureURL = r.restoreString(); + this._xPercent = r.restoreInt(); + this._yPercent = r.restoreInt(); + this._hasToolbar = r.restoreBoolean(); + this._isFixed = r.restoreBoolean(); + this._xSurface = r.restoreInt(); + this._ySurface = r.restoreInt(); + this._refresh = r.restoreInt(); + this._passClicks = r.restoreBoolean(); + this.noteChange(); + break; + case 3: + super.restoreState(r); + this._adURL = r.restoreString(); + this._textureURL = r.restoreString(); + this._xPercent = r.restoreInt(); + this._yPercent = r.restoreInt(); + this._hasToolbar = r.restoreBoolean(); + this._isFixed = r.restoreBoolean(); + this._xSurface = r.restoreInt(); + this._ySurface = r.restoreInt(); + this._refresh = r.restoreInt(); + this._passClicks = r.restoreBoolean(); + this._isAdBanner = r.restoreBoolean(); + this.noteChange(); + break; + default: + throw new TooNewException(); + } + + this.setTexture(); + } + + @Override + public void releaseAuxilaryData() { + if (this._wci != null) { + this._wci.detach(); + this._wci = null; + } + + if (this._surface != null) { + this._surface.finalize(); + this._surface = null; + } + + if (this._material != null) { + this._material.detach(); + this._material.finalize(); + this._material = null; + } + + this._textures = null; + } +} diff --git a/NET/worlds/scape/BizCard.java b/NET/worlds/scape/BizCard.java new file mode 100644 index 0000000..902d071 --- /dev/null +++ b/NET/worlds/scape/BizCard.java @@ -0,0 +1,126 @@ +package NET.worlds.scape; + +import NET.worlds.core.IniFile; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class BizCard extends Attribute { + String[] _line = new String[]{"", "", "", "", ""}; + private static Object classCookie = new Object(); + + public BizCard(int attrID) { + super(attrID); + this.loadIni(); + } + + public BizCard() { + } + + private void loadIni() { + for (int i = 0; i < 5; i++) { + this._line[i] = IniFile.gamma().getIniString("BizCard" + i, this._line[i]); + } + } + + public String[] get() { + return this._line; + } + + public void set(String[] lines) { + int total = 0; + + for (int i = 0; i < this._line.length; i++) { + int l = lines[i].length(); + total += l; + if (total < 200 && lines[i] != null) { + this._line[i] = lines[i]; + } else { + this._line[i] = ""; + } + } + + this.noteChange(); + } + + @Override + protected void noteAddingTo(SuperRoot owner) { + this.set(this._line); + } + + @Override + public void generateNetData(DataOutputStream s) throws IOException { + s.writeInt(this._line.length); + + for (int i = 0; i < this._line.length; i++) { + s.writeUTF(this._line[i]); + } + } + + @Override + public void setFromNetData(DataInputStream ds, int len) throws IOException { + int nLines = ds.readInt(); + String[] serverLines = new String[nLines]; + + for (int i = 0; i < nLines; i++) { + serverLines[i] = ds.readUTF(); + } + + this.set(serverLines); + } + + @Override + public Object properties(int index, int offset, int mode, Object value) throws NoSuchPropertyException { + Object ret = null; + switch (index - offset) { + case 0: + case 1: + case 2: + case 3: + case 4: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Line " + (index - offset))); + } else if (mode == 1) { + ret = this._line[index - offset]; + } else if (mode == 2) { + this._line[index - offset] = (String)value; + this.set(this._line); + } + break; + default: + ret = super.properties(index, offset + 5, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + s.saveInt(this._line.length); + + for (int i = 0; i < this._line.length; i++) { + s.saveString(this._line[i]); + } + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + int nLines = r.restoreInt(); + this._line = new String[nLines]; + + for (int i = 0; i < nLines; i++) { + this._line[i] = r.restoreString(); + } + + this.set(this._line); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/BooleanFieldEditorDialog.java b/NET/worlds/scape/BooleanFieldEditorDialog.java new file mode 100644 index 0000000..ea661ca --- /dev/null +++ b/NET/worlds/scape/BooleanFieldEditorDialog.java @@ -0,0 +1,21 @@ +package NET.worlds.scape; + +class BooleanFieldEditorDialog extends CheckboxEditorDialog { + private Property property; + + BooleanFieldEditorDialog(EditTile parent, String title, Property property, String[] choices) { + super(parent, title, choices); + this.property = property; + this.ready(); + } + + @Override + protected int getValue() { + return this.property.get() ? 1 : 0; + } + + @Override + protected void setValue(int choice) { + this.parent.addUndoableSet(this.property, new Boolean(choice == 1)); + } +} diff --git a/NET/worlds/scape/BooleanPropertyEditor.java b/NET/worlds/scape/BooleanPropertyEditor.java new file mode 100644 index 0000000..83db263 --- /dev/null +++ b/NET/worlds/scape/BooleanPropertyEditor.java @@ -0,0 +1,26 @@ +package NET.worlds.scape; + +import NET.worlds.console.PolledDialog; + +public class BooleanPropertyEditor extends PropEditor { + private String[] choices; + private String falseName; + private String trueName; + + private BooleanPropertyEditor(Property property, String falseName, String trueName) { + super(property); + this.falseName = falseName; + this.trueName = trueName; + } + + @Override + public PolledDialog edit(EditTile parent, String title) { + String[] choices = new String[]{this.falseName, this.trueName}; + return new BooleanFieldEditorDialog(parent, title, this.property, choices); + } + + public static Property make(Property property, String falseName, String trueName) { + property.setPropertyType(0); + return property.setEditor(new BooleanPropertyEditor(property, falseName, trueName)); + } +} diff --git a/NET/worlds/scape/BoundBoxTemp.java b/NET/worlds/scape/BoundBoxTemp.java new file mode 100644 index 0000000..31ddc3e --- /dev/null +++ b/NET/worlds/scape/BoundBoxTemp.java @@ -0,0 +1,84 @@ +package NET.worlds.scape; + +public class BoundBoxTemp { + private static Recycler recycler = new Recycler(); + public Point3Temp lo; + public Point3Temp hi; + + public static BoundBoxTemp make(Point3Temp a, Point3Temp b) { + BoundBoxTemp t = (BoundBoxTemp)recycler.alloc(); + if (t == null) { + recycler.recycle(new BoundBoxTemp()); + t = (BoundBoxTemp)recycler.alloc(); + } + + t.lo = Point3Temp.make(a); + t.hi = Point3Temp.make(b); + if (a.x > b.x) { + t.lo.x = b.x; + t.hi.x = a.x; + } + + if (a.y > b.y) { + t.lo.y = b.y; + t.hi.y = a.y; + } + + if (a.z > b.z) { + t.lo.z = b.z; + t.hi.z = a.z; + } + + return t; + } + + public static BoundBoxTemp make(BoundBoxTemp b) { + return make(b.lo, b.hi); + } + + private BoundBoxTemp() { + } + + public boolean contains(Point3Temp p) { + return p.x >= this.lo.x && p.x <= this.hi.x && p.y >= this.lo.y && p.y <= this.hi.y && p.z >= this.lo.z && p.z <= this.hi.z; + } + + public boolean isEmpty() { + return this.lo.x == this.hi.x && this.lo.y == this.hi.y && this.lo.z == this.hi.z; + } + + public boolean overlaps(BoundBoxTemp r) { + return !(this.hi.x < r.lo.x) && !(r.hi.x < this.lo.x) && !(this.hi.y < r.lo.y) && !(r.hi.y < this.lo.y) && !(this.hi.z < r.lo.z) && !(r.hi.z < this.lo.z); + } + + public void encompass(Point3Temp p) { + if (p.x < this.lo.x) { + this.lo.x = p.x; + } + + if (p.y < this.lo.y) { + this.lo.y = p.y; + } + + if (p.z < this.lo.z) { + this.lo.z = p.z; + } + + if (p.x > this.hi.x) { + this.hi.x = p.x; + } + + if (p.y > this.hi.y) { + this.hi.y = p.y; + } + + if (p.z > this.hi.z) { + this.hi.z = p.z; + } + } + + @Override + public String toString() { + return "BoundBoxTemp[lo=" + this.lo + ", hi=" + this.hi + "]"; + } +} diff --git a/NET/worlds/scape/BoxBumpCalc.java b/NET/worlds/scape/BoxBumpCalc.java new file mode 100644 index 0000000..06e6c50 --- /dev/null +++ b/NET/worlds/scape/BoxBumpCalc.java @@ -0,0 +1,61 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class BoxBumpCalc extends BumpCalc { + private static Object classCookie = new Object(); + + @Override + public void detectBump(BumpEventTemp b, WObject owner) { + BoundBoxTemp box = owner.getBoundBox(); + BoundBoxTemp sourceBox = ((WObject)b.source).getBoundBox(); + box.lo.minus(sourceBox.hi.minus(b.sourceAt)); + box.hi.minus(sourceBox.lo.minus(b.sourceAt)); + Point3Temp pos = Point3Temp.make(); + pos.x = box.lo.x; + pos.y = box.lo.y; + float xExtent = box.hi.x - box.lo.x; + float yExtent = box.hi.y - box.lo.y; + Point3Temp d = Point3Temp.make(xExtent, 0.0F, 0.0F); + Point3Temp extent = Point3Temp.make(0.0F, yExtent / 2.0F, 0.0F); + if (!b.hitTriRegion(owner, pos, d, extent)) { + pos.x = box.hi.x; + pos.y = box.hi.y; + d.x = -d.x; + extent.y = -extent.y; + if (!b.hitTriRegion(owner, pos, d, extent)) { + pos.y = box.lo.y; + d.y = yExtent; + d.x = 0.0F; + extent.x = -xExtent / 2.0F; + extent.y = 0.0F; + if (!b.hitTriRegion(owner, pos, d, extent)) { + pos.x = box.lo.x; + pos.y = box.hi.y; + d.y = -d.y; + extent.x = -extent.x; + if (!b.hitTriRegion(owner, pos, d, extent)) { + ; + } + } + } + } + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/BuildRamp.java b/NET/worlds/scape/BuildRamp.java new file mode 100644 index 0000000..fc4a2e0 --- /dev/null +++ b/NET/worlds/scape/BuildRamp.java @@ -0,0 +1,310 @@ +package NET.worlds.scape; + +import java.awt.Color; +import java.io.IOException; + +public class BuildRamp extends SwitchableBehavior implements FrameHandler, Persister { + protected boolean doBuild = false; + protected boolean built = false; + protected WrRamp ramp = null; + protected String stairName = "ramp"; + protected float length = 1000.0F; + protected float width = 300.0F; + protected float pWidth = 250.0F; + protected float pHeight = 240.0F; + protected float dz = 300.0F; + protected float lintelZ = 50.0F; + protected float floorTileX = 300.0F; + protected float floorTileY = 200.0F; + protected float ceilTileX = 300.0F; + protected float ceilTileY = 200.0F; + protected float leftTileX = 100.0F; + protected float leftTileY = 100.0F; + protected float rightTileX = 100.0F; + protected float rightTileY = 100.0F; + protected Material floor = new Material(Color.green); + protected Material left = new Material(Color.cyan); + protected Material right = new Material(Color.red); + protected Material doorpost = new Material(Color.yellow); + protected Material lintel = new Material(Color.magenta); + protected Material ceiling = new Material(Color.blue); + protected String worldURL = null; + + protected void build(Portal end1) { + Room room = end1.getRoom(); + World world = room.getWorld(); + this.ramp = new WrRamp( + world, + this.stairName, + this.length, + this.width, + this.pWidth, + this.pHeight, + this.dz, + this.lintelZ, + this.floorTileX, + this.floorTileY, + this.ceilTileX, + this.ceilTileY, + this.leftTileX, + this.leftTileY, + this.rightTileX, + this.rightTileY, + this.floor, + this.left, + this.right, + this.doorpost, + this.lintel, + this.ceiling + ); + end1.biconnect(this.ramp.portal1); + this.built = true; + end1.removeHandler(this); + } + + protected void unbuild(Portal end1) { + this.built = false; + } + + @Override + public boolean handle(FrameEvent e) { + if (!this.built && this.doBuild && e.target instanceof Portal) { + this.build((Portal)e.target); + } else if (this.built && !this.doBuild && e.target instanceof Portal) { + this.unbuild((Portal)e.target); + } + + return true; + } + + @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 = new ClassProperty(this, index, "BuildRamp"); + } + break; + case 1: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Build now?"), "Later", "Now"); + } else if (mode == 1) { + ret = new Boolean(this.doBuild); + } else if (mode == 2) { + this.doBuild = (Boolean)value; + } + break; + case 2: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Staircase Name")); + } else if (mode == 1) { + ret = this.stairName; + } else if (mode == 2) { + this.stairName = (String)value; + } + break; + case 3: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Portal-to-portal Distance")); + } else if (mode == 1) { + ret = new Float(this.length); + } else if (mode == 2) { + this.length = (Float)value; + } + break; + case 4: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Stairwell Width")); + } else if (mode == 1) { + ret = new Float(this.width); + } else if (mode == 2) { + this.width = (Float)value; + } + break; + case 5: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Portal Width")); + } else if (mode == 1) { + ret = new Float(this.pWidth); + } else if (mode == 2) { + this.pWidth = (Float)value; + } + break; + case 6: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Portal Height")); + } else if (mode == 1) { + ret = new Float(this.pHeight); + } else if (mode == 2) { + this.pHeight = (Float)value; + } + break; + case 7: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Total Rise")); + } else if (mode == 1) { + ret = new Float(this.dz); + } else if (mode == 2) { + this.dz = (Float)value; + } + break; + case 8: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Lintel Height")); + } else if (mode == 1) { + ret = new Float(this.lintelZ); + } else if (mode == 2) { + this.lintelZ = (Float)value; + } + break; + case 9: + if (mode == 0) { + ret = Point2PropertyEditor.make(new Property(this, index, "Floor Tile Size")); + } else if (mode == 1) { + Point2 coords = new Point2(); + coords.x = this.floorTileX; + coords.y = this.floorTileY; + ret = coords; + } else if (mode == 2) { + this.floorTileX = ((Point2)value).x; + this.floorTileY = ((Point2)value).y; + } + break; + case 10: + if (mode == 0) { + ret = Point2PropertyEditor.make(new Property(this, index, "Ceiling Tile Size")); + } else if (mode == 1) { + Point2 coords = new Point2(); + coords.x = this.ceilTileX; + coords.y = this.ceilTileY; + ret = coords; + } else if (mode == 2) { + this.ceilTileX = ((Point2)value).x; + this.ceilTileY = ((Point2)value).y; + } + break; + case 11: + if (mode == 0) { + ret = Point2PropertyEditor.make(new Property(this, index, "Left Wall Tile Size")); + } else if (mode == 1) { + Point2 coords = new Point2(); + coords.x = this.leftTileX; + coords.y = this.leftTileY; + ret = coords; + } else if (mode == 2) { + this.leftTileX = ((Point2)value).x; + this.leftTileY = ((Point2)value).y; + } + break; + case 12: + if (mode == 0) { + ret = Point2PropertyEditor.make(new Property(this, index, "Right Wall Tile Size")); + } else if (mode == 1) { + Point2 coords = new Point2(); + coords.x = this.rightTileX; + coords.y = this.rightTileY; + ret = coords; + } else if (mode == 2) { + this.rightTileX = ((Point2)value).x; + this.rightTileY = ((Point2)value).y; + } + break; + case 13: + if (mode == 0) { + ret = new Property(this, index, "Floor Material"); + } else if (mode == 1) { + ret = this.floor; + } + break; + case 14: + if (mode == 0) { + ret = new Property(this, index, "Left Wall Material"); + } else if (mode == 1) { + ret = this.left; + } + break; + case 15: + if (mode == 0) { + ret = new Property(this, index, "Right Wall Material"); + } else if (mode == 1) { + ret = this.right; + } + break; + case 16: + if (mode == 0) { + ret = new Property(this, index, "Doorpost Material"); + } else if (mode == 1) { + ret = this.doorpost; + } + break; + case 17: + if (mode == 0) { + ret = new Property(this, index, "Lintel Material"); + } else if (mode == 1) { + ret = this.lintel; + } + break; + case 18: + if (mode == 0) { + ret = new Property(this, index, "Ceiling Material"); + } else if (mode == 1) { + ret = this.ceiling; + } + break; + default: + ret = super.properties(index, offset + 19, mode, value); + } + + return ret; + } + + @Override + public String toString() { + return "Ramp: built=" + this.built; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveBoolean(this.built); + s.saveString(this.stairName); + s.saveFloat(this.length); + s.saveFloat(this.width); + s.saveFloat(this.pWidth); + s.saveFloat(this.pHeight); + s.saveFloat(this.dz); + s.saveFloat(this.lintelZ); + s.saveFloat(this.floorTileX); + s.saveFloat(this.floorTileY); + s.saveFloat(this.ceilTileX); + s.saveFloat(this.ceilTileY); + s.saveFloat(this.leftTileX); + s.saveFloat(this.leftTileY); + s.saveFloat(this.rightTileX); + s.saveFloat(this.rightTileY); + } + + @Override + public void restoreState(Restorer r) throws IOException { + this.built = r.restoreBoolean(); + this.stairName = r.restoreString(); + this.length = r.restoreFloat(); + this.width = r.restoreFloat(); + this.pWidth = r.restoreFloat(); + this.pHeight = r.restoreFloat(); + this.dz = r.restoreFloat(); + this.lintelZ = r.restoreFloat(); + this.floorTileX = r.restoreFloat(); + this.floorTileY = r.restoreFloat(); + this.ceilTileX = r.restoreFloat(); + this.ceilTileY = r.restoreFloat(); + this.leftTileX = r.restoreFloat(); + this.leftTileY = r.restoreFloat(); + this.rightTileX = r.restoreFloat(); + this.rightTileY = r.restoreFloat(); + } + + @Override + public void postRestore(int version) { + } +} diff --git a/NET/worlds/scape/BuildStairs.java b/NET/worlds/scape/BuildStairs.java new file mode 100644 index 0000000..0b3d086 --- /dev/null +++ b/NET/worlds/scape/BuildStairs.java @@ -0,0 +1,248 @@ +package NET.worlds.scape; + +import java.awt.Color; +import java.io.IOException; + +public class BuildStairs extends SwitchableBehavior implements FrameHandler, Persister { + protected boolean doBuild = false; + protected boolean built = false; + protected WrStaircase stairs = null; + protected String stairName = "staircase"; + protected float length = 1000.0F; + protected float width = 300.0F; + protected float pWidth = 250.0F; + protected float pHeight = 240.0F; + protected float dz = 300.0F; + protected float lintelZ = 50.0F; + protected int numsteps = 10; + protected Material riser = new Material(Color.gray); + protected Material tread = new Material(Color.green); + protected Material left = new Material(Color.cyan); + protected Material right = new Material(Color.red); + protected Material doorpost = new Material(Color.yellow); + protected Material lintel = new Material(Color.magenta); + protected Material ceiling = new Material(Color.blue); + protected String worldURL = null; + + protected void build(Portal end1) { + Room room = end1.getRoom(); + World world = room.getWorld(); + this.stairs = new WrStaircase( + world, + this.stairName, + this.length, + this.width, + this.pWidth, + this.pHeight, + this.dz, + this.lintelZ, + this.numsteps, + this.riser, + this.tread, + this.left, + this.right, + this.doorpost, + this.lintel, + this.ceiling + ); + end1.biconnect(this.stairs.portal1); + this.built = true; + end1.removeHandler(this); + } + + protected void unbuild(Portal end1) { + this.built = false; + } + + @Override + public boolean handle(FrameEvent e) { + if (!this.built && this.doBuild && e.target instanceof Portal) { + this.build((Portal)e.target); + } else if (this.built && !this.doBuild && e.target instanceof Portal) { + this.unbuild((Portal)e.target); + } + + return true; + } + + @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 = new ClassProperty(this, index, "BuildStairs"); + } + break; + case 1: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Build now?"), "Later", "Now"); + } else if (mode == 1) { + ret = new Boolean(this.doBuild); + } else if (mode == 2) { + this.doBuild = (Boolean)value; + } + break; + case 2: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Staircase Name")); + } else if (mode == 1) { + ret = this.stairName; + } else if (mode == 2) { + this.stairName = (String)value; + } + break; + case 3: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Number of Steps")); + } else if (mode == 1) { + ret = new Integer(this.numsteps); + } else if (mode == 2) { + this.numsteps = (Integer)value; + } + break; + case 4: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Portal-to-portal Distance")); + } else if (mode == 1) { + ret = new Float(this.length); + } else if (mode == 2) { + this.length = (Float)value; + } + break; + case 5: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Stairwell Width")); + } else if (mode == 1) { + ret = new Float(this.width); + } else if (mode == 2) { + this.width = (Float)value; + } + break; + case 6: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Portal Width")); + } else if (mode == 1) { + ret = new Float(this.pWidth); + } else if (mode == 2) { + this.pWidth = (Float)value; + } + break; + case 7: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Portal Height")); + } else if (mode == 1) { + ret = new Float(this.pHeight); + } else if (mode == 2) { + this.pHeight = (Float)value; + } + break; + case 8: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Total Rise")); + } else if (mode == 1) { + ret = new Float(this.dz); + } else if (mode == 2) { + this.dz = (Float)value; + } + break; + case 9: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Lintel Height")); + } else if (mode == 1) { + ret = new Float(this.lintelZ); + } else if (mode == 2) { + this.lintelZ = (Float)value; + } + break; + case 10: + if (mode == 0) { + ret = new Property(this, index, "Riser Material"); + } else if (mode == 1) { + ret = this.riser; + } + break; + case 11: + if (mode == 0) { + ret = new Property(this, index, "Tread Material"); + } else if (mode == 1) { + ret = this.tread; + } + break; + case 12: + if (mode == 0) { + ret = new Property(this, index, "Left Wall Material"); + } else if (mode == 1) { + ret = this.left; + } + break; + case 13: + if (mode == 0) { + ret = new Property(this, index, "Right Wall Material"); + } else if (mode == 1) { + ret = this.right; + } + break; + case 14: + if (mode == 0) { + ret = new Property(this, index, "Doorpost Material"); + } else if (mode == 1) { + ret = this.doorpost; + } + break; + case 15: + if (mode == 0) { + ret = new Property(this, index, "Lintel Material"); + } else if (mode == 1) { + ret = this.lintel; + } + break; + case 16: + if (mode == 0) { + ret = new Property(this, index, "Ceiling Material"); + } else if (mode == 1) { + ret = this.ceiling; + } + break; + default: + ret = super.properties(index, offset + 17, mode, value); + } + + return ret; + } + + @Override + public String toString() { + return "Stairs: built=" + this.built; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveBoolean(this.built); + s.saveString(this.stairName); + s.saveFloat(this.length); + s.saveFloat(this.width); + s.saveFloat(this.pWidth); + s.saveFloat(this.pHeight); + s.saveFloat(this.dz); + s.saveFloat(this.lintelZ); + s.saveInt(this.numsteps); + } + + @Override + public void restoreState(Restorer r) throws IOException { + this.built = r.restoreBoolean(); + this.stairName = r.restoreString(); + this.length = r.restoreFloat(); + this.width = r.restoreFloat(); + this.pWidth = r.restoreFloat(); + this.pHeight = r.restoreFloat(); + this.dz = r.restoreFloat(); + this.lintelZ = r.restoreFloat(); + this.numsteps = r.restoreInt(); + } + + @Override + public void postRestore(int version) { + } +} diff --git a/NET/worlds/scape/BumpAttribute.java b/NET/worlds/scape/BumpAttribute.java new file mode 100644 index 0000000..1944c35 --- /dev/null +++ b/NET/worlds/scape/BumpAttribute.java @@ -0,0 +1,56 @@ +package NET.worlds.scape; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class BumpAttribute extends Attribute { + private static Object classCookie = new Object(); + + public BumpAttribute(int attrID) { + super(attrID); + } + + public BumpAttribute() { + } + + @Override + protected void noteAddingTo(SuperRoot owner) { + WObject w = (WObject)((Sharer)owner).getOwner(); + w._bumpableAttribute = this; + } + + @Override + public void detach() { + WObject w = (WObject)((Sharer)this.getOwner()).getOwner(); + w._bumpableAttribute = null; + super.detach(); + } + + @Override + public void generateNetData(DataOutputStream s) throws IOException { + s.writeBoolean(((WObject)this.getOwner().getOwner()).getBumpable()); + } + + @Override + public void setFromNetData(DataInputStream ds, int len) throws IOException { + ((WObject)this.getOwner().getOwner()).setBumpable(ds.readBoolean()); + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/BumpCalc.java b/NET/worlds/scape/BumpCalc.java new file mode 100644 index 0000000..4bc0a0b --- /dev/null +++ b/NET/worlds/scape/BumpCalc.java @@ -0,0 +1,10 @@ +package NET.worlds.scape; + +public abstract class BumpCalc extends SuperRoot { + public abstract void detectBump(BumpEventTemp var1, WObject var2); + + @Override + public String toString() { + return this.getName(); + } +} diff --git a/NET/worlds/scape/BumpEventTemp.java b/NET/worlds/scape/BumpEventTemp.java new file mode 100644 index 0000000..b050a44 --- /dev/null +++ b/NET/worlds/scape/BumpEventTemp.java @@ -0,0 +1,151 @@ +package NET.worlds.scape; + +public class BumpEventTemp extends Event { + private static Recycler recycler = new Recycler(); + public Point3Temp fullPath; + public Point3Temp path; + public BoundBoxTemp bound; + public float fraction; + public Room postBumpRoom; + public Transform postBumpPosition; + public Point3Temp postBumpPath; + public Point3Temp sourceAt; + public BoundBoxTemp sourceBoxMinus; + public Point3Temp bumpNormal; + + public static BumpEventTemp make(int time, WObject mover, Point3Temp motion) { + BumpEventTemp t = (BumpEventTemp)recycler.alloc(); + if (t == null) { + recycler.recycle(new BumpEventTemp(0, null)); + t = (BumpEventTemp)recycler.alloc(); + } + + assert t.source == null; + + t.time = time; + t.source = mover; + t.fullPath = Point3Temp.make(motion); + t.path = t.fullPath; + t.sourceAt = ((WObject)t.source).getWorldPosition(); + t.sourceBoxMinus = ((WObject)t.source).getBoundBox(); + t.sourceBoxMinus.lo.minus(t.sourceAt); + t.sourceBoxMinus.hi.minus(t.sourceAt); + t.setPathFraction(1.0F); + Room r = mover.getRoom(); + if (r.getBumpable()) { + r.detectBump(t); + } + + return t; + } + + public void recycle() { + this.time = 0; + this.source = null; + this.target = null; + this.receiver = null; + this.postBumpRoom = null; + this.postBumpPath = null; + this.postBumpPosition = null; + } + + private BumpEventTemp(int time, Object source) { + super(time, source, null); + } + + public void setPathFraction(float fraction) { + this.fraction = fraction; + this.path = Point3Temp.make(this.path).times(fraction); + this.bound = BoundBoxTemp.make(this.sourceAt, Point3Temp.make(this.sourceAt).plus(this.path)); + this.bound.lo.plus(this.sourceBoxMinus.lo); + this.bound.hi.plus(this.sourceBoxMinus.hi); + } + + public float isCollision(Point3Temp left, Point3Temp d, Point3Temp start, Point3Temp motion) { + double D = (double)motion.x * -d.y + (double)motion.y * d.x; + if (D > 0.0) { + Point3Temp C = Point3Temp.make(start).minus(left); + double betaNum = (double)C.x * d.y - (double)C.y * d.x; + double alphaNum = (double)C.x * motion.y - (double)motion.x * C.y; + return alphaNum >= 0.0 && alphaNum <= D && betaNum >= 0.0 && betaNum <= D ? (float)(betaNum / D) : -2.0F; + } else { + return -1.0F; + } + } + + public float hitPlane(WObject o, Point3Temp left, Point3Temp d) { + float dist = this.isCollision(left, d, this.sourceAt, this.path); + if (dist >= 0.0F) { + this.target = o; + this.setPathFraction(dist); + this.bumpNormal = Point3Temp.make(d.y, -d.x, 0.0F).normalize(); + this.path.plus(Point3Temp.make(this.path).normalize().times(0.2F)); + } + + return dist; + } + + public boolean hitRegion(WObject o, Point3Temp left, Point3Temp d, Point3Temp extent) { + float dist = this.hitPlane(o, left, d); + if (dist >= 0.0F) { + return true; + } else if (dist == -1.0F) { + return false; + } else { + Point3Temp right = Point3Temp.make(left).plus(d); + Point3Temp minusD = Point3Temp.make().minus(d); + Point3Temp minusExtent = Point3Temp.make().minus(extent); + if (this.isCollision(right, minusD, this.sourceAt, minusExtent) > 0.0F) { + this.target = o; + this.setPathFraction(0.0F); + this.bumpNormal = minusExtent; + return true; + } else { + return false; + } + } + } + + public boolean hitTriRegion(WObject o, Point3Temp left, Point3Temp d, Point3Temp extent) { + float dist = this.hitPlane(o, left, d); + if (dist >= 0.0F) { + return true; + } else if (dist == -1.0F) { + return false; + } else { + Point3Temp right = Point3Temp.make(left).plus(d); + Point3Temp minusD = Point3Temp.make().minus(d); + Point3Temp minusExtent = Point3Temp.make().minus(extent); + if (this.isCollision(right, minusD, this.sourceAt, minusExtent) > 0.0F) { + float dx = this.sourceAt.x - (left.x + d.x / 2.0F); + float dy = this.sourceAt.y - (left.y + d.y / 2.0F); + float squaredDistFromMid = dx * dx + dy * dy; + dx = this.sourceAt.x - (left.x + extent.x); + dy = this.sourceAt.y - (left.y + extent.y); + float squaredDistFromA = dx * dx + dy * dy; + if (squaredDistFromA < squaredDistFromMid) { + return false; + } else { + dx = this.sourceAt.x - (right.x + extent.x); + dy = this.sourceAt.y - (right.y + extent.y); + float squaredDistFromB = dx * dx + dy * dy; + if (squaredDistFromB < squaredDistFromMid) { + return false; + } else { + this.target = o; + this.setPathFraction(0.0F); + this.bumpNormal = minusExtent; + return true; + } + } + } else { + return false; + } + } + } + + @Override + public boolean deliver(Object o) { + return o instanceof BumpHandler ? ((BumpHandler)o).handle(this) : false; + } +} diff --git a/NET/worlds/scape/BumpHandler.java b/NET/worlds/scape/BumpHandler.java new file mode 100644 index 0000000..c307e32 --- /dev/null +++ b/NET/worlds/scape/BumpHandler.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface BumpHandler { + boolean handle(BumpEventTemp var1); +} diff --git a/NET/worlds/scape/BumpSensor.java b/NET/worlds/scape/BumpSensor.java new file mode 100644 index 0000000..1833a61 --- /dev/null +++ b/NET/worlds/scape/BumpSensor.java @@ -0,0 +1,21 @@ +package NET.worlds.scape; + +public class BumpSensor extends Sensor implements BumpHandler { + public BumpSensor(Action a) { + if (a != null) { + this.addAction(a); + } + } + + public BumpSensor() { + } + + @Override + public boolean handle(BumpEventTemp e) { + if (e.source instanceof Pilot) { + this.trigger(e); + } + + return true; + } +} diff --git a/NET/worlds/scape/CDAudio.java b/NET/worlds/scape/CDAudio.java new file mode 100644 index 0000000..2f1ea8f --- /dev/null +++ b/NET/worlds/scape/CDAudio.java @@ -0,0 +1,518 @@ +package NET.worlds.scape; + +import NET.worlds.console.Main; +import NET.worlds.console.MainCallback; +import NET.worlds.console.MainTerminalCallback; +import NET.worlds.core.IniFile; +import NET.worlds.network.URL; +import java.io.File; +import java.io.IOException; +import java.util.Vector; + +public class CDAudio implements Runnable, MainCallback, MainTerminalCallback { + private static final int STOP = 0; + private static final int PLAY = 1; + private static final int PAUSE = 2; + private static final int NEXT = 3; + private static final int PREV = 4; + private static final int CHANGE = 5; + private static final int CHANGE_MIDI = 6; + private boolean performedStartupPlay; + private boolean cancel; + private Thread playerThread; + private Vector commandBuffer = new Vector(); + private boolean paused; + private int driveID; + private CDTrackInfo tracks; + private int trackOffset; + private Object tracksMutex = new Object(); + private int pos; + private SoundPlayer midiPlayer; + private URL defaultMIDIFile = URL.make("home:start.mid"); + private URL curMIDIFile = this.defaultMIDIFile; + private int trackToRepeat = -1; + private int repeatingTrack = -1; + private boolean enabled = true; + private static CDAudio instance = new CDAudio(); + static boolean useMidiFlag = IniFile.gamma().getIniInt("MIDIONSTART", 1) != 0; + static boolean useAutoCDFlag = IniFile.gamma().getIniInt("AUTOPLAYCD", 1) != 0; + private boolean cdInDrive; + private boolean allowMIDIAnyway; + private boolean midiPaused; + private boolean midiStarted; + + public static CDAudio get() { + return instance; + } + + public String getTimeReadout() { + synchronized (this.tracksMutex) { + if (this.tracks == null) { + this.tracksMutex.notify(); + return "00 [00:00]"; + } else { + int count = this.tracks.getNumTracks(); + if (this.pos != 0) { + for (int i = 0; i < count; i++) { + if (this.pos < this.tracks.getEndFrames(i)) { + return fmt2(i + 1) + " " + fmtFrames(this.pos - this.tracks.getStartFrames(i)); + } + } + } + + return fmt2(count) + " " + fmtFrames(this.tracks.getEndFrames(count - 1)); + } + } + } + + public void setEnabled(boolean state) { + if (this.enabled != state) { + this.enabled = state; + if (!this.enabled) { + this.stop(); + } else { + this.change(true); + } + } + } + + public void play() { + this.queueCommand(1); + } + + public void pause() { + this.queueCommand(2); + } + + public void stop() { + this.queueCommand(0); + } + + public void next() { + this.queueCommand(3); + } + + public void prev() { + this.queueCommand(4); + } + + public void change(boolean loop) { + this.queueCommand(5); + } + + public static void startupPlay() { + get(); + } + + public void setMIDIFile(URL url) { + this.curMIDIFile = url; + } + + public URL getDefaultMIDIFile() { + return this.defaultMIDIFile; + } + + public URL getMIDIFile() { + return this.curMIDIFile; + } + + public void setCDTrack(int track) { + this.trackToRepeat = track - 1; + } + + public int getCDTrack() { + return this.trackToRepeat + 1; + } + + private CDAudio() { + this.playerThread = new Thread(this); + this.playerThread.start(); + } + + @Override + public void run() { + Main.register(this); + int numDrives = CDPlayerAction.getNumDrives(); + + while (!this.cancel) { + for (int i = 0; i < numDrives; i++) { + this.cdInDrive = false; + + try { + if ((this.driveID = CDPlayerAction.openDrive(i)) != 0) { + if (!CDPlayerAction.isPlaying(this.driveID)) { + CDTrackInfo tmp = CDPlayerAction.getDriveTrackList(this.driveID); + char drive = (char)(65 + CDPlayerAction.getDriveLetterOffset(i)); + File f = new File(drive + ":\\WORLDS.CD"); + if (f.exists()) { + synchronized (this.tracksMutex) { + this.tracks = tmp; + this.trackOffset = 0; + if (f.length() == 1L) { + this.trackOffset = 1; + } + } + + this.cdInDrive = true; + if (this.performedStartupPlay) { + this.flushPendingCommands(); + } else { + this.performedStartupPlay = true; + } + + this.change(true); + this.waitForCommands(); + } + } + + this.driveID = 0; + } + } catch (IOException var12) { + } + + if (this.driveID != 0) { + try { + CDPlayerAction.closeDrive(this.driveID); + } catch (IOException var10) { + } + + this.driveID = 0; + this.paused = false; + this.pos = 0; + } + } + + this.performedStartupPlay = true; + this.cdInDrive = false; + synchronized (this.tracksMutex) { + this.tracks = null; + } + + if (!this.cancel) { + this.timedWait(10); + synchronized (this.tracksMutex) { + if (!this.cancel) { + try { + this.tracksMutex.wait(); + } catch (InterruptedException var7) { + } + } + } + } + } + + Main.unregister(this); + } + + public void useAutoCD(boolean f) { + if (f != useAutoCDFlag) { + useAutoCDFlag = f; + IniFile.gamma().setIniInt("AUTOPLAYCD", useAutoCDFlag ? 1 : 0); + if (f) { + if (this.trackToRepeat != -1) { + this.queueCommand(5); + } + } else { + this.queueCommand(0); + } + } + } + + private synchronized void flushPendingCommands() { + this.commandBuffer.removeAllElements(); + } + + private synchronized void prequeueCommand(int command) { + this.commandBuffer.insertElementAt(new Integer(command), 0); + } + + private synchronized void queueCommand(int command) { + if (command != 6) { + this.allowMIDIAnyway = false; + } + + this.commandBuffer.addElement(new Integer(command)); + } + + private synchronized int getQueuedCommand(boolean isMidi) { + if (this.commandBuffer.size() <= 0) { + return -1; + } else { + int command = (Integer)this.commandBuffer.elementAt(0); + if (command == 6) { + if (!isMidi) { + return -1; + } + } else if (isMidi == this.cdInDrive) { + return -1; + } + + this.commandBuffer.removeElementAt(0); + return command; + } + } + + private synchronized int peekQueuedCommand() { + return this.commandBuffer.size() <= 0 ? -1 : (Integer)this.commandBuffer.elementAt(0); + } + + private void waitForCommands() throws IOException { + while (!this.cancel) { + boolean playing = CDPlayerAction.isPlaying(this.driveID); + if (playing) { + int tmp = CDPlayerAction.getPosition(this.driveID); + if (tmp > this.pos) { + this.pos = tmp; + } + + this.paused = false; + } else { + CDPlayerAction.checkDrive(this.driveID); + if (!this.paused) { + this.pos = 0; + } + + if (this.repeatingTrack != -1) { + this.pos = this.tracks.getStartFrames(this.repeatingTrack + this.trackOffset); + CDPlayerAction.playAudio(this.driveID, this.pos, this.tracks.getEndFrames(this.repeatingTrack + this.trackOffset)); + } + } + + int command; + if ((command = this.getQueuedCommand(false)) >= 0) { + this.processCommand(command, playing); + } else { + this.timedWait(1); + } + } + + CDPlayerAction.stopAudio(this.driveID); + } + + private void processCommand(int command, boolean playing) throws IOException { + int wasRepeatingTrack = this.repeatingTrack; + this.repeatingTrack = -1; + switch (command) { + case 0: + if (playing || this.paused) { + CDPlayerAction.stopAudio(this.driveID); + } + + this.paused = false; + break; + case 1: + if (!playing) { + this.play(-this.pos); + } + break; + case 2: + if (playing && !this.paused) { + CDPlayerAction.stopAudio(this.driveID); + this.paused = true; + } + break; + case 3: + if (!playing && !this.paused) { + this.play(0); + } else { + for (int ix = 0; ix < this.tracks.getNumTracks() - 1; ix++) { + if (this.pos >= this.tracks.getStartFrames(ix) && this.pos < this.tracks.getEndFrames(ix)) { + this.play(ix + 1); + return; + } + } + } + break; + case 4: + if (playing || this.paused) { + for (int i = 0; i < this.tracks.getNumTracks(); i++) { + if (this.pos < this.tracks.getEndFrames(i)) { + if (i > 0 && this.pos < this.tracks.getStartFrames(i) + 75) { + this.play(i - 1); + } else { + this.play(i); + } + break; + } + } + } + break; + case 5: + if (useAutoCDFlag && this.enabled) { + if (this.trackToRepeat == -1 || this.trackToRepeat < this.tracks.getNumTracks()) { + this.repeatingTrack = this.trackToRepeat; + if (wasRepeatingTrack == this.trackToRepeat && wasRepeatingTrack != -1) { + return; + } + } + + CDPlayerAction.stopAudio(this.driveID); + if (this.repeatingTrack == -1) { + this.allowMIDIAnyway = true; + this.queueCommand(6); + } + + this.paused = false; + } + } + } + + private void play(int location) throws IOException { + if (location < 0) { + this.pos = -location; + } else { + this.pos = this.tracks.getStartFrames(location); + } + + CDPlayerAction.playAudio(this.driveID, this.pos, this.tracks.getEndFrames(this.tracks.getNumTracks() - 1)); + this.paused = false; + } + + private void startMidi() { + if (this.curMIDIFile != this.defaultMIDIFile) { + if (this.midiPlayer != null) { + this.midiPlayer.stop(); + this.midiPlayer.close(); + this.midiStarted = false; + if (MCISoundPlayer.isActive() || WMPSoundPlayer.isActive()) { + this.midiPlayer = null; + return; + } + } else if (MCISoundPlayer.isActive() || WMPSoundPlayer.isActive()) { + return; + } + + Sound s = new Sound(this.curMIDIFile); + if (!this.curMIDIFile.endsWith(".mid") && !this.curMIDIFile.endsWith(".wav")) { + this.midiPlayer = new WMPSoundPlayer(s); + } else { + this.midiPlayer = new MCISoundPlayer(s); + } + + this.midiPlayer.open(1.0F, 0.0F, false, false); + if (!this.midiPaused) { + this.midiPlayer.start(1); + } + } + } + + private void killMidi() { + if (this.midiPlayer != null) { + this.midiStarted = false; + this.midiPlayer.stop(); + this.midiPlayer.close(); + this.midiPlayer = null; + } + } + + private void useMidi() { + if (useMidiFlag && this.enabled && (!this.cdInDrive || this.allowMIDIAnyway)) { + if (this.midiPlayer == null) { + this.startMidi(); + } else if (this.midiPlayer.getState() == 1) { + if (this.midiStarted) { + this.startMidi(); + this.midiStarted = false; + } + } else { + this.midiStarted = true; + } + } + + if (!useMidiFlag || !this.enabled || this.cdInDrive && !this.allowMIDIAnyway) { + this.killMidi(); + } + } + + public void setMidiFlag(boolean f) { + useMidiFlag = f; + IniFile.gamma().setIniInt("MIDIONSTART", useMidiFlag ? 1 : 0); + } + + @Override + public void mainCallback() { + if (this.performedStartupPlay) { + this.useMidi(); + + while (this.midiPlayer != null || this.peekQueuedCommand() == 6) { + if (this.cdInDrive && this.repeatingTrack != -1) { + if (this.peekQueuedCommand() == 6) { + this.getQueuedCommand(true); + } + + this.allowMIDIAnyway = false; + this.useMidi(); + return; + } + + int command; + if ((command = this.getQueuedCommand(true)) < 0) { + return; + } + + switch (command) { + case 0: + case 2: + this.midiPaused = true; + this.midiPlayer.stop(); + this.midiStarted = false; + break; + case 1: + if (this.midiPaused || !this.midiStarted) { + this.midiPaused = false; + this.startMidi(); + } + break; + case 3: + case 4: + this.startMidi(); + break; + case 5: + case 6: + if (useMidiFlag && this.enabled) { + this.midiStarted = false; + this.midiPaused = false; + this.startMidi(); + } + } + } + } + } + + private synchronized void timedWait(int secs) { + if (!this.cancel) { + try { + this.wait(secs * 1000); + } catch (InterruptedException var3) { + } + } + } + + @Override + public void terminalCallback() { + this.cancel = true; + this.killMidi(); + synchronized (this) { + this.notify(); + } + + synchronized (this.tracksMutex) { + this.tracksMutex.notify(); + } + } + + private static String fmt2(int val) { + return val < 10 ? "0" + val : "" + val; + } + + private static String fmtFrames(int frames) { + if (frames < 0) { + frames = 0; + } + + int minutes = frames / 4500; + frames -= minutes * 4500; + int seconds = frames / 75; + return "[" + fmt2(minutes) + ":" + fmt2(seconds) + "]"; + } +} diff --git a/NET/worlds/scape/CDControl.java b/NET/worlds/scape/CDControl.java new file mode 100644 index 0000000..b881b00 --- /dev/null +++ b/NET/worlds/scape/CDControl.java @@ -0,0 +1,88 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.DialogReceiver; +import NET.worlds.console.PolledDialog; +import java.awt.Button; +import java.awt.Checkbox; +import java.awt.FlowLayout; +import java.awt.Font; +import java.awt.GridLayout; +import java.awt.Label; +import java.awt.Panel; +import java.awt.Window; + +public class CDControl extends PolledDialog { + private Label display; + private Button stopButton = new Button("[]"); + private Button pauseButton = new Button("||"); + private Button playButton = new Button(">"); + private Button prevButton = new Button("|<<"); + private Button nextButton = new Button(">>|"); + private Panel top = new Panel(); + private Panel bottom = new Panel(); + private Checkbox cdBox = new Checkbox(Console.message("Autoplay-CD"), CDAudio.useAutoCDFlag); + private Checkbox midiBox = new Checkbox(Console.message("Autoplay-MIDI"), CDAudio.useMidiFlag); + private String time; + private static Font font = new Font(Console.message("MenuFont"), 0, 12); + + public CDControl(Window parent, DialogReceiver receiver) { + super(parent, receiver, Console.message("Music"), false); + this.display = new Label(this.time = CDAudio.get().getTimeReadout()); + this.setAlignment(1); + this.ready(); + } + + @Override + protected void build() { + this.setLayout(new GridLayout(2, 1)); + this.top.setLayout(new FlowLayout()); + this.top.add(this.display); + this.top.add(this.stopButton); + this.top.add(this.pauseButton); + this.top.add(this.playButton); + this.top.add(this.prevButton); + this.top.add(this.nextButton); + this.bottom.setLayout(new GridLayout(2, 1)); + this.cdBox.setFont(font); + this.midiBox.setFont(font); + this.bottom.add(this.cdBox); + this.bottom.add(this.midiBox); + this.add(this.top); + this.add(this.bottom); + } + + @Override + protected void activeCallback() { + String tmp = CDAudio.get().getTimeReadout(); + if (!tmp.equals(this.time)) { + this.display.setText(this.time = tmp); + } + } + + @Override + public boolean action(java.awt.Event event, Object what) { + Object target = event.target; + if (target == this.stopButton) { + CDAudio.get().stop(); + } else if (target == this.pauseButton) { + CDAudio.get().pause(); + } else if (target == this.playButton) { + CDAudio.get().play(); + } else if (target == this.prevButton) { + CDAudio.get().prev(); + } else if (target == this.nextButton) { + CDAudio.get().next(); + } else if (target == this.cdBox) { + CDAudio.get().useAutoCD(this.cdBox.getState()); + } else { + if (target != this.midiBox) { + return false; + } + + CDAudio.get().setMidiFlag(this.midiBox.getState()); + } + + return true; + } +} diff --git a/NET/worlds/scape/CDDBConnection.java b/NET/worlds/scape/CDDBConnection.java new file mode 100644 index 0000000..c446d1d --- /dev/null +++ b/NET/worlds/scape/CDDBConnection.java @@ -0,0 +1,75 @@ +package NET.worlds.scape; + +import NET.worlds.network.DNSLookup; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.net.Socket; + +class CDDBConnection { + private Socket sock; + private PrintStream sockOut; + private DataInputStream sockIn; + private boolean readOnly; + private boolean debug; + + public CDDBConnection(CDDBHost host, boolean debug) throws IOException { + this.debug = debug; + if (debug) { + System.out.println("Contacting host " + host); + } + + this.sock = new Socket(DNSLookup.lookup(host.getHost()), host.getPort()); + CDDBLookup.markActivity(); + this.sockOut = new PrintStream(this.sock.getOutputStream(), true); + this.sockIn = new DataInputStream(this.sock.getInputStream()); + String msg = this.recv(); + if (msg.startsWith("200 ")) { + this.readOnly = false; + } else { + if (!msg.startsWith("201 ")) { + throw new IOException("Can't connect to " + host + ": " + msg); + } + + this.readOnly = true; + } + } + + public String command(String command) throws IOException { + this.send(command); + return this.recv(); + } + + public String readBody() throws IOException { + String str = this.recv(); + return str.equals(".") ? null : str; + } + + public void close() { + try { + this.send("quit"); + this.recv(); + this.sock.close(); + } catch (IOException var2) { + } + } + + private void send(String msg) throws IOException { + if (this.debug) { + System.out.println("--> " + msg); + } + + this.sockOut.println(msg); + CDDBLookup.markActivity(); + } + + private String recv() throws IOException { + String msg = this.sockIn.readLine(); + CDDBLookup.markActivity(); + if (this.debug) { + System.out.println("<-- " + msg); + } + + return msg; + } +} diff --git a/NET/worlds/scape/CDDBHash.java b/NET/worlds/scape/CDDBHash.java new file mode 100644 index 0000000..5d9ba86 --- /dev/null +++ b/NET/worlds/scape/CDDBHash.java @@ -0,0 +1,76 @@ +package NET.worlds.scape; + +public class CDDBHash { + public static String hashString(CDTrackInfo tracks) { + String id = Integer.toHexString(hash(tracks)); + int len = id.length(); + if (len >= 8) { + return id; + } else { + String pad = "0"; + + while (++len < 8) { + pad = pad + "0"; + } + + return pad + id; + } + } + + public static String lookupString(CDTrackInfo tracks) { + int numTracks = tracks.getNumTracks(); + String ret = hashString(tracks) + " " + numTracks; + + for (int i = 0; i < numTracks; i++) { + ret = ret + " " + tracks.getStartFrames(i); + } + + return ret + " " + leadOutSecs(tracks); + } + + private static int addDigits(int n) { + String buf = "" + n; + int ret = 0; + + for (int i = 0; i < buf.length(); i++) { + ret += buf.charAt(i) - '0'; + } + + return ret; + } + + private static int leadOutSecs(CDTrackInfo tracks) { + int last = tracks.getNumTracks() - 1; + int omin = tracks.getPosM(last); + int osec = tracks.getPosS(last); + int ofrm = tracks.getPosF(last); + int lmin = tracks.getLenM(last); + int lsec = tracks.getLenS(last); + int lfrm = tracks.getLenF(last); + if (++lfrm == 75) { + lfrm = 0; + if (++lsec == 60) { + lsec = 0; + lmin++; + } + } + + ofrm += lfrm; + osec += ofrm / 75 + lsec; + omin += osec / 60 + lmin; + osec %= 60; + return omin * 60 + osec; + } + + private static int hash(CDTrackInfo tracks) { + int n = 0; + int numTracks = tracks.getNumTracks(); + + for (int i = 0; i < numTracks; i++) { + n += addDigits(tracks.getPosM(i) * 60 + tracks.getPosS(i)); + } + + int t = leadOutSecs(tracks) - tracks.getPosM(0) * 60 - tracks.getPosS(0); + return n % 255 << 24 | t << 8 | numTracks; + } +} diff --git a/NET/worlds/scape/CDDBHost.java b/NET/worlds/scape/CDDBHost.java new file mode 100644 index 0000000..5e7ed15 --- /dev/null +++ b/NET/worlds/scape/CDDBHost.java @@ -0,0 +1,24 @@ +package NET.worlds.scape; + +class CDDBHost { + private String host; + private int port; + + public CDDBHost(String host, int port) { + this.host = host; + this.port = port; + } + + public String getHost() { + return this.host; + } + + public int getPort() { + return this.port; + } + + @Override + public String toString() { + return this.host + ":" + this.port; + } +} diff --git a/NET/worlds/scape/CDDBLookup.java b/NET/worlds/scape/CDDBLookup.java new file mode 100644 index 0000000..0deef54 --- /dev/null +++ b/NET/worlds/scape/CDDBLookup.java @@ -0,0 +1,363 @@ +package NET.worlds.scape; + +import NET.worlds.core.Hashtable; +import NET.worlds.network.URL; +import java.io.IOException; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.NoSuchElementException; +import java.util.StringTokenizer; +import java.util.Vector; + +public class CDDBLookup implements Runnable { + public static final int STATUS_SERVERERROR = -3; + public static final int STATUS_NOTUNIQUE = -2; + public static final int STATUS_NOTFOUND = -1; + public static final int STATUS_LOOKING = 0; + public static final int STATUS_EXACTMATCH = 1; + public static final int STATUS_CLOSEMATCH = 2; + private static final boolean debug = false; + private static final String lookupThreadName = "lookup"; + private static final String siteThreadName = "site"; + private static final String pkgName = "gamma"; + private static final String pkgVersion = "1.0"; + private static final int TIMEOUT = 3000; + private static final String dbName = "home:cdcache.db"; + private static CDDBHost siteHost = new CDDBHost("cddb.cddb.com", 888); + private static Vector sites; + private static Object siteMutex = new Object(); + private static Object knownDisksMutex = new Object(); + private static int lastHostUsed = -1; + private static Hashtable threadActivity = new Hashtable(); + private static Hashtable knownDisks; + private static String userName; + private static String hostName; + private CDTrackInfo tracks; + private String hash; + private CDDBStatus status; + private static final String discTitleKey = "DTITLE="; + private static final String trackTitleKey = "TTITLE"; + + public CDDBLookup(CDTrackInfo tracks) { + if (userName == null) { + userName = System.getProperty("user.name").replace(' ', '_'); + + try { + hostName = InetAddress.getLocalHost().getHostName(); + } catch (UnknownHostException var3) { + hostName = "unknown"; + } + } + + this.tracks = tracks; + this.hash = CDDBHash.hashString(tracks); + if ((this.status = this.dbLookup()) == null) { + this.runThread("lookup"); + } + } + + public String getHash() { + return this.hash; + } + + public CDDiskInfo getDiskInfo() { + return this.getDiskInfo(false); + } + + public synchronized CDDiskInfo getDiskInfo(boolean wait) { + if (wait) { + while (this.status == null) { + try { + this.wait(); + } catch (InterruptedException var3) { + } + } + } + + return this.status != null ? this.status.getDiskInfo() : null; + } + + public int getStatus() { + return this.status != null ? this.status.getStatus() : 0; + } + + @Override + public void run() { + String name = Thread.currentThread().getName(); + if (name.equals("lookup")) { + this.maybeRunSiteThread(); + + for (int i = 0; i < sites.size(); i++) { + synchronized (this) { + Thread t = this.runThread("" + i); + + try { + do { + this.wait(3000L); + } while (this.status == null && this.recentlyActive(t)); + } catch (InterruptedException var13) { + } + + this.forgetThread(t); + if (this.status != null) { + break; + } + + if (i == sites.size() - 1) { + this.status = new CDDBStatus(-3); + this.notifyAll(); + } + } + } + } else if (name.equals("site")) { + Vector v = getSiteList(); + synchronized (siteMutex) { + if (sites == null) { + sites = v; + } + + siteMutex.notifyAll(); + } + } else { + CDDBStatus newStatus = null; + int hostIndex = 0; + + try { + hostIndex = Integer.parseInt(name); + } catch (NumberFormatException var11) { + } + + CDDBHost host = null; + synchronized (siteMutex) { + host = (CDDBHost)sites.elementAt(hostIndex); + } + + newStatus = this.findDiskInfo(host); + synchronized (this) { + if (this.status == null && newStatus != null) { + this.status = newStatus; + if (hostIndex != 0) { + synchronized (siteMutex) { + Object site = sites.elementAt(hostIndex); + sites.removeElementAt(hostIndex); + sites.insertElementAt(site, 0); + } + } + + this.notifyAll(); + } + } + } + } + + private static void addSite(Vector v, String host, int port) { + v.addElement(new CDDBHost(host, port)); + } + + private static void defaultSites() { + sites = new Vector(); + addSite(sites, "cddb.moonsoft.com", 888); + addSite(sites, "cddb.moonsoft.com", 8880); + addSite(sites, "cddb.celestial.com", 888); + addSite(sites, "cddb.sonic.net", 888); + addSite(sites, "sunsite.unc.edu", 888); + addSite(sites, "cddb.netads.com", 888); + addSite(sites, "cddb.mattdm.org", 888); + addSite(sites, "cddb.dartmouth.edu", 888); + } + + private static Vector getSiteList() { + CDDBConnection con = null; + + try { + con = new CDDBConnection(siteHost, false); + con.command("sites").startsWith("210 "); + Vector v = new Vector(); + + String line; + while ((line = con.readBody()) != null) { + StringTokenizer tok = new StringTokenizer(line, " "); + addSite(v, tok.nextToken(), Integer.parseInt(tok.nextToken())); + } + + return v; + } catch (IOException var10) { + } catch (NumberFormatException var11) { + } catch (NoSuchElementException var12) { + } finally { + if (con != null) { + con.close(); + } + } + + return null; + } + + private CDDBStatus findDiskInfo(CDDBHost host) { + CDDBConnection con = null; + + CDDBStatus var9; + try { + con = new CDDBConnection(host, false); + if (!con.command("cddb hello " + userName + " " + hostName + " " + "gamma" + " " + "1.0").startsWith("200 ")) { + return null; + } + + String resp = con.command("cddb query " + CDDBHash.lookupString(this.tracks)); + StringTokenizer t = new StringTokenizer(resp, " "); + String code = t.nextToken(); + if (code.equals("200")) { + return this.dbAdd(new CDDBStatus(1, this.getCDDBEntry(con, t))); + } + + if (code.equals("211")) { + String line = con.readBody(); + int extra = 0; + + while (con.readBody() != null) { + extra++; + } + + if (extra != 0) { + return this.dbAdd(new CDDBStatus(-2)); + } + + return this.dbAdd(new CDDBStatus(2, this.getCDDBEntry(con, new StringTokenizer(line, " ")))); + } + + if (!code.equals("202")) { + return null; + } + + var9 = new CDDBStatus(-1); + } catch (IOException var13) { + return null; + } catch (NoSuchElementException var14) { + return null; + } finally { + if (con != null) { + con.close(); + } + } + + return var9; + } + + private Thread runThread(String name) { + Thread t = new Thread(this, name); + t.setDaemon(true); + t.start(); + return t; + } + + private void maybeRunSiteThread() { + synchronized (siteMutex) { + if (sites == null) { + Thread t = this.runThread("site"); + + try { + do { + siteMutex.wait(3000L); + } while (sites == null && this.recentlyActive(t)); + } catch (InterruptedException var4) { + } + + this.forgetThread(t); + if (sites == null) { + defaultSites(); + } + } + } + } + + private CDDiskInfo getCDDBEntry(CDDBConnection con, StringTokenizer t) { + try { + String cat = t.nextToken(); + String id = t.nextToken(); + if (con.command("cddb read " + cat + " " + id).startsWith("210 ")) { + return this.parseCDDBEntry(cat, con); + } + } catch (IOException var5) { + } catch (NoSuchElementException var6) { + } + + return null; + } + + private CDDiskInfo parseCDDBEntry(String category, CDDBConnection con) throws IOException { + String artist = null; + String title = null; + String[] trackNames = new String[this.tracks.getNumTracks()]; + + for (int i = 0; i < trackNames.length; i++) { + trackNames[i] = ""; + } + + String line; + while ((line = con.readBody()) != null) { + if (line.startsWith("DTITLE=")) { + line = line.substring("DTITLE=".length()); + int slashPos = line.indexOf(47); + if (slashPos == -1) { + artist = title = line.trim(); + } else { + artist = line.substring(0, slashPos).trim(); + title = line.substring(slashPos + 1).trim(); + } + } else if (line.startsWith("TTITLE")) { + int eqIndex = line.indexOf(61); + + try { + int trackNum = Integer.parseInt(line.substring("TTITLE".length(), eqIndex)); + trackNames[trackNum] = trackNames[trackNum] + line.substring(eqIndex + 1); + } catch (NumberFormatException var9) { + } catch (IndexOutOfBoundsException var10) { + } + } + } + + return new CDDiskInfo(artist, title, category, trackNames); + } + + static void markActivity() { + threadActivity.put(Thread.currentThread(), new Long(System.currentTimeMillis())); + } + + private boolean recentlyActive(Thread t) { + Long l = (Long)threadActivity.get(t); + return l != null ? System.currentTimeMillis() - l < 3000L : false; + } + + private void forgetThread(Thread t) { + threadActivity.remove(t); + } + + private CDDBStatus dbAdd(CDDBStatus status) { + synchronized (knownDisksMutex) { + if (knownDisks.get(this.hash) == null) { + knownDisks.put(this.hash, status); + + try { + new Saver(new URL("home:cdcache.db")).save(knownDisks); + } catch (Exception var4) { + } + } + + return status; + } + } + + private CDDBStatus dbLookup() { + synchronized (knownDisksMutex) { + if (knownDisks == null) { + try { + knownDisks = (Hashtable)new Restorer(new URL("home:cdcache.db")).restore(); + } catch (Exception var3) { + knownDisks = new Hashtable(); + } + } + + return (CDDBStatus)knownDisks.get(this.hash); + } + } +} diff --git a/NET/worlds/scape/CDDBStatus.java b/NET/worlds/scape/CDDBStatus.java new file mode 100644 index 0000000..bcf8922 --- /dev/null +++ b/NET/worlds/scape/CDDBStatus.java @@ -0,0 +1,52 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class CDDBStatus implements Persister { + private int status; + private CDDiskInfo diskInfo; + private static Object classCookie = new Object(); + + public CDDBStatus(int status, CDDiskInfo diskInfo) { + this.status = status; + this.diskInfo = diskInfo; + } + + public CDDBStatus(int status) { + this.status = status; + } + + public CDDBStatus() { + } + + public int getStatus() { + return this.status; + } + + public CDDiskInfo getDiskInfo() { + return this.diskInfo; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + s.saveInt(this.status); + s.saveMaybeNull(this.diskInfo); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 1: + this.status = r.restoreInt(); + this.diskInfo = (CDDiskInfo)r.restoreMaybeNull(); + return; + default: + throw new TooNewException(); + } + } + + @Override + public void postRestore(int version) { + } +} diff --git a/NET/worlds/scape/CDDiskInfo.java b/NET/worlds/scape/CDDiskInfo.java new file mode 100644 index 0000000..ebfb220 --- /dev/null +++ b/NET/worlds/scape/CDDiskInfo.java @@ -0,0 +1,94 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class CDDiskInfo implements Persister { + private String artist; + private String title; + private String category; + private String[] trackNames; + private static Object classCookie = new Object(); + + public CDDiskInfo(String artist, String title, String category, String[] trackNames) { + this.artist = artist; + this.title = title; + this.category = category; + this.trackNames = new String[trackNames.length]; + System.arraycopy(trackNames, 0, this.trackNames, 0, trackNames.length); + } + + public CDDiskInfo() { + } + + public String getArtist() { + return this.artist; + } + + public String getTitle() { + return this.title; + } + + public String getCategory() { + return this.category; + } + + public int getNumTracks() { + return this.trackNames.length; + } + + public String getTrackName(int track) { + return this.trackNames[track]; + } + + @Override + public String toString() { + String ret = "Artist: " + this.artist + "\n" + "Title: " + this.title + "\n" + "Category: " + this.category + "\n"; + + for (int i = 0; i < this.trackNames.length; i++) { + ret = ret + "Track " + (i + 1) + ":"; + if (this.trackNames[i] != null) { + ret = ret + this.trackNames[i]; + } + + ret = ret + "\n"; + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + s.saveString(this.artist); + s.saveString(this.title); + s.saveString(this.category); + s.saveInt(this.trackNames.length); + + for (int i = 0; i < this.trackNames.length; i++) { + s.saveString(this.trackNames[i]); + } + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 1: + this.artist = r.restoreString(); + this.title = r.restoreString(); + this.category = r.restoreString(); + this.trackNames = new String[r.restoreInt()]; + + for (int i = 0; i < this.trackNames.length; i++) { + this.trackNames[i] = r.restoreString(); + } + + return; + default: + throw new TooNewException(); + } + } + + @Override + public void postRestore(int version) { + } +} diff --git a/NET/worlds/scape/CDPlayerAction.java b/NET/worlds/scape/CDPlayerAction.java new file mode 100644 index 0000000..0d1955a --- /dev/null +++ b/NET/worlds/scape/CDPlayerAction.java @@ -0,0 +1,258 @@ +package NET.worlds.scape; + +import NET.worlds.console.Main; +import NET.worlds.console.MainCallback; +import NET.worlds.console.MainTerminalCallback; +import java.io.IOException; + +public class CDPlayerAction extends Action implements Runnable, MainCallback, MainTerminalCallback { + private static final boolean DISABLE_ALL = true; + private static final int STATE_INITIAL = 0; + private static final int STATE_WAITING = 1; + private static final int STATE_DONE = 2; + private static int numDrives = -1; + private static CDPlayerAction active; + private String artist; + private String title; + private String hash; + private int start; + private int stop; + private boolean isStopper; + private boolean cancel; + private int state = 0; + private static Object classCookie = new Object(); + + private boolean same(String str1, String str2) { + if (str1 == null) { + return str2 == null; + } else { + return str2 == null ? false : str1.equals(str2); + } + } + + private boolean same(CDPlayerAction other) { + return other != null + && this.same(this.artist, other.artist) + && this.same(this.title, other.title) + && this.same(this.hash, other.hash) + && this.start == other.start + && this.stop == other.stop; + } + + @Override + public Persister trigger(Event e, Persister seqID) { + return null; + } + + @Override + public void run() { + if (numDrives == -1) { + numDrives = getNumDrives(); + } + + for (int i = 0; i < numDrives; i++) { + try { + CDTrackInfo trackInfo = getTrackList(i); + String curHash = null; + if (trackInfo != null) { + curHash = CDDBHash.hashString(trackInfo); + if (curHash.equals(this.hash)) { + this.play(i); + break; + } + } + + if (this.cancel) { + break; + } + } catch (IOException var4) { + } + } + + this.state = 2; + } + + @Override + public void mainCallback() { + } + + @Override + public void terminalCallback() { + this.cancel = true; + if (this.state == 2) { + Main.unregister(this); + } + } + + private void play(int drive) throws IOException { + int driveID; + if ((driveID = openDrive(drive)) != 0) { + playAudio(driveID, this.start, this.stop); + + while (isPlaying(driveID)) { + try { + Thread.sleep(1000L); + } catch (InterruptedException var4) { + } + + if (this.cancel) { + stopAudio(driveID); + break; + } + } + + closeDrive(driveID); + } + } + + public static CDTrackInfo getTrackList(int drive) throws IOException { + CDTrackInfo ret = null; + int driveID; + if ((driveID = openDrive(drive)) != 0) { + ret = getDriveTrackList(driveID); + closeDrive(driveID); + } + + return ret; + } + + public static native int getNumDrives(); + + public static native int getDriveLetterOffset(int var0); + + public static native int openDrive(int var0) throws IOException; + + public static native void closeDrive(int var0) throws IOException; + + public static native void checkDrive(int var0) throws IOException; + + public static native CDTrackInfo getDriveTrackList(int var0) throws IOException; + + public static native void playAudio(int var0, int var1, int var2) throws IOException; + + public static native void stopAudio(int var0) throws IOException; + + public static native void pauseAudio(int var0) throws IOException; + + public static native void resumeAudio(int var0) throws IOException; + + public static native boolean isPlaying(int var0) throws IOException; + + public static native int getPosition(int var0) throws IOException; + + public static native void setNTAutoPlayCode(int var0); + + public static native boolean launchVolumeControlApp(); + + @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 = StringPropertyEditor.make(new Property(this, index, "Artist")); + } else if (mode == 1) { + ret = this.artist; + } else if (mode == 2) { + this.artist = (String)value; + } + break; + case 1: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Title")); + } else if (mode == 1) { + ret = this.title; + } else if (mode == 2) { + this.title = (String)value; + } + break; + case 2: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Disk ID (Edit or Delete to read CD)").allowSetNull()); + } else if (mode == 1) { + if (this.hash == null) { + try { + CDTrackInfo trackList = getTrackList(0); + if (trackList != null) { + this.hash = CDDBHash.hashString(trackList); + } + } catch (IOException var7) { + } + } + + ret = this.hash; + } else if (mode == 2) { + this.hash = (String)value; + } + break; + case 3: + if (mode == 0) { + ret = CDPositionPropertyEditor.make(new Property(this, index, "Start (75ths of a second)"), false); + } else if (mode == 1) { + ret = new Integer(this.start); + } else if (mode == 2) { + this.start = (Integer)value; + } + break; + case 4: + if (mode == 0) { + ret = CDPositionPropertyEditor.make(new Property(this, index, "Stop (75ths of a second)"), true); + } else if (mode == 1) { + ret = new Integer(this.stop); + } else if (mode == 2) { + this.stop = (Integer)value; + } + break; + case 5: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Stop identical CDPlayerAction"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.isStopper); + } else if (mode == 2) { + this.isStopper = (Boolean)value; + } + break; + default: + ret = super.properties(index, offset + 6, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(2, classCookie); + super.saveState(s); + s.saveString(this.artist); + s.saveString(this.title); + s.saveString(this.hash); + s.saveInt(this.start); + s.saveInt(this.stop); + s.saveBoolean(this.isStopper); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 1: + super.restoreState(r); + this.artist = r.restoreString(); + this.title = r.restoreString(); + this.hash = r.restoreString(); + this.start = r.restoreInt(); + this.stop = r.restoreInt(); + break; + case 2: + super.restoreState(r); + this.artist = r.restoreString(); + this.title = r.restoreString(); + this.hash = r.restoreString(); + this.start = r.restoreInt(); + this.stop = r.restoreInt(); + this.isStopper = r.restoreBoolean(); + break; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/CDPositionEditorDialog.java b/NET/worlds/scape/CDPositionEditorDialog.java new file mode 100644 index 0000000..1762758 --- /dev/null +++ b/NET/worlds/scape/CDPositionEditorDialog.java @@ -0,0 +1,33 @@ +package NET.worlds.scape; + +import java.util.Vector; + +class CDPositionEditorDialog extends FieldWithListEditorDialog { + Property property; + + CDPositionEditorDialog(EditTile parent, String title, Property property, Vector trackList) { + super(parent, title, trackList); + this.property = property; + this.ready(); + } + + @Override + protected String getValue() { + return "" + this.property.get(); + } + + @Override + protected boolean setValue(String text) { + int index = text.indexOf("#"); + if (index != -1) { + text = text.substring(0, index).trim(); + } + + try { + this.parent.addUndoableSet(this.property, new Integer(text)); + return true; + } catch (NumberFormatException var4) { + return false; + } + } +} diff --git a/NET/worlds/scape/CDPositionPropertyEditor.java b/NET/worlds/scape/CDPositionPropertyEditor.java new file mode 100644 index 0000000..1fe5453 --- /dev/null +++ b/NET/worlds/scape/CDPositionPropertyEditor.java @@ -0,0 +1,42 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.PolledDialog; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.Vector; + +public class CDPositionPropertyEditor extends PropEditor { + private boolean ending; + + private CDPositionPropertyEditor(Property property, boolean ending) { + super(property); + this.ending = ending; + } + + @Override + public PolledDialog edit(EditTile parent, String title) { + CDTrackInfo trackInfo = null; + + try { + trackInfo = CDPlayerAction.getTrackList(0); + } catch (IOException var9) { + } + + Vector trackList = new Vector(); + if (trackInfo != null) { + for (int i = 0; i < trackInfo.getNumTracks(); i++) { + int frames = this.ending ? trackInfo.getEndFrames(i) : trackInfo.getStartFrames(i); + String type = this.ending ? Console.message("End") : Console.message("Start"); + Object[] arguments = new Object[]{new String("" + frames), new String(type), new String("" + (i + 1))}; + trackList.addElement(MessageFormat.format(Console.message("of-track"), arguments)); + } + } + + return new CDPositionEditorDialog(parent, title, this.property, trackList); + } + + public static Property make(Property property, boolean ending) { + return property.setEditor(new CDPositionPropertyEditor(property, ending)); + } +} diff --git a/NET/worlds/scape/CDTrackInfo.java b/NET/worlds/scape/CDTrackInfo.java new file mode 100644 index 0000000..e3c35d9 --- /dev/null +++ b/NET/worlds/scape/CDTrackInfo.java @@ -0,0 +1,82 @@ +package NET.worlds.scape; + +public class CDTrackInfo { + private int[] pos; + private int[] len; + + public CDTrackInfo(int numTracks) { + this.pos = new int[numTracks]; + this.len = new int[numTracks]; + } + + public int getNumTracks() { + return this.pos.length; + } + + public int getStartFrames(int track) { + return this.getPosM(track) * 60 * 75 + this.getPosS(track) * 75 + this.getPosF(track); + } + + public int getEndFrames(int track) { + return track == this.pos.length - 1 + ? this.getStartFrames(track) + this.getLenM(track) * 60 * 75 + this.getLenS(track) * 75 + this.getLenF(track) + : this.getStartFrames(track + 1) - 1; + } + + public int getPosM(int track) { + return minutes(this.pos[track]); + } + + public int getPosS(int track) { + return seconds(this.pos[track]); + } + + public int getPosF(int track) { + return frames(this.pos[track]); + } + + public int getLenM(int track) { + return minutes(this.len[track]); + } + + public int getLenS(int track) { + return seconds(this.len[track]); + } + + public int getLenF(int track) { + return frames(this.len[track]); + } + + private static int minutes(int packed) { + return packed & 0xFF; + } + + private static int seconds(int packed) { + return packed >> 8 & 0xFF; + } + + private static int frames(int packed) { + return packed >> 16 & 0xFF; + } + + private static String format2(int val) { + String result = ""; + if (val < 10) { + result = "0"; + } + + return result + val; + } + + private static String format(int packed) { + return minutes(packed) + ":" + format2(seconds(packed)) + ":" + format2(frames(packed)); + } + + public void dump() { + System.out.println("Tracks: " + this.pos.length); + + for (int i = 0; i < this.pos.length; i++) { + System.out.println("Track " + i + " " + "start " + format(this.pos[i]) + " length " + format(this.len[i])); + } + } +} diff --git a/NET/worlds/scape/CallbackPropertyOperator.java b/NET/worlds/scape/CallbackPropertyOperator.java new file mode 100644 index 0000000..55c2418 --- /dev/null +++ b/NET/worlds/scape/CallbackPropertyOperator.java @@ -0,0 +1,44 @@ +package NET.worlds.scape; + +import NET.worlds.console.Main; +import NET.worlds.console.MainCallback; + +public class CallbackPropertyOperator implements MainCallback { + private Property prop; + private int func; + private Object value; + private boolean done; + + CallbackPropertyOperator(Property prop, int func, Object value) { + this.prop = prop; + this.func = func; + this.value = value; + + assert !Main.isMainThread(); + + Main.register(this); + } + + synchronized Object getValue() { + while (!this.done) { + try { + this.wait(); + } catch (InterruptedException var2) { + } + } + + return this.value; + } + + @Override + public synchronized void mainCallback() { + this.modify(); + Main.unregister(this); + this.notify(); + } + + private void modify() { + this.value = this.prop.safeOperate(this.func, this.value); + this.done = true; + } +} diff --git a/NET/worlds/scape/Camera.java b/NET/worlds/scape/Camera.java new file mode 100644 index 0000000..61addea --- /dev/null +++ b/NET/worlds/scape/Camera.java @@ -0,0 +1,357 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.Gamma; +import NET.worlds.console.RenderCanvas; +import NET.worlds.console.Window; +import NET.worlds.network.URL; +import java.io.IOException; + +public class Camera extends WObject implements MouseButtonHandler, MouseEnterHandler, MouseExitHandler, MouseMoveHandler, IncrementalRestorer, URLSelf { + private RenderCanvas canvas; + static final int CAMERA_SIZE = 20; + private boolean mouseIsOverClickable = false; + private boolean validMouseCoordinates = false; + private float validMouseX = -1.0F; + private float validMouseY = -1.0F; + private static WObject cachedWObject = null; + private static float cachedMouseX = -1.0F; + private static float cachedMouseY = -1.0F; + private int cameraID; + private int cameraMode; + private boolean alwaysClearBackground; + private float xPick; + private float yPick; + private Point3Temp unpickSpot; + private WObject pickedObj; + public Transform lookAround = Transform.make(); + private static final int isBotMode = 0; + private static final int isPickingMode = 1; + private static final int isDrawingMode = 2; + private static final int isThroughMode = 4; + static WObject[] downWentTo = new WObject[3]; + static Point3 downAt = new Point3(); + private static Object classCookie = new Object(); + public float xForRoomPreAndPostRender; + public float yForRoomPreAndPostRender; + public float zForRoomPreAndPostRender; + public float dForRoomPreAndPostRender; + + static { + cameraNativeInit(); + } + + public Camera() { + this.setVisible(false); + } + + public static native void cameraNativeInit(); + + public Window getWindow() { + return this.canvas == null ? null : this.canvas.getWindow(); + } + + @Override + public BoundBoxTemp getBoundBox() { + Transform t = this.getObjectToWorldMatrix(); + Point3Temp p = t.getPosition(); + t.recycle(); + Point3Temp q = Point3Temp.make(p).minus(20.0F); + return BoundBoxTemp.make(q, p.plus(20.0F)); + } + + public static WObject getMousePickWObject() { + return cachedWObject; + } + + public static float getMousePickX() { + return cachedMouseX; + } + + public static float getMousePickY() { + return cachedMouseY; + } + + protected WObject updateView(Window w, int mode) { + Room r = this.getRoom(); + if (!this.hasClump() && r != null) { + r.aboutToDraw(); + } + + Transform t = null; + SuperRoot o = this.getOwner(); + Pilot pilot = null; + if (o instanceof Pilot && o.getOwner() == r) { + pilot = (Pilot)o; + if (r != null) { + pilot.aboutToDraw(); + this.detach(); + r.add(this); + t = this.getTransform(); + Point3Temp motion = t.getPosition().times(pilot).minus(pilot.getPosition()); + this.post(pilot); + if (motion.squaredLength() > 1.0F) { + this.moveBy(Point3Temp.make().minus(motion)); + boolean pBumpable = pilot.getBumpable(); + pilot.setBumpable(false); + this.moveThrough(motion); + pilot.setBumpable(pBumpable); + Room r2 = this.getRoom(); + if (!this.hasClump() && r2 != null && r2 != r) { + r2.aboutToDraw(); + } + } + } + } + + WObject result = this.renderScene(w.getHwnd(), w.fullWidth(), w.fullHeight(), mode, pilot); + if (t != null) { + this.detach(); + pilot.add(this); + this.setTransform(t); + t.recycle(); + } + + return result; + } + + public void renderToCanvas() { + assert this.cameraID == 0; + + if (this.isActive()) { + Window w = this.getWindow(); + if (w != null) { + if (this.validMouseCoordinates) { + this.xPick = this.validMouseX; + this.yPick = this.validMouseY; + WObject obj = this.updateView(w, 7); + boolean toggleMouseCursor = false; + cachedWObject = obj; + cachedMouseX = this.validMouseX; + cachedMouseY = this.validMouseY; + if (obj != null && obj.acceptsLeftClicks()) { + if (!this.mouseIsOverClickable) { + this.mouseIsOverClickable = true; + toggleMouseCursor = true; + } + } else if (this.mouseIsOverClickable) { + this.mouseIsOverClickable = false; + toggleMouseCursor = true; + } + + if (toggleMouseCursor) { + URL newURL = null; + if (this.mouseIsOverClickable) { + newURL = URL.make("home:HAND-M.CUR"); + } else { + newURL = URL.make("system:DEFAULT_CURSOR"); + } + + Console.getActive().getCursor().setURL(newURL); + } + } else { + this.updateView(w, 6); + } + } + } + } + + public native void nDrawText(String var1, int var2, int var3, int var4, int var5); + + public RenderCanvas getCanvas() { + return this.canvas; + } + + public void setCanvas(RenderCanvas c) { + this.canvas = c; + } + + public void setAlwaysClearBackground(boolean in) { + this.alwaysClearBackground = in; + } + + public Point3Temp lastPickSpot() { + return this.unpickSpot; + } + + public void transferFrom(Camera target) { + this.lookAround.setTransform(target.lookAround); + } + + synchronized native WObject renderScene(int var1, int var2, int var3, int var4, Pilot var5); + + public WObject getObjectAt(float x, float y, boolean pickingThrough, Point3Temp pt) { + Window w = this.getWindow(); + if (w == null) { + return null; + } else { + this.xPick = x; + this.yPick = y; + this.unpickSpot = null; + WObject obj = this.updateView(w, 1 + (pickingThrough ? 4 : 0)); + if (pt != null && this.unpickSpot != null) { + pt.copy(this.unpickSpot); + } + + return obj; + } + } + + private void sendClick(WObject obj, MouseButtonEvent e) { + WObject oldTarget = e.target; + e.target = obj; + obj.deliver(e); + e.target = oldTarget; + } + + @Override + public boolean handle(MouseButtonEvent e) { + WObject obj = null; + int which = 3; + if (e.key == '\ue301') { + which = 0; + } else if (e.key == '\ue302') { + which = 1; + } else if (e.key == '\ue304') { + which = 2; + } + + assert which != 3; + + if (e instanceof MouseUpEvent) { + obj = downWentTo[which]; + downWentTo[which] = null; + } else { + Window w = this.getWindow(); + if (w != null && !w.getDeltaMode()) { + if (which == 1 && Gamma.getShaper() != null) { + obj = this.getObjectAt(e.x, e.y, false, null); + if (obj != null) { + obj.rightMenu(); + } + } else { + obj = this.getObjectAt(e.x, e.y, true, downAt); + } + + downWentTo[which] = obj; + } + } + + if (obj != null) { + if (which == 0 && e instanceof MouseUpEvent) { + obj.doAction(Console.getActive().getDefaultAction(), e); + } + + this.sendClick(obj, e); + } + + return false; + } + + @Override + public boolean handle(MouseEnterEvent e) { + if (e != null) { + URL defaultCursor = URL.make("system:DEFAULT_CURSOR"); + Console.getActive().getCursor().setURL(defaultCursor); + this.mouseIsOverClickable = false; + this.validMouseCoordinates = true; + this.validMouseX = e.x; + this.validMouseY = e.y; + cachedWObject = null; + cachedMouseX = -1.0F; + cachedMouseY = -1.0F; + } + + return false; + } + + @Override + public boolean handle(MouseExitEvent e) { + if (e != null) { + URL defaultCursor = URL.make("system:DEFAULT_CURSOR"); + Console.getActive().getCursor().setURL(defaultCursor); + this.mouseIsOverClickable = false; + this.validMouseCoordinates = false; + this.validMouseX = -1.0F; + this.validMouseY = -1.0F; + cachedWObject = null; + cachedMouseX = -1.0F; + cachedMouseY = -1.0F; + } + + return false; + } + + @Override + public boolean handle(MouseMoveEvent e) { + if (e != null) { + this.validMouseX = e.x; + this.validMouseY = e.y; + } + + return false; + } + + @Override + public Object properties(int index, int offset, int mode, Object value) throws NoSuchPropertyException { + Object ret = null; + int var10000 = index - offset; + return super.properties(index, offset + 0, mode, value); + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(2, classCookie); + super.saveState(s); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + case 2: + super.restoreState(r); + break; + case 1: + super.restoreState(r); + r.restoreFloat(); + r.restore(); + r.restore(); + break; + default: + throw new TooNewException(); + } + } + + @Override + public int incRestore(int state, Restorer r, URLSelfLoader p) throws Exception { + if (state == 0) { + this.restoreState(r); + } + + if (r.version() != 3) { + return -1; + } else { + if (state == 0) { + p.otemp1 = r.restore(false); + } + + World w = (World)p.otemp1; + if (state == 0) { + w.setSourceURL(this.getSourceURL()); + } + + return w.incRestore(state, r, p); + } + } + + @Override + public void incRef() { + assert false; + } + + @Override + public void decRef() { + assert false; + } +} diff --git a/NET/worlds/scape/CameraHeightAction.java b/NET/worlds/scape/CameraHeightAction.java new file mode 100644 index 0000000..46c40db --- /dev/null +++ b/NET/worlds/scape/CameraHeightAction.java @@ -0,0 +1,75 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class CameraHeightAction extends Action { + public float newEyeHeight = 0.0F; + private static Object classCookie = new Object(); + + @Override + public Persister trigger(Event e, Persister seqID) { + Object owner = this.getOwner(); + if (owner != null && owner instanceof WObject) { + WObject o = (WObject)owner; + Pilot pilot = Pilot.getActive(); + if (pilot == null) { + return null; + } else if (pilot.getRoom() != o.getRoom()) { + return null; + } else { + if (pilot instanceof HoloPilot) { + HoloPilot hp = (HoloPilot)pilot; + hp.setEyeHeight(this.newEyeHeight); + } + + return null; + } + } else { + return null; + } + } + + @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 = FloatPropertyEditor.make(new Property(this, index, "New Eye Height")); + } else if (mode == 1) { + ret = new Float(this.newEyeHeight); + } else if (mode == 2) { + this.newEyeHeight = (Float)value; + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public String toString() { + return super.toString() + "[New Eye Height: " + this.newEyeHeight + "]"; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + s.saveFloat(this.newEyeHeight); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this.newEyeHeight = r.restoreFloat(); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/ChangeAvatarDialog.java b/NET/worlds/scape/ChangeAvatarDialog.java new file mode 100644 index 0000000..9843b44 --- /dev/null +++ b/NET/worlds/scape/ChangeAvatarDialog.java @@ -0,0 +1,60 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.DialogReceiver; +import NET.worlds.console.ImageButtons; +import NET.worlds.console.ImageButtonsCallback; +import NET.worlds.console.PolledDialog; +import NET.worlds.core.IniFile; +import java.awt.Component; +import java.awt.Rectangle; +import java.awt.Window; +import java.text.MessageFormat; + +public class ChangeAvatarDialog extends PolledDialog implements ImageButtonsCallback { + private ImageButtons ib; + + public ChangeAvatarDialog(Window parent, DialogReceiver receiver, String name) { + super(parent, receiver, Console.message("Change-Avatar"), false); + this.setAlignment(1); + Rectangle[] rects = new Rectangle[2]; + int yesX = IniFile.override().getIniInt("changeavYesX", 39); + int yesY = IniFile.override().getIniInt("changeavYesY", 23); + int yesW = IniFile.override().getIniInt("changeavYesW", 48); + int yesH = IniFile.override().getIniInt("changeavYesH", 18); + rects[0] = new Rectangle(yesX, yesY, yesW, yesH); + int noX = IniFile.override().getIniInt("changeavNoX", 96); + int noY = IniFile.override().getIniInt("changeavNoY", 23); + int noW = IniFile.override().getIniInt("changeavNoW", 42); + int noH = IniFile.override().getIniInt("changeavnoH", 18); + rects[1] = new Rectangle(noX, noY, noW, noH); + Object[] arguments = new Object[]{new String(name)}; + this.ib = new ChangeAvatarImageButtons( + IniFile.override().getIniString("changeAvDlg", Console.message("changeav.gif")), + rects, + this, + MessageFormat.format(Console.message("Change-avatar-to"), arguments) + ); + this.ready(); + } + + @Override + protected void build() { + this.add("Center", this.ib); + } + + @Override + public Object imageButtonsCallback(Component who, int which) { + this.done(which == 0); + return null; + } + + @Override + public boolean keyDown(java.awt.Event event, int key) { + if (key == 27) { + return this.done(false); + } else { + return key == 10 ? this.done(true) : super.keyDown(event, key); + } + } +} diff --git a/NET/worlds/scape/ChangeAvatarImageButtons.java b/NET/worlds/scape/ChangeAvatarImageButtons.java new file mode 100644 index 0000000..56bd29e --- /dev/null +++ b/NET/worlds/scape/ChangeAvatarImageButtons.java @@ -0,0 +1,42 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.ImageButtons; +import NET.worlds.console.ImageButtonsCallback; +import java.awt.Color; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Rectangle; + +class ChangeAvatarImageButtons extends ImageButtons { + private static final int textBoxX = 0; + private static final int textBoxY = 0; + private static final int textBoxW = 177; + private static final int textBoxH = 23; + private static Font font = new Font(Console.message("AvatarFont"), 0, 12); + private static int textWidth; + private static int textX; + private static int textY; + private String text; + + public ChangeAvatarImageButtons(String texture, Rectangle[] rects, ImageButtonsCallback cb, String text) { + super(texture, rects, cb); + this.text = text; + } + + @Override + public void paint(Graphics g) { + super.paint(g); + g.setFont(font); + g.setColor(Color.white); + if (textWidth == 0) { + FontMetrics fm = g.getFontMetrics(); + textWidth = fm.stringWidth(this.text); + textX = (177 - textWidth) / 2; + textY = 23 - (23 - fm.getAscent()) / 2; + } + + g.drawString(this.text, textX, textY); + } +} diff --git a/NET/worlds/scape/CheckboxEditorDialog.java b/NET/worlds/scape/CheckboxEditorDialog.java new file mode 100644 index 0000000..e8eb818 --- /dev/null +++ b/NET/worlds/scape/CheckboxEditorDialog.java @@ -0,0 +1,64 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.OkCancelDialog; +import java.awt.Checkbox; +import java.awt.CheckboxGroup; +import java.awt.Dimension; +import java.awt.GridBagConstraints; + +public abstract class CheckboxEditorDialog extends OkCancelDialog { + private CheckboxGroup group = new CheckboxGroup(); + private Checkbox[] choices; + private String[] labels; + protected EditTile parent; + + protected CheckboxEditorDialog(EditTile parent, String title, String[] labels) { + super(Console.getFrame(), parent, title); + this.labels = labels; + this.parent = parent; + } + + @Override + protected void build() { + this.choices = new Checkbox[this.labels.length]; + GridBagConstraints c = new GridBagConstraints(); + c.weightx = 1.0; + c.weighty = 1.0; + c.gridwidth = 0; + + for (int i = 0; i < this.labels.length; i++) { + this.add(this.gbag, this.choices[i] = new Checkbox(this.labels[i], this.group, false), c); + } + + super.build(); + } + + protected abstract int getValue(); + + protected abstract void setValue(int var1); + + @Override + protected boolean setValue() { + Checkbox selected = this.group.getCurrent(); + + for (int i = 0; i < this.choices.length; i++) { + if (this.choices[i] == selected) { + this.setValue(i); + return true; + } + } + + return false; + } + + @Override + public void show() { + Dimension mySize = this.size(); + this.initialSize(mySize.width < 160 ? 160 : mySize.width, mySize.height < 120 ? 120 : mySize.height); + super.show(); + int choice = this.getValue(); + this.choices[choice].requestFocus(); + this.choices[choice].setState(true); + } +} diff --git a/NET/worlds/scape/ClassProperty.java b/NET/worlds/scape/ClassProperty.java new file mode 100644 index 0000000..59229cc --- /dev/null +++ b/NET/worlds/scape/ClassProperty.java @@ -0,0 +1,7 @@ +package NET.worlds.scape; + +public class ClassProperty extends Property { + public ClassProperty(Properties owner, int index, String className) { + super(owner, index, "Class " + className + " (obsolete; for backwards compatibility)"); + } +} diff --git a/NET/worlds/scape/ClickEventHandler.java b/NET/worlds/scape/ClickEventHandler.java new file mode 100644 index 0000000..01eae57 --- /dev/null +++ b/NET/worlds/scape/ClickEventHandler.java @@ -0,0 +1,13 @@ +package NET.worlds.scape; + +import java.awt.Component; +import java.awt.Point; + +public interface ClickEventHandler { + int DOWN = 1; + int UP = 2; + int META = 4; + int DRAG = 8; + + void clickEvent(Component var1, Point var2, int var3); +} diff --git a/NET/worlds/scape/ClickSensor.java b/NET/worlds/scape/ClickSensor.java new file mode 100644 index 0000000..aab6f0d --- /dev/null +++ b/NET/worlds/scape/ClickSensor.java @@ -0,0 +1,359 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.network.URL; +import java.io.DataInputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.StringTokenizer; +import java.util.Vector; + +public class ClickSensor extends Sensor implements MouseDownHandler, MouseUpHandler, BGLoaded { + private static final int clickTime = 750; + public static final int CENTER = 4; + public static final int RIGHT = 2; + public static final int LEFT = 1; + public static final int ANY = 7; + protected long mouseDownTime = 0L; + protected int keyToCheck = 1; + protected boolean waitForUp = false; + protected URL config = null; + transient int width; + transient int height; + transient ClickSensor.Area[] configTable; + private static Object classCookie = new Object(); + + public ClickSensor(Action a, char whichButton) { + this(a, (int)whichButton); + } + + public ClickSensor(Action a, int whichButton) { + this.keyToCheck = whichButton & 7; + if (a != null) { + this.addAction(a); + } + } + + public ClickSensor(Action a) { + this(a, 7); + } + + public ClickSensor() { + } + + public int getWhichButton() { + return this.keyToCheck; + } + + public boolean getWaitForUp() { + return this.waitForUp; + } + + public void setWhichButton(int which) { + assert which >= 0 && which <= 7; + + this.keyToCheck = which; + } + + public void setWaitForUp(boolean wait) { + this.waitForUp = wait; + } + + @Override + public boolean handle(MouseDownEvent e) { + if (this.keyToCheck == 7 || (e.key & this.keyToCheck) != 0) { + if (this.waitForUp) { + this.mouseDownTime = System.currentTimeMillis(); + } else { + this.trigger(e); + } + } + + return true; + } + + @Override + public boolean handle(MouseUpEvent e) { + if (this.waitForUp && (this.keyToCheck == 7 || (e.key & this.keyToCheck) != 0) && System.currentTimeMillis() - this.mouseDownTime < 750L) { + this.trigger(e); + } + + return true; + } + + public void triggerAction(String actionNamePrefix, Vector props, Event event) { + int len = this.actions.size(); + + for (int i = 0; i < len; i++) { + Action a = this.actions.elementAt(i); + if (a.getName().regionMatches(0, actionNamePrefix, 0, actionNamePrefix.length())) { + len = props.size(); + + for (int var10 = 0; var10 < len; var10 += 2) { + String prop = (String)props.elementAt(var10); + String val = (String)props.elementAt(var10 + 1); + SetPropertyAction.propHelper(2, val, prop, a); + } + + RunningActionHandler.trigger(a, this.getWorld(), event); + return; + } + } + } + + @Override + public void trigger(Event event) { + if (this.configTable != null && this.getOwner() instanceof WObject) { + WObject w = (WObject)this.getOwner(); + Transform t = w.getObjectToWorldMatrix().invert(); + Point3Temp p = Point3Temp.make(Camera.downAt).times(t); + p.x = p.x * this.width; + p.z = p.z * this.height; + + for (int i = 0; i < this.configTable.length; i++) { + ClickSensor.Area a = this.configTable[i]; + if (p.x > a.x && p.z > a.y && p.x - a.x < a.w && p.z - a.y < a.h) { + this.triggerAction(a.actionNamePrefix, a.props, event); + } + } + + t.recycle(); + } else { + super.trigger(event); + } + } + + @Override + public Object asyncBackgroundLoad(String localName, URL remoteURL) { + return localName; + } + + @Override + public boolean syncBackgroundLoad(Object obj, URL remoteURL) { + if (obj != null) { + this.loadConfig((String)obj); + } + + return false; + } + + @Override + public Room getBackgroundLoadRoom() { + return null; + } + + public static String getString(StringTokenizer st) { + String s = st.nextToken(); + if (s.length() > 0 && s.charAt(0) == '"') { + StringBuffer sb = new StringBuffer(s.substring(1)); + + while (sb.charAt(sb.length() - 1) != '"') { + sb.append(" "); + sb.append(st.nextToken()); + } + + sb.setLength(sb.length() - 1); + s = sb.toString(); + } + + return s; + } + + public void loadConfig(String name) { + ClickSensor.Area[] result = (ClickSensor.Area[])null; + DataInputStream in = null; + int line = 1; + + try { + in = new DataInputStream(new FileInputStream(name)); + StringTokenizer st = new StringTokenizer(in.readLine()); + int numLines = Integer.parseInt(st.nextToken()); + this.width = Integer.parseInt(st.nextToken()); + this.height = Integer.parseInt(st.nextToken()); + result = new ClickSensor.Area[numLines]; + + for (int i = 0; i < numLines; i++) { + ClickSensor.Area a = new ClickSensor.Area(); + line++; + st = new StringTokenizer(in.readLine()); + a.x = Integer.parseInt(st.nextToken()); + a.y = Integer.parseInt(st.nextToken()); + a.w = Integer.parseInt(st.nextToken()); + a.h = Integer.parseInt(st.nextToken()); + a.actionNamePrefix = getString(st); + Vector props = new Vector(); + + while (st.hasMoreTokens()) { + props.addElement(getString(st)); + props.addElement(getString(st)); + } + + a.props = props; + result[i] = a; + } + + this.configTable = result; + } catch (Exception var18) { + Object[] arguments = new Object[]{new String(name), new String("" + line)}; + Console.println(MessageFormat.format(Console.message("Error-config-table"), arguments)); + } finally { + try { + if (in != null) { + in.close(); + } + } catch (IOException var17) { + } + } + } + + @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 = BooleanPropertyEditor.make(new Property(this, index, "Left Button"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean((this.keyToCheck & 1) != 0); + } else if (mode == 2) { + if ((Boolean)value) { + this.keyToCheck |= 1; + } else { + this.keyToCheck &= -2; + } + } + break; + case 1: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Right Button"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean((this.keyToCheck & 2) != 0); + } else if (mode == 2) { + if ((Boolean)value) { + this.keyToCheck |= 2; + } else { + this.keyToCheck &= -3; + } + } + break; + case 2: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Center Button"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean((this.keyToCheck & 4) != 0); + } else if (mode == 2) { + if ((Boolean)value) { + this.keyToCheck |= 4; + } else { + this.keyToCheck &= -5; + } + } + break; + case 3: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Wait for up-click"), "Down", "Up"); + } else if (mode == 1) { + ret = new Boolean(this.waitForUp); + } else if (mode == 2) { + this.waitForUp = (Boolean)value; + } + break; + case 4: + if (mode == 0) { + ret = URLPropertyEditor.make(new Property(this, index, "Config File").allowSetNull(), "clk"); + } else if (mode == 1) { + ret = this.config; + } else if (mode == 2) { + this.config = (URL)value; + if (this.config != null) { + BackgroundLoader.get(this, this.config); + } else { + this.configTable = null; + } + } + break; + default: + ret = super.properties(index, offset + 5, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(2, classCookie); + super.saveState(s); + s.saveInt(this.keyToCheck); + s.saveBoolean(this.waitForUp); + URL.save(s, this.config); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this.keyToCheck = (char)r.restoreInt(); + break; + case 1: + super.restoreState(r); + this.keyToCheck = (char)r.restoreInt(); + this.waitForUp = r.restoreBoolean(); + break; + case 2: + super.restoreState(r); + this.keyToCheck = (char)r.restoreInt(); + this.waitForUp = r.restoreBoolean(); + this.config = URL.restore(r); + break; + default: + throw new TooNewException(); + } + + if (this.config == null) { + this.configTable = null; + } else { + BackgroundLoader.get(this, this.config); + } + } + + @Override + public String toString() { + String rval = super.toString() + "["; + if ((this.keyToCheck & 1) != 0) { + rval = rval + "*"; + } else { + rval = rval + " "; + } + + if ((this.keyToCheck & 4) != 0) { + rval = rval + "*"; + } else { + rval = rval + " "; + } + + if ((this.keyToCheck & 2) != 0) { + rval = rval + "*"; + } else { + rval = rval + " "; + } + + if (this.waitForUp) { + rval = rval + "u]"; + } else { + rval = rval + "d]"; + } + + return rval; + } + + class Area { + int x; + int y; + int w; + int h; + String actionNamePrefix; + Vector props; + } +} diff --git a/NET/worlds/scape/ClickWidget.java b/NET/worlds/scape/ClickWidget.java new file mode 100644 index 0000000..e234aa9 --- /dev/null +++ b/NET/worlds/scape/ClickWidget.java @@ -0,0 +1,17 @@ +package NET.worlds.scape; + +abstract class ClickWidget extends WidgetButton { + ClickWidget(ToolBar toolbar, String name, String prompt) { + super(toolbar, name, prompt); + } + + @Override + public boolean usesDrag() { + return false; + } + + @Override + public boolean available() { + return true; + } +} diff --git a/NET/worlds/scape/ClipboardEntry.java b/NET/worlds/scape/ClipboardEntry.java new file mode 100644 index 0000000..86a2d46 --- /dev/null +++ b/NET/worlds/scape/ClipboardEntry.java @@ -0,0 +1,44 @@ +package NET.worlds.scape; + +class ClipboardEntry { + private SuperRoot original; + private byte[] copy; + private boolean canPasteOriginal; + + boolean copy(SuperRoot obj) { + this.original = obj; + this.copy = obj.getByteCopy(); + this.canPasteOriginal = false; + return this.copy != null; + } + + boolean cut(SuperRoot obj) { + boolean var3; + try { + var3 = this.copy(obj); + } finally { + this.canPasteOriginal = true; + } + + return var3; + } + + SuperRoot paste() { + if (this.copy != null) { + if (this.canPasteOriginal) { + this.canPasteOriginal = false; + return this.original; + } else { + return SuperRoot.getCopyFromBytes(this.copy); + } + } else { + return null; + } + } + + void unPaste(SuperRoot obj) { + if (obj == this.original) { + this.canPasteOriginal = true; + } + } +} diff --git a/NET/worlds/scape/ColorAttribute.java b/NET/worlds/scape/ColorAttribute.java new file mode 100644 index 0000000..8255062 --- /dev/null +++ b/NET/worlds/scape/ColorAttribute.java @@ -0,0 +1,81 @@ +package NET.worlds.scape; + +import java.awt.Color; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class ColorAttribute extends Attribute { + private Color value = Color.black; + private static Object classCookie = new Object(); + + public ColorAttribute(int attrID) { + super(attrID); + } + + public ColorAttribute() { + } + + public void set(Color x) { + this.value = x; + this.noteChange(); + } + + public Color get() { + return this.value; + } + + @Override + public void generateNetData(DataOutputStream s) throws IOException { + s.writeInt(this.value.getRGB()); + } + + @Override + public void setFromNetData(DataInputStream ds, int len) throws IOException { + this.value = new Color(ds.readInt()); + } + + @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 = ColorPropertyEditor.make(new Property(this, index, "value")); + } else if (mode == 1) { + ret = this.get(); + } else if (mode == 2) { + this.set((Color)value); + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + s.saveInt(this.value.getRGB()); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this.value = new Color(r.restoreInt()); + return; + default: + throw new TooNewException(); + } + } + + @Override + public String toString() { + return super.toString() + "[" + this.get() + "]"; + } +} diff --git a/NET/worlds/scape/ColorEditorDialog.java b/NET/worlds/scape/ColorEditorDialog.java new file mode 100644 index 0000000..99c23a6 --- /dev/null +++ b/NET/worlds/scape/ColorEditorDialog.java @@ -0,0 +1,68 @@ +package NET.worlds.scape; + +import java.awt.Color; +import java.util.StringTokenizer; + +class ColorEditorDialog extends ListEditorDialog { + protected Property property; + protected Color c; + + ColorEditorDialog(EditTile parent, String title, Property property) { + super(parent, title); + this.property = property; + this.ready(); + } + + @Override + protected void build() { + this.c = (Color)this.property.get(); + super.build(); + } + + @Override + protected int getElementCount() { + return 3; + } + + @Override + protected String getElement(int index) { + if (this.c == null) { + return "null"; + } else { + switch (index) { + case 0: + return "" + this.c.getRed(); + case 1: + return "" + this.c.getGreen(); + default: + return "" + this.c.getBlue(); + } + } + } + + @Override + protected boolean setElements(StringTokenizer e) { + int[] c = new int[3]; + int count = 0; + + while (e.hasMoreTokens()) { + try { + int tmp = Integer.valueOf(e.nextToken()); + if (tmp < 0 || tmp > 255) { + return false; + } + + c[count++] = tmp; + } catch (Exception var5) { + return false; + } + } + + if (count == 3) { + this.parent.addUndoableSet(this.property, new Color(c[0], c[1], c[2])); + return true; + } else { + return false; + } + } +} diff --git a/NET/worlds/scape/ColorPropertyEditor.java b/NET/worlds/scape/ColorPropertyEditor.java new file mode 100644 index 0000000..2abef3c --- /dev/null +++ b/NET/worlds/scape/ColorPropertyEditor.java @@ -0,0 +1,19 @@ +package NET.worlds.scape; + +import NET.worlds.console.PolledDialog; + +public class ColorPropertyEditor extends PropEditor { + private ColorPropertyEditor(Property property) { + super(property); + } + + @Override + public PolledDialog edit(EditTile parent, String title) { + return new ColorEditorDialog(parent, title, this.property); + } + + public static Property make(Property property) { + property.setPropertyType(4); + return property.setEditor(new ColorPropertyEditor(property)); + } +} diff --git a/NET/worlds/scape/CopyWidget.java b/NET/worlds/scape/CopyWidget.java new file mode 100644 index 0000000..121c1b1 --- /dev/null +++ b/NET/worlds/scape/CopyWidget.java @@ -0,0 +1,14 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; + +class CopyWidget extends ClickWidget { + public CopyWidget(ToolBar toolbar) { + super(toolbar, Console.message("copy.gif"), Console.message("Copy")); + } + + @Override + public void perform() { + Console.getFrame().getEditTile().copy(); + } +} diff --git a/NET/worlds/scape/CrashAction.java b/NET/worlds/scape/CrashAction.java new file mode 100644 index 0000000..c8a23ce --- /dev/null +++ b/NET/worlds/scape/CrashAction.java @@ -0,0 +1,56 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class CrashAction extends Action { + private String message = "CrashAction"; + private static Object classCookie = new Object(); + + public void setMessage(String m) { + this.message = m; + } + + @Override + public Persister trigger(Event e, Persister seqId) { + throw new Error(this.message); + } + + @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 = StringPropertyEditor.make(new Property(this, index, "Message")); + } else if (mode == 1) { + ret = new String(this.message); + } else if (mode == 2) { + this.message = (String)value; + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + super.saveState(s); + s.saveString(this.message); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 1: + super.restoreState(r); + this.message = r.restoreString(); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/CutWidget.java b/NET/worlds/scape/CutWidget.java new file mode 100644 index 0000000..d28aa54 --- /dev/null +++ b/NET/worlds/scape/CutWidget.java @@ -0,0 +1,14 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; + +class CutWidget extends ClickWidget { + public CutWidget(ToolBar toolbar) { + super(toolbar, "cut.gif", Console.message("Cut")); + } + + @Override + public void perform() { + Console.getFrame().getEditTile().cut(); + } +} diff --git a/NET/worlds/scape/DPAction.java b/NET/worlds/scape/DPAction.java new file mode 100644 index 0000000..a3bb3f8 --- /dev/null +++ b/NET/worlds/scape/DPAction.java @@ -0,0 +1,220 @@ +package NET.worlds.scape; + +import NET.worlds.core.Std; +import java.io.IOException; +import java.util.Enumeration; + +public class DPAction extends Action { + private static final int INFINITY = 60000; + protected int loadDist = 2; + protected int unloadDist = 4; + protected DPState state = null; + private static Object classCookie = new Object(); + + public int getLoadDist() { + return this.loadDist; + } + + public int getUnloadDist() { + return this.unloadDist; + } + + public void setLoadDist(int v) { + assert v > 0; + + if (v > 0) { + this.loadDist = v; + if (this.unloadDist <= this.loadDist) { + this.unloadDist = v + 1; + } + } + } + + public void setUnloadDist(int v) { + assert v > 1; + + if (v <= this.loadDist) { + this.unloadDist = this.loadDist + 1; + } else { + this.unloadDist = v; + } + } + + @Override + public Persister trigger(Event e, Persister seqID) { + if (this.state == null) { + return null; + } else { + if (e != null) { + this.state.setDist(0, e.time); + } else { + this.state.setDist(0, Std.getFastTime()); + } + + return null; + } + } + + public void handleDist(int dist, int time) { + assert this.loadDist < this.unloadDist; + + if (this.getOwner() instanceof Portal) { + if (dist <= this.loadDist) { + ((Portal)this.getOwner()).triggerLoad(); + if (((Portal)this.getOwner()).active()) { + this.informOtherSide(dist + 1, time); + } else { + new DPLoadTracker(this, dist + 1, time); + } + } else if (dist > this.unloadDist) { + ((Portal)this.getOwner()).reset(); + } else if (((Portal)this.getOwner()).active()) { + this.informOtherSide(dist + 1, time); + } + } + } + + void informOtherSide(int distance, int triggerTime) { + DPState s = null; + Portal p = ((Portal)this.getOwner()).farSide(); + Enumeration e = p.getActions(); + + while (e.hasMoreElements()) { + Object a = e.nextElement(); + if (a instanceof DPAction) { + s = ((DPAction)a).getState(); + + assert s != null; + } + } + + if (s != null) { + s.setDist(distance, triggerTime); + } + } + + @Override + protected void noteAddingTo(SuperRoot owner) { + super.noteAddingTo(owner); + if (this.state == null) { + if (owner instanceof Portal) { + Portal p = (Portal)owner; + World w = owner.getWorld(); + if (w != null) { + this.state = this.findState(w); + } + + if (this.state == null) { + this.state = new DPState(60000, this); + } else { + this.state.addConnection(this); + } + } + } + } + + protected DPState findState(SuperRoot root) { + DPState rVal = null; + Enumeration e = root.getDeepOwned(); + + while (e.hasMoreElements() && rVal == null) { + SuperRoot sr = (SuperRoot)e.nextElement(); + if (sr instanceof DPAction) { + rVal = ((DPAction)sr).getState(); + } + } + + return rVal; + } + + public DPState getState() { + return this.state; + } + + @Override + public void detach() { + if (this.state != null) { + this.state.dropConnection(this); + this.state = null; + } + + super.detach(); + } + + @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 = IntegerPropertyEditor.make(new Property(this, index, "Load Distance")); + } else if (mode == 1) { + ret = new Integer(this.loadDist); + } else if (mode == 2) { + this.setLoadDist((Integer)value); + } + break; + case 1: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Unload Distance")); + } else if (mode == 1) { + ret = new Integer(this.unloadDist); + } else if (mode == 2) { + this.setUnloadDist((Integer)value); + } + break; + case 2: + if (mode == 0) { + ret = new Property(this, index, "Cell State"); + } else if (mode == 1) { + ret = this.state; + } + break; + default: + ret = super.properties(index, offset + 3, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(2, classCookie); + super.saveState(s); + s.saveInt(this.loadDist); + s.saveInt(this.unloadDist); + s.saveMaybeNull(this.state); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this.loadDist = r.restoreInt(); + this.unloadDist = r.restoreInt(); + this.state = (DPState)r.restore(); + r.restoreInt(); + break; + case 1: + super.restoreState(r); + this.loadDist = r.restoreInt(); + this.unloadDist = r.restoreInt(); + this.state = (DPState)r.restore(); + break; + case 2: + super.restoreState(r); + this.loadDist = r.restoreInt(); + this.unloadDist = r.restoreInt(); + this.state = (DPState)r.restoreMaybeNull(); + break; + default: + throw new TooNewException(); + } + } + + @Override + public String toString() { + return super.toString() + "[" + this.getOwner().getWorld().getName() + "|" + this.getOwner().getName() + "]"; + } +} diff --git a/NET/worlds/scape/DPLoadTracker.java b/NET/worlds/scape/DPLoadTracker.java new file mode 100644 index 0000000..657739b --- /dev/null +++ b/NET/worlds/scape/DPLoadTracker.java @@ -0,0 +1,44 @@ +package NET.worlds.scape; + +class DPLoadTracker extends WObject implements FrameHandler, NonPersister { + protected DPAction src; + protected int distance; + protected int triggerTime = 0; + + public DPLoadTracker(DPAction a, int dist, int time) { + this.src = a; + this.setDistance(dist, time); + ((Portal)this.src.getOwner()).addHandler(this); + } + + public DPLoadTracker() { + } + + public void setDistance(int dist, int time) { + if (time > this.triggerTime) { + this.distance = dist; + this.triggerTime = time; + } + } + + @Override + public boolean handle(FrameEvent ev) { + if (((Portal)this.src.getOwner()).active()) { + this.src.informOtherSide(this.distance, this.triggerTime); + this.finish(); + } else if (((Portal)this.src.getOwner()).unconnected()) { + this.finish(); + } + + return true; + } + + public void finish() { + ((Portal)this.src.getOwner()).removeHandler(this); + } + + @Override + public String toString() { + return super.toString(); + } +} diff --git a/NET/worlds/scape/DPState.java b/NET/worlds/scape/DPState.java new file mode 100644 index 0000000..f4502eb --- /dev/null +++ b/NET/worlds/scape/DPState.java @@ -0,0 +1,118 @@ +package NET.worlds.scape; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.Vector; + +public class DPState extends SuperRoot { + public static final int INFINITY = 60000; + protected Vector connections = new Vector(); + protected int currentDist = 60000; + protected long currentTime = 0L; + private static Object classCookie = new Object(); + + public DPState(int dist, DPAction conn) { + this.currentDist = dist; + this.currentTime = 0L; + this.addConnection(conn); + } + + public DPState() { + } + + public void setDist(int d, int t) { + if (this.currentTime <= t) { + if (this.currentDist > d || this.currentTime != t) { + this.currentDist = d; + this.currentTime = t; + Enumeration e = this.connections.elements(); + + while (e.hasMoreElements()) { + ((DPAction)e.nextElement()).handleDist(d, t); + } + } + } + } + + public int getDist() { + return this.currentDist; + } + + public Enumeration getConnections() { + return this.connections.elements(); + } + + public Enumeration getPortals() { + Vector v = new Vector(this.connections.size()); + Enumeration e = this.connections.elements(); + + while (e.hasMoreElements()) { + v.addElement(((DPAction)e.nextElement()).getOwner()); + } + + return v.elements(); + } + + public void addConnection(DPAction conn) { + if (!this.connections.contains(conn)) { + this.connections.addElement(conn); + } + } + + public void dropConnection(DPAction conn) { + this.connections.removeElement(conn); + } + + @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 = IntegerPropertyEditor.make(new Property(this, index, "Current Distance")); + } else if (mode == 1) { + ret = new Integer(this.currentDist); + } else if (mode == 2) { + this.currentDist = (Integer)value; + } + break; + case 1: + if (mode == 0) { + ret = new VectorProperty(this, index, "Connections"); + } else if (mode == 1) { + ret = this.connections.clone(); + } + break; + default: + ret = super.properties(index, offset + 2, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + s.saveVector(this.connections); + s.saveInt(this.currentDist); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this.connections = r.restoreVector(); + this.currentDist = r.restoreInt(); + return; + default: + throw new TooNewException(); + } + } + + @Override + public String toString() { + return super.getName(); + } +} diff --git a/NET/worlds/scape/DeepEnumeration.java b/NET/worlds/scape/DeepEnumeration.java new file mode 100644 index 0000000..060d71e --- /dev/null +++ b/NET/worlds/scape/DeepEnumeration.java @@ -0,0 +1,114 @@ +package NET.worlds.scape; + +import java.util.Enumeration; +import java.util.Vector; + +public class DeepEnumeration<K> implements Enumeration<K> { + Vector<SuperRoot> roots = new Vector<SuperRoot>(); + Vector<Vector<K>> vectors = new Vector<Vector<K>>(); + Vector<K> currentVector = null; + int currentIndex = -1; + SuperRoot nextValue = null; + protected boolean valueRetrieved = true; + + public DeepEnumeration(SuperRoot o) { + this.addChildElement(o); + } + + public DeepEnumeration(Vector<K> v) { + this.addChildVector(v); + } + + public DeepEnumeration(Enumeration<K> e) { + this.addChildEnumeration(e); + } + + public DeepEnumeration() { + } + + @Override + public boolean hasMoreElements() { + if (this.valueRetrieved) { + this.getNextElement(); + } + + return this.nextValue != null; + } + + @Override + public K nextElement() { + if (this.valueRetrieved) { + this.getNextElement(); + } + + this.valueRetrieved = true; + return (K)this.nextValue; + } + + protected void getNextElement() { + this.valueRetrieved = false; + if (!this.roots.isEmpty()) { + this.nextValue = this.roots.elementAt(this.roots.size() - 1); + this.roots.removeElementAt(this.roots.size() - 1); + + assert this.nextValue != null; + + this.nextValue.getChildren(this); + } else if (this.currentIndex >= 0) { + try { + this.nextValue = (SuperRoot)this.currentVector.elementAt(this.currentIndex--); + } catch (ArrayIndexOutOfBoundsException var2) { + this.currentIndex = this.currentVector.size() - 1; + this.getNextElement(); + } + + assert this.nextValue != null; + + this.nextValue.getChildren(this); + } else if (!this.vectors.isEmpty()) { + this.currentVector = this.vectors.elementAt(this.vectors.size() - 1); + this.currentIndex = this.currentVector.size() - 1; + this.vectors.removeElementAt(this.vectors.size() - 1); + this.getNextElement(); + } else { + this.nextValue = null; + } + } + + public void addChildVector(Vector<K> eventHandlers) { + assert eventHandlers != null; + + this.vectors.addElement(eventHandlers); + } + + public void addChildEnumeration(Enumeration<K> e) { + assert e != null; + + while (e.hasMoreElements()) { + this.addChildElement(e.nextElement()); + } + } + + public void addChildVectorWithNulls(Vector<K> v) { + assert v != null; + + for (int i = v.size() - 1; i >= 0; i--) { + Object obj = v.elementAt(i--); + if (obj != null) { + this.addChildElement(obj); + } + } + } + + public void addChildElement(Object o) { + assert o != null; + + this.roots.addElement((SuperRoot)o); + } + + public void addChildVectorAction(Vector<K> actions) { + assert actions != null; + + this.vectors.addElement(actions); + } +} diff --git a/NET/worlds/scape/DialogAction.java b/NET/worlds/scape/DialogAction.java new file mode 100644 index 0000000..b0092be --- /dev/null +++ b/NET/worlds/scape/DialogAction.java @@ -0,0 +1,118 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.DialogReceiver; +import NET.worlds.console.PolledDialog; +import java.io.IOException; + +public abstract class DialogAction extends Action implements DialogReceiver { + boolean showDialog = true; + boolean cancelOnly = false; + private static PolledDialog dialogUp = null; + private PolledDialog thisDialog; + protected static boolean doCancel = false; + private static Object classCookie = new Object(); + + @Override + public void dialogDone(Object who, boolean confirmed) { + if (dialogUp == who) { + doCancel = true; + if (confirmed) { + this.doIt(); + } + } + } + + public abstract void doIt(); + + public abstract PolledDialog getDialog(); + + @Override + public Persister trigger(Event e, Persister seqID) { + Console console = Console.getActive(); + if (console == null) { + return null; + } else if (!this.showDialog && !this.cancelOnly) { + if (console != null) { + this.doIt(); + } + + return null; + } else if (dialogUp == null) { + if (this.cancelOnly) { + return null; + } else { + this.thisDialog = dialogUp = this.getDialog(); + doCancel = false; + return this; + } + } else { + if (this.thisDialog == dialogUp && seqID != null) { + if (doCancel) { + dialogUp.closeIt(false); + dialogUp = null; + this.thisDialog = null; + return null; + } + } else { + doCancel = true; + } + + return this; + } + } + + @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 = BooleanPropertyEditor.make(new Property(this, index, "Display Dialog Box"), "Don't ask", "Ask user to ok choice"); + } else if (mode == 1) { + ret = new Boolean(this.showDialog); + } else if (mode == 2) { + this.showDialog = (Boolean)value; + } + break; + case 1: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Cancel only"), "Regular operation", "Cancels dialog, doesn't do action"); + } else if (mode == 1) { + ret = new Boolean(this.cancelOnly); + } else if (mode == 2) { + this.cancelOnly = (Boolean)value; + } + break; + default: + ret = super.properties(index, offset + 2, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + s.saveBoolean(this.showDialog); + s.saveBoolean(this.cancelOnly); + } + + protected void dialogActionSkipRestore(Restorer r) throws IOException, TooNewException { + super.restoreState(r); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this.showDialog = r.restoreBoolean(); + this.cancelOnly = r.restoreBoolean(); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/DiffRoomSensor.java b/NET/worlds/scape/DiffRoomSensor.java new file mode 100644 index 0000000..141b76e --- /dev/null +++ b/NET/worlds/scape/DiffRoomSensor.java @@ -0,0 +1,49 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class DiffRoomSensor extends Sensor implements FrameHandler { + private Room lastCamRoom; + private static Object classCookie = new Object(); + + @Override + public void detach() { + this.lastCamRoom = null; + super.detach(); + } + + @Override + public boolean handle(FrameEvent e) { + Object owner = this.getOwner(); + if (owner != null && owner instanceof WObject) { + WObject o = (WObject)owner; + Room thisRoom = o.getRoom(); + Room thisCamRoom = Pilot.getActiveRoom(); + if (thisCamRoom != thisRoom && this.lastCamRoom == thisRoom) { + this.trigger(e); + } + + this.lastCamRoom = thisCamRoom; + return true; + } else { + return true; + } + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/DirectShow.java b/NET/worlds/scape/DirectShow.java new file mode 100644 index 0000000..9af989b --- /dev/null +++ b/NET/worlds/scape/DirectShow.java @@ -0,0 +1,51 @@ +package NET.worlds.scape; + +public class DirectShow implements TextureSurfaceRenderer { + static final int nUnitialized = 0; + static final int nStopped = 1; + static final int nPaused = 2; + static final int nPlaying = 3; + private int mediaRendererInstancePtr; + private int m_hwnd; + + public DirectShow() { + nativeInit(); + this.nInit(0); + } + + public DirectShow(int hwnd) { + this.m_hwnd = hwnd; + nativeInit(); + this.nInit(hwnd); + } + + @Override + public void finalize() { + this.nTick(); + this.nStop(); + this.nShutdown(); + } + + @Override + public void renderTo(int dc) { + this.nRenderTo(this.m_hwnd, dc); + } + + public static native void nativeInit(); + + protected native void nInit(int var1); + + protected native void nShutdown(); + + public native void nOpen(String var1); + + public native void nPlay(int var1); + + public native void nStop(); + + public native void nPause(); + + public native void nRenderTo(int var1, int var2); + + public native int nTick(); +} diff --git a/NET/worlds/scape/DiskShadow.java b/NET/worlds/scape/DiskShadow.java new file mode 100644 index 0000000..603ad75 --- /dev/null +++ b/NET/worlds/scape/DiskShadow.java @@ -0,0 +1,61 @@ +package NET.worlds.scape; + +import java.awt.Color; + +public class DiskShadow extends Polygon implements NonPersister, Shadow { + private static int numSides = 8; + private static float[] diskVertices = new float[5 * numSides]; + + static { + float radius = 0.5F; + int end = 5 * numSides; + double angle = 0.0; + double angleInc = (float)((Math.PI * 2) / numSides); + + for (int i = 0; i < end; angle += angleInc) { + float x = (float)Math.cos(angle); + float y = (float)Math.sin(angle); + diskVertices[i + 0] = radius * x; + diskVertices[i + 1] = radius * y; + diskVertices[i + 2] = 0.0F; + diskVertices[i + 3] = 0.5F + 0.5F * x; + diskVertices[i + 4] = 0.5F + 0.5F * y; + i += 5; + } + } + + public DiskShadow(WObject caster) { + super(diskVertices, new Material(0.0F, 0.0F, 0.0F, Color.black, null, 0.5F, false, false)); + this.setBumpable(false); + this.adjustShadow(caster); + } + + @Override + public void adjustShadow(WObject caster) { + Room r = caster.getRoom(); + if (caster.getVisible() && r != null) { + float defSize = 0.0F; + float size = caster.getMinXYExtent(); + BoundBoxTemp box = caster.getBoundBox(); + if (!(size <= 0.0F) && !(size > 10000.0F) && !(box.hi.z < 0.0F) && !(box.lo.z >= 250.0F)) { + float shadowFrac = 1.0F; + if (box.lo.z > 0.0F) { + shadowFrac = 1.0F - box.lo.z / 250.0F; + } + + if (this.getOwner() == null && r != null) { + r.getEnvironment().add(this); + } + + Point3Temp xyz = caster.getWorldPosition(); + this.moveTo(xyz.x, xyz.y, r.floorHeight(xyz.x, xyz.y, xyz.z) + 0.5F); + this.yaw(this.getYaw() - caster.getYaw()); + this.scale(size * shadowFrac / this.getScaleX()); + } else { + this.detach(); + } + } else { + this.detach(); + } + } +} diff --git a/NET/worlds/scape/DispenserAction.java b/NET/worlds/scape/DispenserAction.java new file mode 100644 index 0000000..082336a --- /dev/null +++ b/NET/worlds/scape/DispenserAction.java @@ -0,0 +1,98 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.network.URL; +import java.io.IOException; + +public class DispenserAction extends Action { + URL wobName; + Point3 center = new Point3(200.0F, 200.0F, 0.0F); + float radius = 50.0F; + private static Object classCookie = new Object(); + + @Override + public Persister trigger(Event arg, Persister seqID) { + WObject w = (WObject)this.getOwner(); + SuperRoot ob = SuperRoot.readFile(this.wobName); + if (!(ob instanceof WObject)) { + Console.println(Console.message("Cant-find") + this.wobName); + return null; + } else { + WObject wob = (WObject)ob; + Point3Temp pos = Point3Temp.make( + this.radius - (float)Math.random() * 2.0F * this.radius, this.radius - (float)Math.random() * 2.0F * this.radius, 0.0F + ) + .plus(this.center); + pos.z = wob.getZ(); + wob.moveTo(pos); + w.getRoom().add(wob); + return null; + } + } + + @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 = URLPropertyEditor.make(new Property(this, index, "wob File Name"), "wob"); + } else if (mode == 1) { + ret = this.wobName; + } else if (mode == 2) { + this.wobName = (URL)value; + } + break; + case 1: + if (mode == 0) { + ret = Point3PropertyEditor.make(new Property(this, index, "Center Position For Drop")); + } else if (mode == 1) { + ret = new Point3(this.center); + } else if (mode == 2) { + this.center = new Point3((Point3)value); + } + break; + case 2: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Drop-position Radius")); + } else if (mode == 1) { + ret = new Float(this.radius); + } else if (mode == 2) { + this.radius = (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); + URL.save(s, this.wobName); + s.save(this.center); + s.saveFloat(this.radius); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this.wobName = URL.restore(r); + this.center = (Point3)r.restore(); + this.radius = r.restoreFloat(); + return; + default: + throw new TooNewException(); + } + } + + @Override + public String toString() { + return super.toString() + "[" + this.wobName + "]"; + } +} diff --git a/NET/worlds/scape/DoorBasedFilter.java b/NET/worlds/scape/DoorBasedFilter.java new file mode 100644 index 0000000..3a46069 --- /dev/null +++ b/NET/worlds/scape/DoorBasedFilter.java @@ -0,0 +1,142 @@ +package NET.worlds.scape; + +public class DoorBasedFilter extends AudibilityFilter { + float stopDistance; + public static final double log10 = Math.log(10.0); + + DoorBasedFilter(Sound s, WObject o, int maxHops, float stopDist) { + super(s, o, maxHops, stopDist); + this.debugOut(6, "DoorBasedFilter"); + this.stopDistance = stopDist; + } + + private void debugOut(int level, String s) { + if (Sound.debugLevel > level) { + System.out.println(s); + } + } + + @Override + void fillOwnerEntry() { + this.debugOut(9, "door fillOwnerEntry called " + this.sound.getURL()); + DoorBasedParams dbp = new DoorBasedParams(); + dbp.room = this.owner.getRoom(); + dbp.transform = Transform.make(); + dbp.hopcount = 0; + dbp.portalCenter = new Point3(this.owner.getPosition()); + dbp.localPortalCenter = new Point3(dbp.portalCenter); + dbp.nextLastApparent = new Point3(dbp.portalCenter); + dbp.position = new Point3(dbp.portalCenter); + dbp.portalWidth = 0.0F; + dbp.next = null; + dbp.distance = 0.0; + this.ownerPos = dbp; + this.roomList.addElement(this.ownerPos); + } + + @Override + void fillNewAP(AudibleParams connectingRoom, Portal bestPortal, int bestCount) { + this.debugOut(9, "fillNewAP from " + bestPortal.farSideRoom().getName()); + DoorBasedParams conRoom = (DoorBasedParams)connectingRoom; + this.debugOut(9, " to conRoom " + conRoom.room.getName()); + DoorBasedParams newAP = new DoorBasedParams(); + newAP.room = bestPortal.farSideRoom(); + newAP.hopcount = bestCount; + if (bestPortal.p2pXform() == null) { + bestPortal.setTransform(); + } + + if (bestPortal.p2pXform() != null) { + newAP.transform = bestPortal.p2pXform().getTransform(); + } else { + newAP.transform = Transform.make(); + } + + newAP.portalWidth = bestPortal.getScaleX(); + newAP.portalCenter = new Point3(bestPortal.getPosition()); + newAP.portalCenter.plus(bestPortal.getFarCorner()).times(0.5F); + newAP.localPortalCenter = new Point3(newAP.portalCenter); + newAP.localPortalCenter.times(newAP.transform); + newAP.next = conRoom; + newAP.nextLastApparent = new Point3(newAP.next.position); + newAP.nextLastApparent.times(newAP.transform); + newAP.position = newAP.nextLastApparent; + newAP.distance = Point3Temp.make(newAP.portalCenter).minus(newAP.next.localPortalCenter).length() + newAP.next.distance; + this.roomList.addElement(newAP); + this.localPos = newAP; + } + + @Override + public void adjustEmitterLocation() { + this.debugOut(6, "DoorBasedFilter::adjustEmitterLocation"); + if (this.ownerPos.room != this.owner.getRoom()) { + this.moveEmitter(); + } else { + this.recursiveFindAttenuation((DoorBasedParams)this.localPos); + } + } + + public void recursiveFindAttenuation(DoorBasedParams dbp) { + this.debugOut(9, "recursiveFindAttenuation on " + dbp.room.getName()); + if (dbp.next == null) { + dbp.portalCenter.copy(this.owner.getPosition()); + dbp.localPortalCenter.copy(dbp.portalCenter); + dbp.nextLastApparent.copy(dbp.portalCenter); + dbp.position.copy(dbp.portalCenter); + } else { + this.recursiveFindAttenuation(dbp.next); + dbp.nextLastApparent.copy(dbp.next.position); + dbp.nextLastApparent.times(dbp.transform); + dbp.distance = Point3Temp.make(dbp.portalCenter).minus(dbp.next.localPortalCenter).length() + dbp.next.distance; + this.calculateEmitterPosition(dbp); + } + } + + public double calculateTau(Point3Temp listener, Point3Temp portalPos, float portalWidth) { + assert portalWidth > 0.0F; + + double tau = (Point3Temp.make(listener).minus(portalPos).length() - portalWidth) / portalWidth; + tau = Math.max(Math.min(tau, 1.0), 0.0); + + assert tau >= 0.0; + + assert tau <= 1.0; + + return tau; + } + + @Override + public void getEmitterPosition(Point3Temp pos) { + this.debugOut(9, "getEmitterPosition"); + this.calculateEmitterPosition((DoorBasedParams)this.localPos); + pos.copy(((DoorBasedParams)this.localPos).position); + } + + private void calculateEmitterPosition(DoorBasedParams dbp) { + if (dbp.next != null) { + float tau = (float)this.calculateTau(Pilot.getActive().getPosition(), dbp.localPortalCenter, dbp.portalWidth); + Point3Temp far = Point3Temp.make(dbp.nextLastApparent); + Point3Temp local = Point3Temp.make(dbp.localPortalCenter); + Point3Temp apparent = local.times(tau).plus(far.times(1.0F - tau)); + dbp.position.copy(apparent); + } + } + + @Override + public float getEmitterVolume() { + float rv = 1.0F; + + assert this.localPos != null; + + DoorBasedParams dbp = (DoorBasedParams)this.localPos; + if (dbp.next == null) { + return 1.0F; + } else { + Point3Temp apparent = Point3Temp.make(dbp.position); + double atten = apparent.minus(dbp.localPortalCenter).length(); + double atten1 = dbp.distance - atten; + double atten2 = -2.0 / this.stopDistance * atten1; + return (float)Math.exp(atten2 * log10); + } + } +} diff --git a/NET/worlds/scape/DoorBasedParams.java b/NET/worlds/scape/DoorBasedParams.java new file mode 100644 index 0000000..2fd3eab --- /dev/null +++ b/NET/worlds/scape/DoorBasedParams.java @@ -0,0 +1,10 @@ +package NET.worlds.scape; + +class DoorBasedParams extends AudibleParams { + public Point3 portalCenter; + public Point3 localPortalCenter; + public Point3 nextLastApparent; + public float portalWidth; + public DoorBasedParams next; + public double distance; +} diff --git a/NET/worlds/scape/Drone.java b/NET/worlds/scape/Drone.java new file mode 100644 index 0000000..d930b61 --- /dev/null +++ b/NET/worlds/scape/Drone.java @@ -0,0 +1,864 @@ +package NET.worlds.scape; + +import NET.worlds.console.BBAppearDroneCommand; +import NET.worlds.console.BBDisappearDroneCommand; +import NET.worlds.console.BBDroneBitmapCommand; +import NET.worlds.console.BBDroneDeltaPosCommand; +import NET.worlds.console.BBMoveDroneCommand; +import NET.worlds.console.BlackBox; +import NET.worlds.console.Console; +import NET.worlds.console.FriendsListPart; +import NET.worlds.console.Main; +import NET.worlds.console.MainCallback; +import NET.worlds.console.MuteListPart; +import NET.worlds.core.IniFile; +import NET.worlds.core.ServerTableManager; +import NET.worlds.core.Std; +import NET.worlds.network.FilthFilter; +import NET.worlds.network.Galaxy; +import NET.worlds.network.InfiniteWaitException; +import NET.worlds.network.NetworkObject; +import NET.worlds.network.ObjID; +import NET.worlds.network.OldPropertyList; +import NET.worlds.network.PacketTooLargeException; +import NET.worlds.network.PropertyList; +import NET.worlds.network.URL; +import NET.worlds.network.WorldServer; +import NET.worlds.network.net2Property; +import NET.worlds.network.netProperty; +import NET.worlds.network.propReqCmd; +import java.awt.Color; +import java.io.IOException; +import java.net.MalformedURLException; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +public abstract class Drone extends WObject implements NetworkObject, WobLoaded, MouseDownHandler, FrameHandler { + private int _last_FrameTime; + private int _last_PosTime; + private int _vel_x; + private int _vel_y; + private int _vel_z; + private int _vel_yaw; + private int _last_x; + private int _last_y; + private int _last_z; + private int _last_yaw; + private int _x; + private int _y; + private int _z; + private int _yaw; + private boolean inited = false; + protected WObject tag; + protected WObject tagbg; + private Console console; + private float tagHeight; + private Shape sleepBox; + static boolean showNametags = IniFile.gamma().getIniInt("SHOWNAMETAGS", 1) == 1; + private static String[] employeeAccounts = ServerTableManager.instance().getTable("employeeAccounts"); + private static Hashtable<String, String> employeeHash = null; + public static Vector<Drone> usableDrones = new Vector<Drone>(); + private int lastUsed; + protected WorldServer _server; + private String sleepMode; + private static Object classCookie = new Object(); + private static Object classCookieInterpolatedDrone = new Object(); + + static { + Main.register(new Drone.Flusher()); + } + + public Drone(ObjID id, WorldServer serv) { + if (serv != null) { + assert id != null; + + this.attachToServer(serv.getLongID(id), serv); + } + } + + protected Drone(String longID, WorldServer serv) { + assert longID != null; + + if (serv != null) { + this.attachToServer(longID, serv); + } + } + + private void attachToServer(String longID, WorldServer serv) { + if (serv != null) { + assert Main.isMainThread(); + + String nameWas = null; + if (this.tag != null) { + nameWas = this.getLongID(); + } + + this.getSharer().createDynamicFromNet(); + this.setName(longID); + String nameIs = this.getLongID(); + this._server = serv; + this._server.incRefCnt(this); + this._server.regObject(nameIs, this); + + try { + this._server.sendNetworkMsg(new propReqCmd(new ObjID(this.getLongID()))); + } catch (InfiniteWaitException var6) { + } catch (PacketTooLargeException var7) { + assert false; + } + + if (nameIs.equals(nameWas)) { + this.avatarHeightChangedTo(189.0F); + } else { + this.makeTag(false); + } + + Main.register(new Drone.MakeSleepBox()); + } + } + + private static void flushUnusedDrones() { + synchronized (usableDrones) { + int now = Std.getFastTime(); + int i = usableDrones.size(); + + while (--i >= 0) { + Drone d = usableDrones.elementAt(i); + if (now > d.lastUsed + 2000) { + usableDrones.removeElementAt(i); + d.discard(); + } + } + } + } + + public static boolean isEmployeeAccount(String name) { + if (employeeHash == null) { + employeeHash = new Hashtable<String, String>(); + + for (int i = 0; i < employeeAccounts.length; i++) { + employeeHash.put(employeeAccounts[i], employeeAccounts[i]); + } + } + + return employeeHash.get(name) != null; + } + + public void makeTag(boolean force) { + this.tagHeight = 195.0F; + if (this.tag != null) { + this.tagHeight = this.tag.getPosition().z; + this.tag.detach(); + this.tag = null; + } + + if (this.tagbg != null) { + this.tagbg.detach(); + this.tagbg = null; + } + + if ((this._server != null || force) && !(this instanceof MutedDrone) && showNametags) { + String unfilteredName = this.getLongID(); + String name = FilthFilter.get().filterName(unfilteredName); + if (name != null && !name.equals("")) { + Texture[] tagText = new Texture[1]; + boolean hw = RenderWare.get3DHardwareInUse(); + boolean isHost = name.toLowerCase().startsWith(Console.message("host")) || name.toLowerCase().startsWith("host"); + if (isHost) { + name = Console.message("host-upper") + name.substring(4); + } + + boolean isSpecialGuest = name.toLowerCase().startsWith(Console.message("guest-")) || name.toLowerCase().startsWith("guest-"); + if (isSpecialGuest) { + name = Console.message("guest-upper") + name.substring(5); + } + + boolean isEmployee = isEmployeeAccount(name); + Color bgColor; + if (isSpecialGuest) { + bgColor = Color.pink; + } else if (isHost) { + bgColor = Color.yellow; + } else if (isEmployee) { + bgColor = Color.cyan; + } else { + bgColor = Color.lightGray; + } + + tagText[0] = new StringTexture(name, Console.message("TagFont"), 48, Color.black, hw ? new Color(254, 254, 254) : bgColor); + int height = 14; + int width = name.length() * 10; + Hologram h = new Hologram(width, height, tagText); + h.setViewplaneAligned(true); + h.raise(this.tagHeight); + h.setScaleDist(300.0F); + this.tag = h; + this.tag.setVisible(true); + this.tag.setBumpable(false); + this.tag.setLocalShadowed(false); + this.tag.setShadowedLocally(true); + this.add(this.tag); + if (hw) { + Texture[] bgText = new Texture[]{new StringTexture(name, Console.message("TagFont"), 48, Color.black, bgColor)}; + Hologram h2 = new Hologram(width, height, bgText); + h2.setViewplaneAligned(true); + h2.raise(this.tagHeight); + h2.setScaleDist(300.0F); + h2.setMaterial(new Material(0.75F, 0.0F, 0.0F, Color.white, null, 0.5F, false, false)); + this.tagbg = h2; + this.tagbg.setVisible(true); + this.tagbg.setBumpable(false); + this.tagbg.setLocalShadowed(false); + this.tagbg.setShadowedLocally(true); + this.add(this.tagbg); + } + } + } + } + + protected void avatarHeightChangedTo(float h) { + if (this.tag != null) { + this.tag.raise(h + 1.0F + 5.0F - this.tag.getPosition().z); + } + + if (this.tagbg != null) { + this.tagbg.raise(h + 1.0F + 5.0F - this.tagbg.getPosition().z); + } + } + + public void detachFromServer(boolean reuse) { + assert Main.isMainThread(); + + if (this._server != null) { + this._server.delObject(new ObjID(this.getLongID())); + this._server.decRefCnt(this); + this._server = null; + } + + if (reuse) { + this.lastUsed = Std.getFastTime(); + synchronized (usableDrones) { + usableDrones.addElement(this); + } + } + } + + public static Drone make(ObjID id, WorldServer serv) { + synchronized (usableDrones) { + if (!usableDrones.isEmpty() && id != null && serv != null) { + String name = "!" + serv.getLongID(id); + + int i; + for (i = usableDrones.size() - 1; i > 0; i--) { + Drone d = usableDrones.elementAt(i); + if (d.getName().equals(name)) { + break; + } + } + + Drone d = usableDrones.elementAt(i); + if (!d.getName().equals(name) && usableDrones.size() < 5) { + return new HoloDrone(id, serv); + } else { + usableDrones.removeElementAt(i); + d.attachToServer(serv.getLongID(id), serv); + return d; + } + } else { + return new HoloDrone(id, serv); + } + } + } + + public Drone() { + } + + @Override + public boolean handle(MouseDownEvent event) { + if (this._server != null && (event.key & 1) == 1) { + FriendsListPart.droneClick(this, event); + } + + return true; + } + + public float animate(String action) { + if (action.equalsIgnoreCase("_hdb")) { + new Drone.BounceNametag(); + } + + return 0.0F; + } + + public Vector<String> getAnimationList() { + return new Vector<String>(); + } + + public void muteStateChanged() { + this.setAvatarNow(this.getCurrentURL()); + } + + public boolean shouldBeMuted() { + return MuteListPart.isMuted(this._server, this.getLongID()); + } + + private World getOwnerWorld() { + WObject o = (WObject)this.getOwner(); + Room room = o == null ? null : o.getRoom(); + return room == null ? null : room.getWorld(); + } + + public boolean shouldBeForcedHuman() { + World w = this.getOwnerWorld(); + return w != null && w.getForceHuman(); + } + + public URL getCurrentURL() { + return this instanceof PosableDrone ? ((PosableDrone)this).getPosableShapeURL() : this.getSourceURL(); + } + + public Drone setAvatarNow(URL url) { + if (url == null) { + return this; + } else { + if (this.shouldBeForcedHuman()) { + url = PosableShape.getHuman(url); + if (Console.getActive() != null) { + Console.getActive().pendingPilot = url.toString(); + } + } + + url = PosableShape.getPermitted(url, this.getWorld()); + boolean muted = this.shouldBeMuted(); + if (url.equals(this.getCurrentURL()) && muted == (this instanceof MutedDrone)) { + return this; + } else if (!url.endsWith(".rwx") && !url.endsWith(".rwg") && !url.endsWith(".mov")) { + String s = url.getInternal(); + if (s.endsWith(".pilot")) { + s = s.substring(0, s.length() - 6) + ".drone"; + } else if (!s.endsWith(".drone")) { + s = s + ".drone"; + } + + url = URL.make(s); + if (url.equals(this.getSourceURL())) { + return this; + } else { + new WobLoader(url, this); + return this; + } + } else { + WObject o = (WObject)this.getOwner(); + if (o == null) { + return this; + } else { + WorldServer serv = this._server; + String longID = this.getLongID(); + this.detachFromServer(false); + this.detach(); + Drone d; + if (muted) { + d = new MutedDrone(new ObjID(longID), serv, url); + } else if (url.endsWith(".mov")) { + d = new HoloDrone(new ObjID(longID), serv); + d.setAvatarNow(url); + } else { + d = new PosableDrone(new ObjID(longID), serv, url); + } + + if (serv != null) { + d.transferFrom(this); + d.addTo(o.getRoom()); + } else { + d.makeIdentity().post(this); + d.setName(this.getLongID()); + o.add(d); + } + + return d; + } + } + } + } + + @Override + public void wobLoaded(WobLoader loader, SuperRoot w) { + if (w instanceof Drone) { + assert w != null; + + Drone d = (Drone)w; + d.setName(this.getLongID()); + if (this._server == null) { + WObject o = (WObject)this.getOwner(); + this.detach(); + d.makeIdentity().post(this); + o.add(d); + } else { + WorldServer serv = this._server; + String longID = this.getLongID(); + this.detachFromServer(false); + Room r = this.getRoom(); + this.detach(); + d.addTo(r); + d.attachToServer(longID, serv); + d.transferFrom(this); + } + } + } + + public void addTo(Room r) { + if (r != null) { + Console c = r.getWorld().getConsole(); + if (this.console == null) { + this.console = c; + if (c != null) { + Pilot.copySoul(c.getDroneSoulTemplate(), this); + } + } + + r.add(this); + } + } + + @Override + public void add(WObject w) { + super.add(w); + } + + @Override + protected void noteUnadding(SuperRoot child) { + if (child instanceof WObject) { + WObject w = (WObject)child; + if (w.isDynamic()) { + w.setVisible(true); + } + } + + super.noteUnadding(child); + } + + public void setSleepMode(String mode) { + if (!mode.equals(this.sleepMode)) { + this.sleepMode = mode; + Main.register(new Drone.MakeSleepBox()); + } + } + + private void handleVAR_ASLEEP(String s) { + if (s != null && s.length() > 2 && s.charAt(0) == 0) { + s = s.substring(2); + } + + this.setSleepMode(s); + } + + public Drone handleVAR_BITMAP(String s) { + if (s.equals("")) { + return this; + } else { + BlackBox.getInstance().submitEvent(new BBDroneBitmapCommand(this.getName(), s)); + if (s.charAt(0) == 0) { + s = s.substring(2); + } + + try { + return this.setAvatarNow(new URL(URL.getAvatar(), s)); + } catch (MalformedURLException var3) { + Console.println(Console.message("Invalid-av") + s); + return this; + } + } + } + + public Point3Temp getVelocity() { + return Point3Temp.make(this._vel_x, this._vel_y, this._vel_z); + } + + public int getYawRate() { + return this._vel_yaw; + } + + @Override + public boolean handle(FrameEvent fe) { + if (this._server == null) { + return true; + } else { + int timeNow = fe.time; + this.interpolate(timeNow, this._server.getUpdateTime(), this); + return true; + } + } + + public void interpolate(int timeNow, int updateTime, Transform target) { + if (this.inited) { + if (timeNow - this._last_PosTime > updateTime) { + this._last_PosTime = timeNow; + this._vel_x = this._last_x - this._x; + this._vel_y = this._last_y - this._y; + this._vel_z = this._last_z - this._z; + this._vel_yaw = ((this._last_yaw - this._yaw) % 360 + 360) % 360; + + assert this._vel_yaw >= 0; + + if (this._vel_yaw > 180) { + this._vel_yaw -= 360; + } + } + + double timeDiff = (double)(timeNow - this._last_FrameTime) / updateTime; + if (timeNow - this._last_FrameTime > updateTime) { + timeDiff = 0.0; + } + + this._x = this._x + (int)(timeDiff * this._vel_x); + this._y = this._y + (int)(timeDiff * this._vel_y); + this._z = this._z + (int)(timeDiff * this._vel_z); + this._yaw = this._yaw + (int)(timeDiff * this._vel_yaw) % 360; + target.makeIdentity().moveBy(this._x, this._y, this._z).yaw(this._yaw); + this._last_FrameTime = timeNow; + } + } + + public void reset(short x, short y, short z, short yaw) { + this._x = x; + this._y = y; + this._z = z; + this._yaw = yaw; + this._vel_x = this._vel_y = this._vel_z = 0; + this._vel_yaw = 0; + this._last_x = this._x; + this._last_y = this._y; + this._last_z = this._z; + this._last_yaw = this._yaw; + this._last_PosTime = this._last_FrameTime = Std.getRealTime(); + this.inited = true; + } + + protected void transferFrom(Drone i) { + this.makeIdentity().post(i); + this._x = i._x; + this._y = i._y; + this._z = i._z; + this._yaw = i._yaw; + this._vel_x = i._vel_x; + this._vel_y = i._vel_y; + this._vel_z = i._vel_z; + this._vel_yaw = i._vel_yaw; + this._last_x = i._last_x; + this._last_y = i._last_y; + this._last_z = i._last_z; + this._last_yaw = i._last_yaw; + this._last_PosTime = i._last_PosTime; + this._last_FrameTime = i._last_FrameTime; + this.inited = true; + } + + public void appear(Room rm, short x, short y, short z, short yaw) { + assert rm != null; + + BlackBox.getInstance().submitEvent(new BBAppearDroneCommand(rm.toString(), this.getName(), x, y, z, yaw)); + if (this.getRoom() != rm) { + this.detach(); + rm.add(this); + } + + this.makeIdentity().moveBy(x, y, z).yaw(yaw); + this._x = x; + this._y = y; + this._z = z; + this._yaw = yaw; + this._vel_x = this._vel_y = this._vel_z = 0; + this._vel_yaw = 0; + this._last_x = x; + this._last_y = y; + this._last_z = z; + this._last_yaw = yaw; + this._last_PosTime = this._last_FrameTime = Std.getRealTime(); + URL u = this.getCurrentURL(); + if (u != null) { + this.setAvatarNow(u); + } + + this.inited = true; + } + + public void disappear() { + BlackBox.getInstance().submitEvent(new BBDisappearDroneCommand(this.getName())); + this.detachFromServer(true); + this.detach(); + } + + public void longLoc(short x, short y, short z, short yaw) { + if (!(this.getOwner() instanceof Pilot)) { + BlackBox.getInstance().submitEvent(new BBMoveDroneCommand(this.getName(), x, y, z, yaw)); + } + + this._last_x = x; + this._last_y = y; + this._last_z = z; + this._last_yaw = yaw; + this._vel_x = this._last_x - this._x; + this._vel_y = this._last_y - this._y; + this._vel_z = this._last_z - this._z; + this._vel_yaw = ((this._last_yaw - this._yaw) % 360 + 360) % 360; + + assert this._vel_yaw >= 0; + + if (this._vel_yaw > 180) { + this._vel_yaw -= 360; + } + + this._last_PosTime = Std.getRealTime(); + this.inited = true; + } + + @Override + public void property(OldPropertyList propList) { + int end = propList.size(); + + for (int i = 0; i < end; i++) { + netProperty tmpProp = propList.elementAt(i); + switch (tmpProp.property()) { + case 5: + this.handleVAR_BITMAP(tmpProp.value()); + break; + case 23: + this.handleVAR_ASLEEP(tmpProp.value()); + break; + default: + byte[] data = new byte[tmpProp.value().length()]; + tmpProp.value().getBytes(0, tmpProp.value().length(), data, 0); + this.getSharer().setFromNetData(tmpProp.property(), data); + } + } + } + + @Override + public void propertyUpdate(PropertyList propList) { + int end = propList.size(); + + for (int i = 0; i < end; i++) { + net2Property tmpProp = propList.elementAt(i); + switch (tmpProp.property()) { + case 5: + this.handleVAR_BITMAP(tmpProp.value()); + break; + case 23: + this.handleVAR_ASLEEP(tmpProp.value()); + break; + default: + this.getSharer().setFromNetData(tmpProp.property(), tmpProp.data()); + } + } + } + + public void roomChange(Room newRoom, short x, short y, short z, short yaw) { + this.detach(); + if (newRoom != null) { + this.appear(newRoom, x, y, z, yaw); + } + } + + public void shortLoc(byte dx, byte dy, byte dyaw) { + if (!(this.getOwner() instanceof Pilot)) { + BlackBox.getInstance().submitEvent(new BBDroneDeltaPosCommand(this.getName(), dx, dy, dyaw)); + } + + this._last_x += dx; + this._last_y += dy; + this._last_yaw += dyaw; + this._last_yaw %= 360; + this._vel_x = this._last_x - this._x; + this._vel_y = this._last_y - this._y; + this._vel_z = 0; + this._vel_yaw = ((this._last_yaw - this._yaw) % 360 + 360) % 360; + + assert this._vel_yaw >= 0; + + if (this._vel_yaw > 180) { + this._vel_yaw -= 360; + } + + this._last_PosTime = Std.getRealTime(); + } + + public void teleport(WorldServer serv, byte exitType, byte entryType, Room newRoom, short x, short y, short z, short yaw) { + assert serv.getObject(new ObjID(this.getLongID())) == this; + + Room curRoom = this.getRoom(); + switch (exitType) { + default: + if (curRoom != null) { + assert curRoom != null; + + this.detach(); + } + case 0: + switch (entryType) { + case 0: + this.detachFromServer(true); + this.detach(); + break; + default: + if (newRoom == null) { + this.detach(); + } else { + assert newRoom != null; + + this.appear(newRoom, x, y, z, yaw); + } + } + } + } + + @Override + public WorldServer getServer() { + return this._server; + } + + @Override + public String getLongID() { + String name = this.getName(); + if (name.startsWith("!")) { + name = name.substring(1); + } + + return name; + } + + @Override + public void register() { + assert false; + } + + @Override + public void galaxyDisconnected() { + assert false; + } + + @Override + public void reacquireServer(WorldServer oldServ) { + assert false; + } + + @Override + public void changeChannel(Galaxy g, String oldChannel, String newChannel) { + assert false; + } + + @Override + public Object properties(int index, int offset, int mode, Object value) throws NoSuchPropertyException { + Object ret = null; + int var10000 = index - offset; + return super.properties(index, offset + 0, mode, value); + } + + @Override + public void saveState(Saver s) throws IOException { + if (this.console != null) { + System.out.println("Warning: saving drone " + this.getName() + " WITH soul, which won't restore correctly!"); + } + + s.saveVersion(0, classCookieInterpolatedDrone); + s.saveVersion(0, classCookie); + super.saveState(s); + } + + public void restoreStateDrone(Restorer r) throws IOException, TooNewException { + r.restoreVersion(classCookieInterpolatedDrone); + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + Enumeration e = this.getContents(); + + while (e.hasMoreElements()) { + WObject w = (WObject)e.nextElement(); + if (w instanceof Hologram) { + Hologram h = (Hologram)w; + if (h.getMovieName() == null) { + this.tag = h; + } + } + } + + return; + default: + throw new TooNewException(); + } + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + this.restoreStateDrone(r); + } + + class BounceNametag implements MainCallback { + int start; + WObject origTag; + WObject origTagbg; + + BounceNametag() { + if (Drone.this.tag != null) { + this.start = Std.getFastTime(); + this.origTag = Drone.this.tag; + this.origTagbg = Drone.this.tagbg; + Main.register(this); + } + } + + @Override + public void mainCallback() { + int now = Std.getFastTime(); + float h = Drone.this.tagHeight; + if (now > this.start + 6000 || this.origTag != Drone.this.tag || this.origTagbg != Drone.this.tagbg) { + Main.unregister(this); + } else if (now < this.start + 1500) { + h = Drone.this.tagHeight + 200.0F * ((now - this.start) / 1500.0F); + } else { + float t = (now - this.start) / 1500.0F; + h = (float)(200.0 * Math.pow(1.414F, t) * Math.cos(t * 3.14159F)); + } + + this.origTag.setZ(h); + if (this.origTagbg != null) { + this.origTagbg.setZ(h); + } + } + } + + static class Flusher implements MainCallback { + int lastTime; + + @Override + public void mainCallback() { + int now = Std.getFastTime(); + if (now > this.lastTime + 1000) { + Drone.flushUnusedDrones(); + this.lastTime = now; + } + } + } + + class MakeSleepBox implements MainCallback { + @Override + public void mainCallback() { + if (Drone.this.sleepMode != null && Drone.this.sleepMode.equals(Console.message("asleep")) && !(Drone.this instanceof MutedDrone)) { + if (Drone.this.sleepBox == null) { + Drone.this.sleepBox = new Shape(); + Drone.this.sleepBox.setURL(URL.make("home:idle.rwg")); + Drone.this.sleepBox.setBumpable(false); + Drone.this.sleepBox.scale(100.0F); + Drone.this.sleepBox.spin(0.0F, 1.0F, 1.0F, 180.0F); + Drone.this.sleepBox.raise(189.0F); + Drone.this.add(Drone.this.sleepBox); + } + } else if (Drone.this.sleepBox != null) { + Drone.this.sleepBox.detach(); + Drone.this.sleepBox = null; + } + + Main.unregister(this); + } + } +} diff --git a/NET/worlds/scape/DroneAnimator.java b/NET/worlds/scape/DroneAnimator.java new file mode 100644 index 0000000..c50d926 --- /dev/null +++ b/NET/worlds/scape/DroneAnimator.java @@ -0,0 +1,92 @@ +package NET.worlds.scape; + +import NET.worlds.console.Gamma; +import NET.worlds.console.Main; +import NET.worlds.console.MainCallback; +import NET.worlds.core.Std; +import java.util.Vector; + +public class DroneAnimator implements MainCallback { + public static final int INVALID_INDEX = -1; + private static Vector<Integer> deltypeList; + protected int _rep = 0; + + static { + init("."); + if (Gamma.loadProgress != null) { + Gamma.loadProgress.setMessage("Loading avatar definitions..."); + Gamma.loadProgress.advance(); + } + + loadconfig(PendingCacheDrone.getAvatarDatPath()); + } + + public static native void init(String var0); + + public static native void loadconfig(String var0); + + public static native int getnameindex(String var0); + + public static native String getindexgeom(int var0); + + public static native void prepFigure(WObject var0, boolean var1); + + public static native void addtype(int var0); + + public static native void deltype(int var0); + + public void delayedDeltype(int type) { + if (deltypeList == null) { + deltypeList = new Vector<Integer>(); + Main.register(this); + } + + deltypeList.addElement(new Integer(type)); + deltypeList.addElement(new Integer(Std.getFastTime())); + } + + @Override + public void mainCallback() { + int eraseTime = Std.getFastTime() - 20000; + + while (deltypeList.size() > 1) { + int nextTime = deltypeList.elementAt(1); + if (nextTime > eraseTime) { + break; + } + + int type = deltypeList.elementAt(0); + deltype(type); + deltypeList.removeElementAt(0); + deltypeList.removeElementAt(0); + } + } + + public DroneAnimator() { + this._rep = CreateRep(); + } + + @Override + public void finalize() throws Throwable { + DestroyRep(this._rep); + super.finalize(); + } + + public native void endanimations(); + + public native void moveto(int var1, short var2, short var3, short var4, short var5, int var6); + + public native void moveby(int var1, short var2, short var3, short var4, int var5); + + public native void update(WObject var1, WObject var2, int var3, float var4, boolean var5); + + public native float animate(int var1, String var2, int var3); + + public native float getAnimationTime(int var1, String var2); + + public static synchronized native Vector<String> getActionList(int var0); + + protected static native int CreateRep(); + + protected static native void DestroyRep(int var0); +} diff --git a/NET/worlds/scape/DroneLoader.java b/NET/worlds/scape/DroneLoader.java new file mode 100644 index 0000000..1b8052c --- /dev/null +++ b/NET/worlds/scape/DroneLoader.java @@ -0,0 +1,80 @@ +package NET.worlds.scape; + +import NET.worlds.core.IniFile; +import NET.worlds.network.URL; +import java.util.Enumeration; +import java.util.Vector; + +class DroneLoader { + private int MaxDroneLoadingRate = 2000; + static final boolean debug = false; + + DroneLoader() { + int numAvs = IniFile.gamma().getIniInt("avatars", 24); + int droneRate = IniFile.gamma().getIniInt("droneLoadRate", 8000); + this.MaxDroneLoadingRate = droneRate / numAvs; + } + + public synchronized void load(Vector droneList) { + try { + if (droneList.size() > 0) { + Vector listCopy = (Vector)droneList.clone(); + Enumeration enums = listCopy.elements(); + + while (enums.hasMoreElements()) { + PendingDrone pd = (PendingDrone)enums.nextElement(); + if (pd.getDrone().discarded) { + droneList.removeElement(pd); + } else { + loadDrone(pd); + droneList.removeElement(pd); + } + } + } + + this.wait(); + } catch (InterruptedException var5) { + } + } + + public synchronized void wakeUp() { + this.notify(); + } + + private static void loadDrone(PendingDrone pd) { + if (!pd.getLoaded()) { + Enumeration e = PosableShape.getComponentAvatars(pd.getUrl()); + if (e != null) { + while (e.hasMoreElements()) { + String avURL = (String)e.nextElement(); + pd.download(URL.make(avURL)); + } + } + + PosableShape ps; + if (VehicleShape.isVehicle(pd.getUrl())) { + ps = new VehicleShape(); + } else { + ps = new PosableShape(); + } + + boolean prog = ProgressiveAdder.get().enabled(); + if (prog) { + ProgressiveAdder.get().scheduleForAdd(pd.getDrone(), ps); + } + + ps.setURL(pd.getUrl()); + ps.setVisible(true); + ps.setBumpable(false); + if (!pd.getDrone().isPilotDrone(pd.getUrl())) { + ps.enableLOD(true); + } + + if (!prog) { + pd.getDrone().SetPendingShape(ps); + } + + pd.setLoaded(); + } + } +} diff --git a/NET/worlds/scape/DropInfo.java b/NET/worlds/scape/DropInfo.java new file mode 100644 index 0000000..b955456 --- /dev/null +++ b/NET/worlds/scape/DropInfo.java @@ -0,0 +1,19 @@ +package NET.worlds.scape; + +import NET.worlds.network.URL; +import java.awt.Component; +import java.awt.Point; + +class DropInfo { + public URL url; + public String propertyName; + public Component comp; + public Point location; + + DropInfo(URL url, String propertyName, Component comp, Point location) { + this.url = url; + this.propertyName = propertyName; + this.comp = comp; + this.location = location; + } +} diff --git a/NET/worlds/scape/DynamicForwardAttribute.java b/NET/worlds/scape/DynamicForwardAttribute.java new file mode 100644 index 0000000..696a18e --- /dev/null +++ b/NET/worlds/scape/DynamicForwardAttribute.java @@ -0,0 +1,172 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.network.URL; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.Enumeration; + +public class DynamicForwardAttribute extends Attribute implements NonPersister, WobLoaded { + WObject wob = null; + static int DYNAMIC_CODE = 21990; + WobLoader wobLoader; + DataInputStream wobLoaderProps; + private ByteArrayOutputStream _bs = new ByteArrayOutputStream(); + + DynamicForwardAttribute(int attrID) { + super(attrID); + } + + private URL getDynamicHeader(DataInputStream ds) { + try { + return ds.readUnsignedShort() != DYNAMIC_CODE ? null : new URL(this, ds.readUTF()); + } catch (IOException var3) { + return null; + } + } + + @Override + public void setFromNetData(DataInputStream ds, int len) throws IOException { + URL wobName = this.getDynamicHeader(ds); + if (wobName != null && this.wob != null && wobName.equals(this.wob.getSourceURL())) { + this.setProps(ds); + } else { + if (this.wob != null) { + WObject w = this.wob; + this.wob = null; + w.detach(); + } + + if (wobName == null) { + ((Sharer)this.getOwner()).removeAttribute(this); + return; + } + + if (this.wobLoader == null || !this.wobLoader.getWobName().equals(wobName)) { + this.wobLoader = new WobLoader(wobName, this); + } + + this.wobLoaderProps = ds; + } + } + + @Override + public void wobLoaded(WobLoader loader, SuperRoot w) { + if (loader == this.wobLoader) { + Object[] arguments = new Object[]{new String(loader.getWobName().toString())}; + if (w == null) { + Console.println(MessageFormat.format(Console.message("Couldnt-load"), arguments)); + this.wobLoaderProps = null; + } else if (!(w instanceof WObject)) { + Console.println(MessageFormat.format(Console.message("not-WObject"), arguments)); + this.wobLoaderProps = null; + } else { + this.wob = (WObject)w; + this.wob.getSharer().createDynamicForwardedFromNet(this); + ((WObject)this.getOwner().getOwner()).add(this.wob); + this.setProps(this.wobLoaderProps); + this.wobLoaderProps = null; + } + } + } + + void connect(WObject w) { + assert this.wob == null; + + this.wob = w; + this.noteChange(); + } + + void unconnect() { + if (this.wob != null) { + this.wob = null; + this.noteChange(); + } + } + + public void setProps(DataInputStream ds) { + while (true) { + byte[] b; + int id; + try { + if ((id = ds.read()) == -1) { + return; + } + + int len = ds.readByte(); + b = new byte[len]; + ds.readFully(b, 0, len); + } catch (IOException var6) { + Object[] arguments = new Object[]{new String("" + this.getAttrID())}; + Console.println(MessageFormat.format(Console.message("Early-EOF"), arguments)); + return; + } + + this.wob.getSharer().setFromNetData(id, b); + } + } + + @Override + public void generateNetData(DataOutputStream s) throws IOException { + if (this.wob != null && this.wob.getSourceURL() != null) { + s.writeShort(DYNAMIC_CODE); + s.writeUTF(this.wob.getSourceURL().getRelativeTo(this)); + Enumeration e = this.wob.getSharer().getAttributes(); + + while (e.hasMoreElements()) { + Attribute a = (Attribute)e.nextElement(); + s.writeByte(a.getAttrID()); + this._bs.reset(); + + try { + a.generateNetData(new DataOutputStream(this._bs)); + } catch (IOException var5) { + System.err.println(var5); + throw new Error("Fatal in generateNetData"); + } + + s.writeByte(this._bs.size()); + this._bs.writeTo(s); + } + } + } + + @Override + protected void noteAddingTo(SuperRoot owner) { + WObject w = (WObject)owner.getOwner(); + if ((w.getSharer().getMode() & 1) != 0) { + throw new ClassCastException("Must forward to unforwarded object"); + } + } + + @Override + public void detach() { + if (this.wob == null && !this._waitingForFeedback) { + this.wobLoader = null; + super.detach(); + } else { + Console.println(Console.message("Shutting-down")); + if (this.wob != null) { + this.wob.detach(); + } + } + } + + @Override + public void setAttrID(int newID) { + Console.println(Console.message("Cant-change-ID")); + } + + @Override + public String toString() { + return this.wob == null ? super.toString() : super.toString() + "[forwarding wob " + this.wob.getName() + "]"; + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + assert false; + } +} diff --git a/NET/worlds/scape/EditMusicDialog.java b/NET/worlds/scape/EditMusicDialog.java new file mode 100644 index 0000000..a5720b0 --- /dev/null +++ b/NET/worlds/scape/EditMusicDialog.java @@ -0,0 +1,166 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.DialogReceiver; +import NET.worlds.console.FileSysDialog; +import NET.worlds.console.PolledDialog; +import java.awt.Button; +import java.awt.Checkbox; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Label; +import java.awt.Panel; +import java.awt.TextField; + +class EditMusicDialog extends PolledDialog implements DialogReceiver { + private TextField nameField = new TextField(20); + private TextField trackField = new TextField(3); + private TextField midiField = new TextField(30); + private Button browseButton = new Button(Console.message("Browse")); + private Checkbox loopBox = new Checkbox(Console.message("Loop-cont")); + private Button okButton = new Button(Console.message("OK")); + private Button cancelButton = new Button(Console.message("Cancel")); + private MusicManagerDialog parent; + private MusicTrack music; + private String oldName; + private String path; + private static Font font = new Font(Console.message("MenuFont"), 0, 12); + private static Font bfont = new Font(Console.message("ButtonFont"), 0, 12); + + public EditMusicDialog(MusicManagerDialog parent, MusicTrack music) { + super(parent, parent, music == null ? Console.message("Add-Music") : Console.message("Edit-Music"), true); + this.parent = parent; + this.music = music; + if (music != null) { + this.oldName = music.getName(); + } + + this.path = parent.getManager().getFileName().toLowerCase().replace('/', '\\'); + this.path = this.path.substring(0, this.path.lastIndexOf(92) + 1); + this.ready(); + } + + @Override + protected void build() { + GridBagLayout gbag = new GridBagLayout(); + this.setLayout(gbag); + GridBagConstraints c = new GridBagConstraints(); + c.fill = 0; + c.anchor = 13; + this.add(gbag, new Label(Console.message("Name"), 2), c); + c.gridwidth = 0; + c.anchor = 17; + this.nameField.setFont(font); + this.trackField.setFont(font); + this.midiField.setFont(font); + this.browseButton.setFont(bfont); + this.loopBox.setFont(font); + this.add(gbag, this.nameField, c); + c.gridwidth = 1; + c.anchor = 13; + Label vt = new Label(Console.message("Virtual-track"), 2); + vt.setFont(font); + this.add(gbag, vt, c); + c.gridwidth = 0; + c.anchor = 17; + this.add(gbag, this.trackField, c); + c.gridwidth = 1; + c.anchor = 13; + Label am = new Label(Console.message("Alternate-MIDI"), 2); + am.setFont(font); + this.add(gbag, am, c); + c.fill = 2; + c.weightx = 1.0; + c.anchor = 17; + this.add(gbag, this.midiField, c); + c.fill = 0; + c.weightx = 0.0; + c.gridwidth = 0; + this.add(gbag, this.browseButton, c); + this.add(gbag, this.loopBox, c); + c.fill = 0; + c.anchor = 10; + Panel p = new Panel(); + this.okButton.setFont(bfont); + this.cancelButton.setFont(bfont); + p.add(this.okButton); + p.add(this.cancelButton); + this.add(gbag, p, c); + if (this.music != null) { + this.nameField.setText(this.music.getName()); + this.trackField.setText("" + this.music.getVirtTrackNumber()); + this.midiField.setText(this.music.getMIDIFileName()); + this.loopBox.setState(this.music.getLooping()); + } + } + + @Override + public boolean action(java.awt.Event event, Object what) { + Object target = event.target; + if (target == this.okButton && this.nameField.getText().trim().length() != 0) { + return this.done(true); + } else if (target == this.cancelButton) { + return this.done(false); + } else { + if (target == this.browseButton) { + this.dialogDisable(true); + new FileSysDialog( + Console.getFrame(), + this, + Console.message("Browse-MIDI"), + 0, + "MIDI Files|*.mid;*.midi|All Files|*.*", + this.path + this.midiField.getText(), + false + ); + } + + return false; + } + } + + @Override + public synchronized void dialogDone(Object who, boolean confirmed) { + this.dialogDisable(false); + if (confirmed && who instanceof FileSysDialog) { + String name = ((FileSysDialog)who).fileName().toLowerCase(); + if (name.startsWith(this.path)) { + this.midiField.setText(name.substring(this.path.length())); + } + } + } + + public boolean isEditor() { + return this.music != null; + } + + public MusicTrack getMusicTrack() { + String name = this.nameField.getText().trim(); + int track = 0; + + try { + track = Integer.parseInt(this.trackField.getText()); + } catch (NumberFormatException var5) { + } + + String midi = this.midiField.getText().trim(); + boolean loop = this.loopBox.getState(); + if (this.music == null) { + return new MusicTrack(name, track, midi, loop); + } else { + this.music.setName(name); + if (track != -1) { + this.music.setVirtTrackNumber(track); + } + + this.music.setMIDIFileName(midi); + this.music.setLooping(loop); + return this.music; + } + } + + public String getOldName() { + return this.oldName; + } +} diff --git a/NET/worlds/scape/EditRoomDialog.java b/NET/worlds/scape/EditRoomDialog.java new file mode 100644 index 0000000..eca4180 --- /dev/null +++ b/NET/worlds/scape/EditRoomDialog.java @@ -0,0 +1,122 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.PolledDialog; +import NET.worlds.core.Sort; +import java.awt.Button; +import java.awt.Choice; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Label; +import java.awt.Panel; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +class EditRoomDialog extends PolledDialog { + private Choice roomChoice = new Choice(); + private Choice musicChoice = new Choice(); + private Button okButton = new Button(Console.message("OK")); + private Button cancelButton = new Button(Console.message("Cancel")); + private MusicManagerDialog parent; + private MusicRoom room; + private String startSelect; + private static String lastMusic; + private static Font font = new Font(Console.message("MenuFont"), 0, 12); + private static Font bfont = new Font(Console.message("ButtonFont"), 0, 12); + + public EditRoomDialog(MusicManagerDialog parent, MusicRoom room, String startSelect) { + super(parent, parent, Console.message("Assign-Music"), true); + this.parent = parent; + this.room = room; + this.startSelect = startSelect; + this.ready(); + } + + @Override + protected void build() { + GridBagLayout gbag = new GridBagLayout(); + this.setLayout(gbag); + GridBagConstraints c = new GridBagConstraints(); + c.fill = 0; + c.anchor = 13; + Label lName = new Label(Console.message("Room-name"), 2); + lName.setFont(font); + this.add(gbag, lName, c); + c.gridwidth = 0; + c.anchor = 17; + this.roomChoice.setFont(font); + this.add(gbag, this.roomChoice, c); + c.gridwidth = 1; + c.anchor = 13; + Label lMusic = new Label(Console.message("Music"), 2); + lMusic.setFont(font); + this.add(gbag, lMusic, c); + c.gridwidth = 0; + c.anchor = 17; + this.musicChoice.setFont(font); + this.add(gbag, this.musicChoice, c); + c.anchor = 10; + Panel p = new Panel(); + p.setFont(bfont); + p.add(this.okButton); + p.add(this.cancelButton); + this.add(gbag, p, c); + this.roomChoice.setFont(font); + this.musicChoice.setFont(font); + if (this.room != null) { + this.roomChoice.add(this.room.getRoomName()); + } + + Enumeration e = this.parent.getAllRooms().elements(); + Hashtable roomsWithMusic = this.parent.getManager().getRooms(); + Vector v = new Vector(); + + while (e.hasMoreElements()) { + String name = (String)e.nextElement(); + if (!roomsWithMusic.containsKey(name)) { + v.addElement(name); + } + } + + Sort.sortInto(this.roomChoice, v); + Sort.sortInto(this.musicChoice, this.parent.getManager().getMusic()); + if (this.room != null) { + this.roomChoice.select(this.room.getRoomName()); + this.musicChoice.select(this.room.getMusicName()); + } else { + this.roomChoice.select(this.startSelect); + if (lastMusic != null) { + this.musicChoice.select(lastMusic); + } + } + } + + @Override + public boolean action(java.awt.Event event, Object what) { + Object target = event.target; + if (target == this.okButton) { + return this.done(true); + } else { + return target == this.cancelButton ? this.done(false) : false; + } + } + + public boolean isEditor() { + return this.room != null; + } + + public MusicRoom getMusicRoom() { + String roomName = this.roomChoice.getSelectedItem(); + String musicName = this.musicChoice.getSelectedItem(); + lastMusic = musicName; + if (this.room == null) { + return new MusicRoom(roomName, musicName); + } else { + this.room.setRoomName(roomName); + this.room.setMusicName(musicName); + return this.room; + } + } +} diff --git a/NET/worlds/scape/EditTile.java b/NET/worlds/scape/EditTile.java new file mode 100644 index 0000000..d0ab600 --- /dev/null +++ b/NET/worlds/scape/EditTile.java @@ -0,0 +1,664 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.DialogDisabled; +import NET.worlds.console.DialogReceiver; +import NET.worlds.console.ExposedPanel; +import NET.worlds.console.Main; +import NET.worlds.console.MainCallback; +import NET.worlds.console.PolledDialog; +import NET.worlds.console.RenderCanvas; +import NET.worlds.console.SnapTool; +import NET.worlds.console.Tree; +import NET.worlds.console.TreeCallback; +import NET.worlds.network.URL; +import java.awt.Button; +import java.awt.Component; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Label; +import java.awt.Point; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.Enumeration; +import java.util.Vector; + +public class EditTile extends ExposedPanel implements DialogReceiver, TreeCallback, MainCallback, DialogDisabled { + private Button editButton = new Button(Console.message("Edit")); + private Button addButton = new Button(Console.message("Add")); + private Button delButton = new Button(Console.message("Delete")); + private Button helpButton = new Button(Console.message("Help")); + private ToolBar toolbar = new ToolBar(); + private Label title = new Label(); + private String titleText = ""; + private boolean usingTitleAsPrompt; + private PropList props = new PropList(); + private int queuedFunction = 0; + private Object queuedObject; + private Tree tree; + private PolledDialog activePopup; + private boolean startup = true; + private World rootWorld = null; + private boolean isDialogDisabled; + private static final int NONE = 0; + private static final int DELETE = 1; + private static final int ADD = 2; + private static final int CHANGE = 3; + private static final int UPDATE = 4; + private static final int CUT = 5; + private static final int COPY = 6; + private static final int PASTE = 7; + private static final int UNDO = 8; + private static final int EDIT = 9; + private static final int DROP = 10; + private static final int HELP = 11; + private static ClipboardEntry clipboard; + private static UndoStack undoStack = new UndoStack(); + private Undoable preAddStackTop; + private boolean isAdd; + private SendURLAction helpAction = new SendURLAction(); + private Persister helpBrowser; + + public void viewProperties(Object obj) { + Console.getFrame().setShaperVisible(true); + this.queue(3, obj); + } + + public void libraryDrop(URL url, String propertyName, Component comp, Point location) { + this.queue(10, new DropInfo(url, propertyName, comp, location)); + } + + public EditTile(Tree tree) { + this.tree = tree; + tree.setOwner(this); + GridBagLayout gbag = new GridBagLayout(); + this.setLayout(gbag); + GridBagConstraints c = new GridBagConstraints(); + c.fill = 2; + c.gridwidth = 0; + c.weightx = 1.0; + c.weighty = 0.0; + c.anchor = 18; + this.add(gbag, this.toolbar, c); + this.add(gbag, this.title, c); + c.weighty = 1.0; + c.fill = 1; + c.gridwidth = 2; + c.gridheight = 0; + this.add(gbag, this.props, c); + c.weightx = 0.0; + c.weighty = 0.0; + c.gridwidth = 0; + c.gridheight = 1; + c.fill = 2; + this.add(gbag, this.editButton, c); + this.add(gbag, this.addButton, c); + this.add(gbag, this.delButton, c); + this.add(gbag, this.helpButton, c); + Main.register(this); + } + + public void update() { + this.queue(4); + } + + private void add(GridBagLayout gbag, Component comp, GridBagConstraints c) { + gbag.setConstraints(comp, c); + this.add(comp); + } + + private boolean queue(int function) { + return this.queue(function, null); + } + + private synchronized boolean queue(int function, Object obj) { + if (this.queuedFunction == 0 && this.activePopup == null) { + this.queuedFunction = function; + this.queuedObject = obj; + this.disable(); + } + + return true; + } + + @Override + public synchronized void mainCallback() { + if (this.startup) { + World w = Pilot.getActiveWorld(); + if (w != null) { + this.change(w); + this.startup = false; + } + } + + if (this.rootWorld != null) { + this.rootWorld.incRef(); + } + + boolean enable = true; + switch (this.queuedFunction) { + case 0: + return; + case 1: + this.delete(false); + break; + case 2: + enable = this.doAdd(); + break; + case 3: + this.change(this.queuedObject); + break; + case 4: + this.tree.update(); + break; + case 5: + this.delete(true); + break; + case 6: + this.doCopy(); + break; + case 7: + this.doPaste(); + break; + case 8: + this.doUndo(); + break; + case 9: + enable = this.doEdit(); + break; + case 10: + if (!this.drop((DropInfo)this.queuedObject)) { + Object[] arguments = new Object[]{new String("" + ((DropInfo)this.queuedObject).url)}; + Console.println(MessageFormat.format(Console.message("Target-doesnt"), arguments)); + } + break; + case 11: + this.doHelp(); + } + + this.enable(enable); + this.queuedFunction = 0; + this.queuedObject = null; + } + + private void delete(boolean isCut) { + if (this.delButton.isEnabled()) { + PropTreeNode e = (PropTreeNode)this.tree.getSelectedNode(); + if (e != null && this.tree.hasFocus()) { + this.addUndoable(e.delete(isCut)); + } else { + Property p = this.props.getSelectedProperty(); + + assert p.canSetNull() && p.get() != null; + + this.addUndoableSet(p, null); + } + + this.tree.update(); + } + } + + public static void adjustDroppedSource(SuperRoot sr) { + if (sr != null && (!(sr instanceof WObject) || !((WObject)sr).isDynamic())) { + sr.setSourceURL(null); + } + } + + private boolean drop(DropInfo info) { + Object dropped = info.url; + if (info.url.endsWith(".class") || info.url.endsWith("." + WObject.getSaveExtension())) { + SuperRoot sr = WobLoader.immediateLoad(info.url); + adjustDroppedSource(sr); + dropped = sr; + } + + return this.drop(dropped, info.propertyName, false, info.comp, info.location); + } + + private boolean drop(Object obj, String propertyName, boolean isPaste) { + return this.drop(obj, propertyName, isPaste, null, null); + } + + private boolean drop(Object obj, String propertyName, boolean isPaste, Component comp, Point location) { + if (obj == null) { + return false; + } else { + PropTreeNode e = null; + Point3Temp dropPoint = null; + if (comp == null && this.tree.hasFocus()) { + e = (PropTreeNode)this.tree.getSelectedNode(); + } else if (comp == this.tree) { + e = (PropTreeNode)this.tree.elementAt(location); + } else if (comp instanceof RenderCanvas) { + Camera c = ((RenderCanvas)comp).getCamera(); + dropPoint = Point3Temp.make(); + WObject picked = c.getObjectAt(location.x, location.y, false, dropPoint); + if (picked != null) { + if (obj instanceof WObject) { + picked = picked.getRoom(); + } + } else { + Pilot pilot = Pilot.getActive(); + picked = pilot.getRoom(); + dropPoint.set(0.0F, 180.0F, 0.0F); + dropPoint.times(pilot); + } + + if (picked != null) { + this.change(picked); + e = (PropTreeNode)this.tree.getSelectedNode(); + } + } + + if (e == null) { + return false; + } else { + boolean success = false; + VectorProperty vp; + PropAdder adder; + if ((vp = e.getContainingVectorProperty()) != null && (adder = vp.getAdder()) != null) { + success = adder.libraryDrop(this, obj, isPaste, true); + } + + if (!success) { + Object top; + for (top = null; e != null; e = (PropTreeNode)e.getParent()) { + top = e.getObject(); + if (top instanceof Properties) { + break; + } + + if (top instanceof Property) { + Property prop = (Property)top; + top = ((Property)top).get(); + if (top instanceof Properties) { + break; + } + } + } + + if (e != null) { + Vector targets = new Vector(); + int topLevelTargets = this.recurseFindDropTargets(targets, obj, propertyName, isPaste, new EnumProperties(top), 0, 10); + if (topLevelTargets == 1 || topLevelTargets == 0 && targets.size() == 1) { + success = ((LibraryDrop)targets.elementAt(0)).libraryDrop(this, obj, isPaste, true); + } + } + } + + if (success) { + if (obj instanceof Properties) { + this.change(obj); + } else { + this.tree.update(); + } + } + + WObject wobj; + if (dropPoint != null && obj instanceof WObject && !(obj instanceof Room) && (wobj = (WObject)obj).isActive()) { + dropPoint.z = wobj.getZ(); + wobj.moveTo(SnapTool.snapTool().snapTo(dropPoint)); + } + + return success; + } + } + } + + private int recurseFindDropTargets(Vector targets, Object obj, String propertyName, boolean isPaste, Enumeration props, int level, int maxLevel) { + int firstLevelMatches = 0; + if (level > maxLevel) { + return 0; + } else { + while (props.hasMoreElements()) { + Property p = (Property)props.nextElement(); + boolean propMatch = propertyName == null || propertyName.equals(p.getName()); + if (propMatch) { + LibraryDrop target = null; + if (p instanceof VectorProperty) { + target = ((VectorProperty)p).getAdder(); + } else { + target = p.getEditor(); + } + + if (target != null && target.libraryDrop(this, obj, isPaste, false)) { + if (level == 0) { + targets.insertElementAt(target, firstLevelMatches++); + } else { + targets.addElement(target); + } + continue; + } + } + + if (!(p instanceof VectorProperty)) { + int err = this.recurseFindDropTargets(targets, obj, propertyName, isPaste, new EnumProperties(p.get()), level + 1, maxLevel); + if (err != 0) { + return err; + } + } + } + + return firstLevelMatches; + } + } + + private boolean change(Object obj) { + Object parent = obj; + Vector lineage = new Vector(); + + Object p; + while (parent instanceof Properties && (p = ((Properties)parent).propertyParent()) != null) { + if (lineage != null) { + Enumeration e = new EnumProperties(p); + boolean found = false; + + while (e.hasMoreElements()) { + Property prop = (Property)e.nextElement(); + Object o = prop.get(); + boolean isVector = prop instanceof VectorProperty; + if (o == parent || isVector && o != null && ((Vector)o).indexOf(parent) != -1) { + if (isVector) { + lineage.insertElementAt(parent, 0); + } + + lineage.insertElementAt(prop, 0); + found = true; + break; + } + } + + if (!found) { + lineage = null; + } + } + + parent = p; + } + + this.rootWorld = null; + if (parent instanceof World) { + this.rootWorld = (World)parent; + } + + PropTreeNode root = new PropTreeNode(parent); + if (lineage != null) { + this.tree.change(root, lineage); + } else { + this.tree.change(root, obj); + } + + return true; + } + + @Override + public void treeFocusChanged(boolean hasFocus) { + if (hasFocus) { + this.props.deselect(this.props.getSelectedIndex()); + this.adjustButtons(); + } + } + + @Override + public void treeChange(Object obj) { + if (obj instanceof Property && !(obj instanceof VectorProperty)) { + obj = ((Property)obj).get(); + } + + this.props.setObject(obj); + this.toolbar.setCurrentObject(obj); + String name = obj.getClass().getName(); + int index; + if ((index = name.lastIndexOf(46)) != -1) { + name = name.substring(index + 1); + } + + this.setTitle(name + " " + Console.message("Properties")); + this.adjustButtons(); + } + + private void setTitle(String titleText) { + this.titleText = titleText; + if (!this.usingTitleAsPrompt) { + this.title.setText(titleText); + } + } + + public void setPrompt(String promptText) { + this.title.setText((this.usingTitleAsPrompt = promptText != null) ? promptText : this.titleText); + } + + private void adjustButtons() { + PropTreeNode e = (PropTreeNode)this.tree.getSelectedNode(); + if (e != null && this.tree.hasFocus()) { + this.editButton.enable(e.canEdit()); + this.delButton.enable(e.canDelete()); + this.addButton.enable(e.canAdd()); + this.helpButton.enable(true); + } else { + Property p = this.props.getSelectedProperty(); + if (p != null) { + Object obj = p.get(); + this.editButton.enable(p.getEditor() != null); + this.delButton.enable(p.canSetNull() && obj != null); + this.addButton.enable(p.canSetNull() && p.getEditor() != null && obj == null); + this.helpButton.enable(p.helpExists); + } else { + this.editButton.disable(); + this.delButton.disable(); + this.addButton.disable(); + this.helpButton.disable(); + } + } + } + + @Override + public void dialogDisable(boolean disable) { + this.isDialogDisabled = disable; + this.toolbar.dialogDisable(disable); + } + + @Override + public boolean handleEvent(java.awt.Event event) { + if (event.id == 701) { + if (event.target == this.props) { + this.tree.setFocus(false); + } + + this.adjustButtons(); + } + + return this.isDialogDisabled ? false : super.handleEvent(event); + } + + @Override + public boolean action(java.awt.Event event, Object what) { + Object target = event.target; + if (target == this.delButton) { + return this.queue(1); + } else if (target == this.addButton) { + return this.queue(2); + } else if (target != this.editButton && (target != this.props || !this.editButton.isEnabled())) { + return target == this.helpButton ? this.queue(11) : false; + } else { + return this.queue(9); + } + } + + @Override + public void dialogDone(Object who, boolean confirmed) { + if (who == this.activePopup) { + this.activePopup = null; + this.tree.enable(); + if (confirmed) { + Undoable u; + Object obj; + if (this.isAdd + && (u = undoStack.peek()) != this.preAddStackTop + && u instanceof UndoablAdd + && (obj = ((UndoablAdd)u).getObject()) instanceof Properties) { + this.change(obj); + } else { + this.tree.update(); + } + } + + this.enable(); + } + } + + private boolean doEdit() { + Property p = this.props.getSelectedProperty(); + PropEditor editor; + if (p != null && (editor = p.getEditor()) != null) { + this.isAdd = false; + this.activePopup = editor.edit(this, "Edit " + p.getName()); + this.tree.disable(); + return false; + } else { + return true; + } + } + + private boolean doAdd() { + PropTreeNode e = (PropTreeNode)this.tree.getSelectedNode(); + PropAdder adder; + if (e != null && this.tree.hasFocus() && (adder = e.getAdder()) != null) { + this.preAddStackTop = undoStack.peek(); + this.isAdd = true; + this.activePopup = adder.add(this, "Add to " + e.getContainerName()); + this.tree.disable(); + return false; + } else { + return true; + } + } + + public void cut() { + this.queue(5); + } + + public void paste() { + this.queue(7); + } + + private boolean doPaste() { + if (clipboard != null) { + SuperRoot obj = clipboard.paste(); + if (this.drop(obj, null, true)) { + return true; + } + + clipboard.unPaste(obj); + Console.println(Console.message("Clip-contents")); + } else { + Console.println(Console.message("Clip-empty")); + } + + return false; + } + + private boolean doHelp() { + this.helpAction.showDialog = false; + if (this.tree.hasFocus() && this.props.getSelectedProperty() == null) { + try { + SuperRoot s = (SuperRoot)((PropTreeNode)this.tree.getSelectedNode()).getObject(); + if (s != null) { + this.helpAction.setDestination(s.getHelpURL()); + } + } catch (ClassCastException var5) { + Console.println(Console.message("No-help")); + } + } else { + Property p = this.props.getSelectedProperty(); + if (p != null && p.helpExists) { + try { + SuperRoot s = (SuperRoot)((PropTreeNode)this.tree.getSelectedNode()).getObject(); + if (s != null) { + this.helpAction.setDestination(s.getHelpURL(p)); + } + } catch (ClassCastException var4) { + Console.println(Console.message("No-help")); + } + } + } + + this.helpBrowser = this.helpAction.trigger(null, this.helpBrowser); + return true; + } + + public void copy() { + this.queue(6); + } + + private void doCopy() { + SuperRoot item = this.getCurSuperRoot(true); + if (item != null) { + ClipboardEntry newClip = new ClipboardEntry(); + if (newClip.copy(item)) { + this.addUndoable(new UndoabCopy(newClip)); + } + } + } + + public boolean save(String fileName) { + SuperRoot item = this.getCurSuperRoot(true); + + try { + item.saveFile(new URL(URL.getCurDir(), fileName)); + return true; + } catch (IOException var4) { + return false; + } + } + + private SuperRoot getCurSuperRoot(boolean allowContainers) { + Object obj = this.props.getObject(); + return obj instanceof SuperRoot ? (SuperRoot)obj : null; + } + + public void addUndoable(Undoable u) { + undoStack.push(u); + } + + public void addUndoableSet(Property prop, Object obj) { + this.addUndoable(new UndoablSet(prop, obj)); + } + + public void addUndoableAdd(VectorProperty prop, Object obj, boolean changeTree) { + this.addUndoable(new UndoablAdd(prop, obj)); + if (!changeTree) { + this.preAddStackTop = undoStack.peek(); + } + } + + public void addUndoablePaste(VectorProperty prop, Object obj) { + try { + this.addUndoable(new UndoablPaste(prop, clipboard, obj)); + } catch (Error var4) { + Console.println(var4.getMessage()); + } + } + + public void undo() { + if (Main.isMainThread()) { + this.doUndo(); + } else { + this.queue(8); + } + } + + private void doUndo() { + if (undoStack.undo()) { + this.tree.update(); + } + } + + public static void setClipboard(ClipboardEntry clip) { + clipboard = clip; + } + + public static ClipboardEntry getClipboard() { + return clipboard; + } +} diff --git a/NET/worlds/scape/EnumFieldEditorDialog.java b/NET/worlds/scape/EnumFieldEditorDialog.java new file mode 100644 index 0000000..0fccdc7 --- /dev/null +++ b/NET/worlds/scape/EnumFieldEditorDialog.java @@ -0,0 +1,23 @@ +package NET.worlds.scape; + +class EnumFieldEditorDialog extends CheckboxEditorDialog { + private Property property; + private int[] numbers; + + EnumFieldEditorDialog(EditTile parent, String title, Property property, String[] choices, int[] values) { + super(parent, title, choices); + this.property = property; + this.numbers = values; + this.ready(); + } + + @Override + protected int getValue() { + return (Integer)this.property.get(); + } + + @Override + protected void setValue(int choice) { + this.parent.addUndoableSet(this.property, new Integer(this.numbers[choice])); + } +} diff --git a/NET/worlds/scape/EnumProperties.java b/NET/worlds/scape/EnumProperties.java new file mode 100644 index 0000000..a6fbdc9 --- /dev/null +++ b/NET/worlds/scape/EnumProperties.java @@ -0,0 +1,46 @@ +package NET.worlds.scape; + +import java.util.Enumeration; +import java.util.NoSuchElementException; + +public class EnumProperties implements Enumeration<Object> { + private Properties props; + private Property next; + private int index = 0; + + public EnumProperties(Object obj) { + if (obj instanceof Properties) { + this.props = (Properties)obj; + } + } + + @Override + public boolean hasMoreElements() { + if (this.props != null && this.next == null) { + try { + this.next = (Property)this.props.properties(this.index++, 0, 0, null); + + assert this.next.index == this.index - 1; + } catch (NoSuchPropertyException var2) { + } + } + + return this.next != null; + } + + @Override + public Object nextElement() { + if (this.hasMoreElements()) { + Property var2; + try { + var2 = this.next; + } finally { + this.next = null; + } + + return var2; + } else { + throw new NoSuchElementException(); + } + } +} diff --git a/NET/worlds/scape/EnumPropertyEditor.java b/NET/worlds/scape/EnumPropertyEditor.java new file mode 100644 index 0000000..07a363a --- /dev/null +++ b/NET/worlds/scape/EnumPropertyEditor.java @@ -0,0 +1,47 @@ +package NET.worlds.scape; + +import NET.worlds.console.PolledDialog; + +public class EnumPropertyEditor extends PropEditor { + private String[] choices; + private int[] numbers; + + private EnumPropertyEditor(Property property, String[] names, int[] values) { + super(property); + + assert names != null; + + assert values != null; + + int len = Math.max(names.length, values.length); + + assert len > 1; + + this.choices = new String[len]; + this.numbers = new int[len]; + + for (int i = 0; i < len; i++) { + if (i < names.length) { + this.choices[i] = names[i]; + } else { + this.choices[i] = names[names.length - 1] + i; + } + + if (i < values.length) { + this.numbers[i] = values[i]; + } else { + this.numbers[i] = values[values.length - 1] + i - values.length; + } + } + } + + @Override + public PolledDialog edit(EditTile parent, String title) { + return new EnumFieldEditorDialog(parent, title, this.property, this.choices, this.numbers); + } + + public static Property make(Property property, String[] names, int[] values) { + property.setPropertyType(5); + return property.setEditor(new EnumPropertyEditor(property, names, values)); + } +} diff --git a/NET/worlds/scape/EquipAction.java b/NET/worlds/scape/EquipAction.java new file mode 100644 index 0000000..b196e1b --- /dev/null +++ b/NET/worlds/scape/EquipAction.java @@ -0,0 +1,35 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import java.io.IOException; +import java.util.Vector; + +public class EquipAction extends Action { + private static Object classCookie = new Object(); + + @Override + public Persister trigger(Event arg, Persister seqID) { + Vector equippableItems = InventoryManager.getInventoryManager().getEquippableItems(); + new Vector(); + InventoryDialog invDialog = new InventoryDialog(Console.getFrame()); + invDialog.show(); + return null; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/EquippableItem.java b/NET/worlds/scape/EquippableItem.java new file mode 100644 index 0000000..c8385b1 --- /dev/null +++ b/NET/worlds/scape/EquippableItem.java @@ -0,0 +1,136 @@ +package NET.worlds.scape; + +public class EquippableItem extends InventoryItem { + private String modelLocation_; + private float xPos_; + private float yPos_; + private float zPos_; + private float scale_; + private int pitch_; + private int roll_; + private int yaw_; + private Shape shape_; + private int bodyLocation_; + + public EquippableItem(String id, String name, int qty, String modelLoc, float scale, int bodyLoc) { + super(id, name, qty); + this.modelLocation_ = modelLoc; + this.scale_ = scale; + this.bodyLocation_ = bodyLoc; + this.shape_ = null; + } + + public EquippableItem(String id, String name, int qty, String modelLoc, float scale, int bodyLoc, float xPos, float yPos, float zPos) { + super(id, name, qty); + this.modelLocation_ = modelLoc; + this.scale_ = scale; + this.bodyLocation_ = bodyLoc; + this.xPos_ = xPos; + this.yPos_ = yPos; + this.zPos_ = zPos; + this.shape_ = null; + } + + public EquippableItem( + String id, String name, int qty, String modelLoc, float scale, int bodyLoc, float xPos, float yPos, float zPos, int pitch, int roll, int yaw + ) { + super(id, name, qty); + this.modelLocation_ = modelLoc; + this.scale_ = scale; + this.bodyLocation_ = bodyLoc; + this.xPos_ = xPos; + this.yPos_ = yPos; + this.zPos_ = zPos; + this.pitch_ = pitch; + this.roll_ = roll; + this.yaw_ = yaw; + this.shape_ = null; + } + + public EquippableItem(EquippableItem in) { + super(in); + this.modelLocation_ = in.modelLocation_; + this.scale_ = in.scale_; + this.bodyLocation_ = in.bodyLocation_; + this.xPos_ = in.xPos_; + this.yPos_ = in.yPos_; + this.zPos_ = in.zPos_; + this.pitch_ = in.pitch_; + this.roll_ = in.roll_; + this.yaw_ = in.yaw_; + this.shape_ = null; + } + + @Override + public InventoryItem cloneItem() { + return new EquippableItem(this); + } + + public String getModelLocation() { + return this.modelLocation_; + } + + public void setModelLocation(String loc) { + this.modelLocation_ = loc; + } + + public int getBodyLocation() { + return this.bodyLocation_; + } + + public void setBodyLocation(int loc) { + this.bodyLocation_ = loc; + } + + public float getScale() { + return this.scale_; + } + + public void setScale(float scale) { + this.scale_ = scale; + } + + public float getXPos() { + return this.xPos_; + } + + public float getYPos() { + return this.yPos_; + } + + public float getZPos() { + return this.zPos_; + } + + public void setPosition(float xPos, float yPos, float zPos) { + this.xPos_ = xPos; + this.yPos_ = yPos; + this.zPos_ = zPos; + } + + public int getPitch() { + return this.pitch_; + } + + public int getRoll() { + return this.roll_; + } + + public int getYaw() { + return this.yaw_; + } + + public void setRotation(int pitch, int roll, int yaw) { + this.pitch_ = pitch; + this.roll_ = roll; + this.yaw_ = yaw; + } + + public void setOwnedShape(Shape s) { + this.shape_ = s; + } + + public Shape getOwnedShape() { + return this.shape_; + } +} diff --git a/NET/worlds/scape/Event.java b/NET/worlds/scape/Event.java new file mode 100644 index 0000000..69c9c6a --- /dev/null +++ b/NET/worlds/scape/Event.java @@ -0,0 +1,74 @@ +package NET.worlds.scape; + +public class Event implements Cloneable { + public static final Class eventSuperclass = new Object().getClass(); + public int time; + public Object source; + public WObject target; + public WObject receiver; + + public Event(int time, Object source, WObject target) { + this.time = time; + this.source = source; + this.target = target; + } + + @Override + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException var2) { + System.out.println("Clone of Object not supported!"); + return null; + } + } + + public boolean isA(Class c) { + for (Class t = this.getClass(); t != eventSuperclass; t = t.getSuperclass()) { + if (t == c) { + return true; + } + } + + return false; + } + + public boolean deliver(Object o) { + return o instanceof Handler && ((Handler)o).handle(this); + } + + @Override + public String toString() { + String result = "Event at " + this.time; + String sname = null; + if (this.source instanceof SuperRoot) { + sname = ((SuperRoot)this.source).getName(); + } else if (this.source != null) { + sname = this.source.toString(); + } + + if (sname != null) { + result = result + " from " + sname; + } + + String tname = null; + if (this.target != null) { + this.target.getName(); + } + + if (tname != null) { + result = result + " to " + tname; + } + + String rname = null; + if (this.receiver != null) { + this.receiver.getName(); + } + + if (rname != null) { + result = result + " handled by " + rname; + } + + return result; + } +} diff --git a/NET/worlds/scape/EventQueue.java b/NET/worlds/scape/EventQueue.java new file mode 100644 index 0000000..83008d3 --- /dev/null +++ b/NET/worlds/scape/EventQueue.java @@ -0,0 +1,125 @@ +package NET.worlds.scape; + +import NET.worlds.core.Std; + +public class EventQueue { + private static final int keyDown = 1; + private static final int keyUp = 2; + private static final int keyChar = 3; + private static final int mouseDown = 4; + private static final int mouseUp = 5; + private static final int mouseMove = 6; + private static final int mouseDelta = 7; + private static final int mouseEnter = 8; + private static final int mouseExit = 9; + private static final int teleport = 10; + private char key; + private int type; + private int time; + private int x; + private int y; + private static EventQueue dequeueInfo = new EventQueue(); + + static { + nativeInit(); + } + + public static void pollForEvents(Camera eventEater) { + if (eventEater != null) { + int eventCount = getEventCount(); + + Event e; + while (eventCount-- > 0 && (e = dequeueInfo.dequeue()) != null) { + if (e.target == null) { + e.target = eventEater; + } + + eventEater.deliver(e); + } + } + } + + public static boolean redirectDrivingKeys(java.awt.Event e) { + boolean press; + if (!(press = e.id == 403) && e.id != 404) { + return false; + } else { + char newKey; + switch (e.key) { + case 27: + newKey = '\ue31b'; + break; + case 1000: + newKey = '\ue324'; + break; + case 1001: + newKey = '\ue323'; + break; + case 1002: + newKey = '\ue321'; + break; + case 1003: + newKey = '\ue322'; + break; + case 1004: + newKey = '\ue326'; + break; + case 1005: + newKey = '\ue328'; + break; + case 1006: + newKey = '\ue325'; + break; + case 1007: + newKey = '\ue327'; + break; + default: + return false; + } + + addEvent(newKey, press ? 1 : 2, Std.getTimeZero() + Std.getRealTime(), e.x, e.y); + return true; + } + } + + private EventQueue() { + } + + private Event dequeue() { + if (this.getNextEvent()) { + this.time = this.time - Std.getTimeZero(); + switch (this.type) { + case 1: + return new KeyDownEvent(this.time, null, this.key); + case 2: + return new KeyUpEvent(this.time, null, this.key); + case 3: + return new KeyCharEvent(this.time, null, this.key); + case 4: + return new MouseDownEvent(this.time, null, this.key, this.x, this.y); + case 5: + return new MouseUpEvent(this.time, null, this.key, this.x, this.y); + case 6: + return new MouseMoveEvent(this.time, null, this.x, this.y); + case 7: + return new MouseDeltaEvent(this.time, null, this.x, this.y); + case 8: + return new MouseEnterEvent(this.time, null, this.x, this.y); + case 9: + return new MouseExitEvent(this.time, null, this.x, this.y); + default: + throw new Error("Illegal internal event type"); + } + } else { + return null; + } + } + + public static native void nativeInit(); + + private native boolean getNextEvent(); + + private static native int getEventCount(); + + private static native void addEvent(char var0, int var1, int var2, int var3, int var4); +} diff --git a/NET/worlds/scape/ExtensionFilter.java b/NET/worlds/scape/ExtensionFilter.java new file mode 100644 index 0000000..b02bcfc --- /dev/null +++ b/NET/worlds/scape/ExtensionFilter.java @@ -0,0 +1,17 @@ +package NET.worlds.scape; + +import java.io.File; +import java.io.FilenameFilter; + +public class ExtensionFilter implements FilenameFilter { + private String _ext; + + public ExtensionFilter(String ext) { + this._ext = ext; + } + + @Override + public boolean accept(File dir, String name) { + return name.endsWith(this._ext); + } +} diff --git a/NET/worlds/scape/Facer.java b/NET/worlds/scape/Facer.java new file mode 100644 index 0000000..913fc96 --- /dev/null +++ b/NET/worlds/scape/Facer.java @@ -0,0 +1,14 @@ +package NET.worlds.scape; + +import java.io.IOException; + +class Facer extends SwitchableBehavior { + @Override + public void saveState(Saver s) throws IOException { + } + + @Override + public void restoreState(Restorer r) throws IOException { + System.out.println("WARNING! Facers are obsolete. Use 1-image Holograms instead."); + } +} diff --git a/NET/worlds/scape/FieldEditorDialog.java b/NET/worlds/scape/FieldEditorDialog.java new file mode 100644 index 0000000..04e496c --- /dev/null +++ b/NET/worlds/scape/FieldEditorDialog.java @@ -0,0 +1,47 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.OkCancelDialog; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.TextField; + +public abstract class FieldEditorDialog extends OkCancelDialog { + private TextField strField = new TextField(40); + protected EditTile parent; + private static Font font = new Font(Console.message("GammaTextFont"), 0, 12); + + protected FieldEditorDialog(EditTile parent, String title) { + super(Console.getFrame(), parent, title); + this.parent = parent; + } + + @Override + protected void build() { + GridBagConstraints c = new GridBagConstraints(); + c.fill = 2; + c.weightx = 1.0; + c.weighty = 1.0; + c.gridwidth = 0; + this.strField.setFont(font); + this.add(this.gbag, this.strField, c); + super.build(); + } + + protected abstract String getValue(); + + protected abstract boolean setValue(String var1); + + @Override + protected boolean setValue() { + return this.setValue(this.strField.getText().trim()); + } + + @Override + public void show() { + super.show(); + this.strField.setText(this.getValue()); + this.strField.requestFocus(); + this.strField.selectAll(); + } +} diff --git a/NET/worlds/scape/FieldWithListEditorDialog.java b/NET/worlds/scape/FieldWithListEditorDialog.java new file mode 100644 index 0000000..26c0a37 --- /dev/null +++ b/NET/worlds/scape/FieldWithListEditorDialog.java @@ -0,0 +1,83 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.OkCancelDialog; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.List; +import java.awt.TextField; +import java.util.Enumeration; +import java.util.Vector; + +public abstract class FieldWithListEditorDialog extends OkCancelDialog { + private TextField strField = new TextField(40); + private List list = new List(); + private Vector choices; + protected EditTile parent; + private static Font font = new Font(Console.message("GammaTextFont"), 0, 12); + + protected FieldWithListEditorDialog(EditTile parent, String title, Vector choices) { + super(Console.getFrame(), parent, title); + this.choices = choices; + this.parent = parent; + } + + @Override + protected void build() { + Enumeration e = this.choices.elements(); + + while (e.hasMoreElements()) { + this.list.addItem((String)e.nextElement()); + } + + GridBagConstraints c = new GridBagConstraints(); + c.fill = 2; + c.weightx = 0.0; + c.weighty = 0.0; + c.gridwidth = 0; + this.strField.setFont(font); + this.add(this.gbag, this.strField, c); + c.fill = 1; + c.weightx = 1.0; + c.weighty = 1.0; + c.gridheight = 6; + this.add(this.gbag, this.list, c); + super.build(); + } + + @Override + public boolean handleEvent(java.awt.Event event) { + if (event.id == 701) { + this.strField.setText(this.list.getSelectedItem()); + this.strField.selectAll(); + } + + return super.handleEvent(event); + } + + @Override + public boolean action(java.awt.Event event, Object what) { + if (event.target == this.list) { + event.target = this.okButton; + } + + return super.action(event, what); + } + + protected abstract String getValue(); + + protected abstract boolean setValue(String var1); + + @Override + protected boolean setValue() { + return this.setValue(this.strField.getText().trim()); + } + + @Override + public void show() { + super.show(); + this.strField.setText(this.getValue()); + this.strField.requestFocus(); + this.strField.selectAll(); + } +} diff --git a/NET/worlds/scape/FileList.java b/NET/worlds/scape/FileList.java new file mode 100644 index 0000000..c7c8a24 --- /dev/null +++ b/NET/worlds/scape/FileList.java @@ -0,0 +1,132 @@ +package NET.worlds.scape; + +import java.io.File; +import java.io.FilenameFilter; +import java.util.Enumeration; +import java.util.StringTokenizer; +import java.util.Vector; + +public class FileList implements FilenameFilter { + private String dirList; + private String extList; + private Vector<String> exts; + private boolean keepPathInfo; + private boolean sort = true; + + public FileList(String dirList, String extList) { + this.dirList = dirList; + this.extList = extList; + } + + public String getExtList() { + return this.extList; + } + + private static Vector<String> breakUp(String list) { + StringTokenizer t = new StringTokenizer(list, File.pathSeparator, false); + Vector<String> v = new Vector<String>(); + + while (t.hasMoreTokens()) { + v.addElement(t.nextToken()); + } + + return v; + } + + @Override + public boolean accept(File dir, String name) { + return extMatches(name, this.exts); + } + + public static boolean extMatches(String name, Vector<String> exts) { + int index = name.lastIndexOf("."); + if (index != -1) { + String ext = name.substring(index + 1); + Enumeration<String> e = exts.elements(); + + while (e.hasMoreElements()) { + if (ext.equalsIgnoreCase(e.nextElement())) { + return true; + } + } + } + + return false; + } + + public static boolean extMatches(String name, String exts) { + return extMatches(name, breakUp(exts)); + } + + public boolean extMatches(String name) { + return extMatches(name, this.extList); + } + + public FileList keepPathInfo() { + this.keepPathInfo = true; + return this; + } + + public FileList dontSort() { + this.sort = false; + return this; + } + + public static String removeTrailingSlash(String dir) { + if (dir != null) { + int len = dir.length(); + if (len > 0) { + char c = dir.charAt(len - 1); + if (c == '/' || c == '\\') { + dir = dir.substring(0, len - 1); + } + } + } + + return dir; + } + + public Vector<String> getList() { + this.exts = breakUp(this.extList); + Vector<String> dirs = breakUp(this.dirList); + Vector<String> v = new Vector<String>(); + Enumeration<String> edirs = dirs.elements(); + + while (edirs.hasMoreElements()) { + String dir = removeTrailingSlash(edirs.nextElement()); + File f = new File(dir); + if (f.exists()) { + String[] list = f.list(this); + if (this.keepPathInfo && !dir.equals(".")) { + dir = dir + File.separator; + } else { + dir = ""; + } + + for (int i = 0; i < list.length; i++) { + String name = dir + list[i]; + if (!this.sort) { + v.addElement(name); + } else { + int count = v.size(); + String lname = name.toLowerCase(); + + int j; + for (j = 0; j < count; j++) { + if (lname.compareTo(v.elementAt(j).toLowerCase()) < 0) { + v.insertElementAt(name, j); + break; + } + } + + if (j == count) { + v.addElement(name); + } + } + } + } + } + + return v; + } +} diff --git a/NET/worlds/scape/FileTexture.java b/NET/worlds/scape/FileTexture.java new file mode 100644 index 0000000..52a3441 --- /dev/null +++ b/NET/worlds/scape/FileTexture.java @@ -0,0 +1,50 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class FileTexture extends Texture implements Persister { + private String _urlName; + private static Object classCookie = new Object(); + + static { + nativeInit(); + } + + public FileTexture(String urlName, String filename) { + this.makeTexture(urlName, filename); + } + + protected FileTexture() { + } + + public static native void nativeInit(); + + public static native FileTexture dictLookup(String var0); + + private native void makeTexture(String var1, String var2); + + @Override + public String getName() { + return this._urlName; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + s.saveString(this._urlName); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + String name = r.restoreString(); + this.makeTexture(name, name); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/FileTextureDecoder.java b/NET/worlds/scape/FileTextureDecoder.java new file mode 100644 index 0000000..6f226a4 --- /dev/null +++ b/NET/worlds/scape/FileTextureDecoder.java @@ -0,0 +1,15 @@ +package NET.worlds.scape; + +class FileTextureDecoder extends TextureDecoder { + private String exts = "bmp;ras"; + + @Override + protected String getExts() { + return this.exts; + } + + @Override + protected Texture read(String urlName, String filename) { + return new FileTexture(urlName, filename); + } +} diff --git a/NET/worlds/scape/FloatArrayEditorDialog.java b/NET/worlds/scape/FloatArrayEditorDialog.java new file mode 100644 index 0000000..4172da1 --- /dev/null +++ b/NET/worlds/scape/FloatArrayEditorDialog.java @@ -0,0 +1,50 @@ +package NET.worlds.scape; + +import java.util.StringTokenizer; + +class FloatArrayEditorDialog extends ListEditorDialog { + protected Property property; + protected float[] arr; + + FloatArrayEditorDialog(EditTile parent, String title, Property property) { + super(parent, title); + this.property = property; + this.ready(); + } + + @Override + protected void build() { + this.arr = (float[])this.property.get(); + super.build(); + } + + @Override + protected int getElementCount() { + return this.arr.length; + } + + @Override + protected String getElement(int index) { + return "" + this.arr[index]; + } + + @Override + protected boolean setElements(StringTokenizer e) { + int count = 0; + + while (e.hasMoreTokens()) { + try { + this.arr[count++] = Float.valueOf(e.nextToken()); + } catch (Exception var4) { + return false; + } + } + + if (count == this.arr.length) { + this.parent.addUndoableSet(this.property, this.arr); + return true; + } else { + return false; + } + } +} diff --git a/NET/worlds/scape/FloatArrayPropertyEditor.java b/NET/worlds/scape/FloatArrayPropertyEditor.java new file mode 100644 index 0000000..49de010 --- /dev/null +++ b/NET/worlds/scape/FloatArrayPropertyEditor.java @@ -0,0 +1,19 @@ +package NET.worlds.scape; + +import NET.worlds.console.PolledDialog; + +public class FloatArrayPropertyEditor extends PropEditor { + private FloatArrayPropertyEditor(Property property) { + super(property); + } + + @Override + public PolledDialog edit(EditTile parent, String title) { + return new FloatArrayEditorDialog(parent, title, this.property); + } + + public static Property make(Property property) { + property.setPropertyType(6); + return property.setEditor(new FloatArrayPropertyEditor(property)); + } +} diff --git a/NET/worlds/scape/FloatFieldEditorDialog.java b/NET/worlds/scape/FloatFieldEditorDialog.java new file mode 100644 index 0000000..7ad36cc --- /dev/null +++ b/NET/worlds/scape/FloatFieldEditorDialog.java @@ -0,0 +1,34 @@ +package NET.worlds.scape; + +class FloatFieldEditorDialog extends FieldEditorDialog { + Property property; + FloatPropertyEditor limits; + + FloatFieldEditorDialog(EditTile parent, String title, Property property, FloatPropertyEditor limits) { + super(parent, title); + this.property = property; + this.limits = limits; + this.ready(); + } + + @Override + protected String getValue() { + return "" + this.property.get(); + } + + @Override + protected boolean setValue(String text) { + if (text.length() != 0) { + try { + Float val = Float.valueOf(text); + if (!this.limits.rangeLimits || val >= this.limits.minVal && val <= this.limits.maxVal) { + this.parent.addUndoableSet(this.property, val); + return true; + } + } catch (NumberFormatException var3) { + } + } + + return false; + } +} diff --git a/NET/worlds/scape/FloatPropertyEditor.java b/NET/worlds/scape/FloatPropertyEditor.java new file mode 100644 index 0000000..90a6099 --- /dev/null +++ b/NET/worlds/scape/FloatPropertyEditor.java @@ -0,0 +1,35 @@ +package NET.worlds.scape; + +import NET.worlds.console.PolledDialog; + +public class FloatPropertyEditor extends PropEditor { + boolean rangeLimits = false; + float minVal; + float maxVal; + + private FloatPropertyEditor(Property property) { + super(property); + } + + private FloatPropertyEditor(Property property, float minVal, float maxVal) { + super(property); + this.rangeLimits = true; + this.minVal = minVal; + this.maxVal = maxVal; + } + + @Override + public PolledDialog edit(EditTile parent, String title) { + return new FloatFieldEditorDialog(parent, title, this.property, this); + } + + public static Property make(Property property) { + property.setPropertyType(2); + return property.setEditor(new FloatPropertyEditor(property)); + } + + public static Property make(Property property, float minVal, float maxVal) { + property.setPropertyType(2); + return property.setEditor(new FloatPropertyEditor(property, minVal, maxVal)); + } +} diff --git a/NET/worlds/scape/FloorPatch.java b/NET/worlds/scape/FloorPatch.java new file mode 100644 index 0000000..3c3795e --- /dev/null +++ b/NET/worlds/scape/FloorPatch.java @@ -0,0 +1,9 @@ +package NET.worlds.scape; + +public interface FloorPatch { + boolean inPatch(float var1, float var2); + + float floorHeight(float var1, float var2); + + Point3 surfaceNormal(float var1, float var2); +} diff --git a/NET/worlds/scape/ForwardAttribute.java b/NET/worlds/scape/ForwardAttribute.java new file mode 100644 index 0000000..fd2a830 --- /dev/null +++ b/NET/worlds/scape/ForwardAttribute.java @@ -0,0 +1,61 @@ +package NET.worlds.scape; + +import NET.worlds.core.Std; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class ForwardAttribute extends Attribute implements NonPersister { + private Attribute _from; + + ForwardAttribute(Attribute forwarder, int attrID) { + super(attrID); + this._from = forwarder; + } + + @Override + protected void noteAddingTo(SuperRoot owner) { + WObject w = (WObject)owner.getOwner(); + if ((w.getSharer().getMode() & 1) != 0) { + throw new ClassCastException("Must forward to unforwarded object"); + } + } + + @Override + public void detach() { + super.detach(); + this._from.unforward(); + } + + @Override + public int getFlags() { + return this._from.getFlags(); + } + + @Override + public void setFlag(int flag, boolean onoff) { + this._from.setFlag(flag, onoff); + } + + @Override + public void generateNetData(DataOutputStream s) throws IOException { + this._from.generateNetData(s); + } + + @Override + public void setFromNetData(DataInputStream ds, int len) throws IOException { + this._from.setFromNetData(ds, len); + ValueEvent e = new ValueEvent(Std.getFastTime(), this._from.getOwner(), (WObject)this._from.getOwner().getOwner(), this._from); + this._from.trigger(e); + } + + @Override + public String toString() { + return super.toString() + "[forwarded from " + this._from.getName() + "]"; + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + assert false; + } +} diff --git a/NET/worlds/scape/FrameEvent.java b/NET/worlds/scape/FrameEvent.java new file mode 100644 index 0000000..c4e6131 --- /dev/null +++ b/NET/worlds/scape/FrameEvent.java @@ -0,0 +1,44 @@ +package NET.worlds.scape; + +import NET.worlds.core.Std; + +public class FrameEvent extends Event { + private static int lastFrameTime; + private static int deltaFrameTime; + public int dt; + + public FrameEvent(WObject target) { + super(lastFrameTime, null, target); + this.dt = deltaFrameTime; + } + + public FrameEvent(WObject source, WObject target) { + super(lastFrameTime, source, target); + this.dt = deltaFrameTime; + } + + public void newFrameTime() { + this.time = Std.getRealTime(); + if (lastFrameTime == 0) { + deltaFrameTime = 0; + } else { + deltaFrameTime = this.time - lastFrameTime; + + assert this.time >= lastFrameTime && deltaFrameTime >= 0; + } + + lastFrameTime = this.time; + this.dt = deltaFrameTime; + } + + @Override + public boolean deliver(Object o) { + return o instanceof FrameHandler && ((FrameHandler)o).handle(this) ? true : true; + } + + public void retargetAndDeliver(FrameHandler h, WObject o) { + this.target = o; + this.receiver = o; + h.handle(this); + } +} diff --git a/NET/worlds/scape/FrameHandler.java b/NET/worlds/scape/FrameHandler.java new file mode 100644 index 0000000..bf4f38f --- /dev/null +++ b/NET/worlds/scape/FrameHandler.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface FrameHandler { + boolean handle(FrameEvent var1); +} diff --git a/NET/worlds/scape/FrameSensor.java b/NET/worlds/scape/FrameSensor.java new file mode 100644 index 0000000..47c57d7 --- /dev/null +++ b/NET/worlds/scape/FrameSensor.java @@ -0,0 +1,18 @@ +package NET.worlds.scape; + +public class FrameSensor extends Sensor implements FrameHandler { + public FrameSensor(Action a) { + if (a != null) { + this.addAction(a); + } + } + + public FrameSensor() { + } + + @Override + public boolean handle(FrameEvent e) { + this.trigger(e); + return true; + } +} diff --git a/NET/worlds/scape/GravityAction.java b/NET/worlds/scape/GravityAction.java new file mode 100644 index 0000000..f77e645 --- /dev/null +++ b/NET/worlds/scape/GravityAction.java @@ -0,0 +1,189 @@ +package NET.worlds.scape; + +import NET.worlds.core.Std; +import java.io.IOException; + +public class GravityAction extends Action { + public float cycleTime = 0.0F; + int startTime; + public int force = 300; + public float xDest = 0.0F; + public float yDest = 0.0F; + public float zDest = 0.0F; + static final float epsilon = 2.0F; + int lastFrameTime; + float initialDistance = 0.0F; + Point3 initialPoint; + protected boolean gravityEnd = true; + private static Object classCookie = new Object(); + + public void startGravity() { + this.startTime = Std.getRealTime(); + this.gravityEnd = false; + this.lastFrameTime = 0; + } + + private float distance(float tx, float ty, float tz, float cx, float cy, float cz) { + float dx = tx - cx; + float dy = ty - cy; + float dz = tz - cz; + return (float)Math.sqrt(dx * dx + dy * dy + dz * dz); + } + + public void doGravity(Pilot pilotObject, WObject o) { + int currentFrameTime = Std.getRealTime(); + float r = this.distance(pilotObject.getX(), pilotObject.getY(), pilotObject.getZ(), o.getX(), o.getY(), o.getZ()); + if (this.lastFrameTime == 0) { + this.lastFrameTime = currentFrameTime; + } + + float distanceTraveled = this.distance( + this.initialPoint.x, this.initialPoint.y, this.initialPoint.z, pilotObject.getX(), pilotObject.getY(), pilotObject.getZ() + ); + this.initialDistance = this.distance(this.initialPoint.x, this.initialPoint.y, this.initialPoint.z, o.getX(), o.getY(), o.getZ()); + if (r > 2.0F && distanceTraveled <= this.initialDistance) { + float dx = o.getX() - pilotObject.getX(); + if (dx != 0.0) { + float new_dx = (currentFrameTime - this.lastFrameTime) * this.force * dx / (r * r); + if (Math.abs(new_dx) < Math.abs(dx)) { + dx = new_dx; + } + } + + float dy = o.getY() - pilotObject.getY(); + if (dy != 0.0) { + float new_dy = (currentFrameTime - this.lastFrameTime) * this.force * dy / (r * r); + if (Math.abs(new_dy) < Math.abs(dy)) { + dy = new_dy; + } + } + + float dz = o.getZ() - pilotObject.getZ(); + if (dz != 0.0) { + float new_dz = (currentFrameTime - this.lastFrameTime) * this.force * dz / (r * r); + if (Math.abs(new_dz) < Math.abs(dz)) { + dz = new_dz; + } + } + + pilotObject.moveBy(dx, dy, dz); + } else { + pilotObject.moveTo(o.getX(), o.getY(), o.getZ()); + this.gravityEnd = true; + } + + this.lastFrameTime = currentFrameTime; + } + + @Override + public Persister trigger(Event e, Persister seqID) { + Object owner = this.getOwner(); + if (owner != null && owner instanceof WObject) { + WObject o = (WObject)owner; + Pilot pilot = Pilot.getActive(); + if (pilot == null) { + return null; + } else if (pilot.getRoom() != o.getRoom()) { + if (this.gravityEnd && pilot instanceof HoloPilot) { + HoloPilot hp = (HoloPilot)pilot; + hp.returnSmoothDriver(); + } + + return null; + } else { + if (this.gravityEnd) { + this.startGravity(); + if (pilot instanceof HoloPilot) { + HoloPilot hp = (HoloPilot)pilot; + hp.removeSmoothDriver(); + this.initialPoint = new Point3(pilot.getPosition()); + this.initialDistance = this.distance(this.initialPoint.x, this.initialPoint.y, this.initialPoint.z, o.getX(), o.getY(), o.getZ()); + } + } + + this.doGravity(pilot, o); + if (this.gravityEnd) { + if (pilot instanceof HoloPilot) { + HoloPilot hp = (HoloPilot)pilot; + hp.returnSmoothDriver(); + } + + return null; + } else { + return this; + } + } + } else { + return null; + } + } + + @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 = IntegerPropertyEditor.make(new Property(this, index, "Force")); + } else if (mode == 1) { + ret = new Integer(this.force); + } else if (mode == 2) { + this.force = (Integer)value; + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public String toString() { + return super.toString() + "[Force " + this.force + "]"; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(4, classCookie); + super.saveState(s); + s.saveInt(this.force); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + r.restore(); + this.cycleTime = r.restoreFloat(); + this.force = r.restoreInt(); + break; + case 1: + super.restoreState(r); + this.cycleTime = r.restoreFloat(); + this.force = r.restoreInt(); + break; + case 2: + super.restoreState(r); + this.cycleTime = r.restoreFloat(); + this.force = r.restoreInt(); + this.xDest = r.restoreFloat(); + this.yDest = r.restoreFloat(); + break; + case 3: + super.restoreState(r); + this.force = r.restoreInt(); + this.xDest = r.restoreFloat(); + this.yDest = r.restoreFloat(); + this.zDest = r.restoreFloat(); + break; + case 4: + super.restoreState(r); + this.force = r.restoreInt(); + break; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/HTransWidget.java b/NET/worlds/scape/HTransWidget.java new file mode 100644 index 0000000..51aae9e --- /dev/null +++ b/NET/worlds/scape/HTransWidget.java @@ -0,0 +1,20 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.SnapTool; + +class HTransWidget extends WidgetButton { + public HTransWidget(ToolBar toolbar) { + super(toolbar, "htrans.gif", Console.message("Move-horiz")); + } + + @Override + public String drag(boolean initialDrag, float deltax, float deltay) { + Transform t = Transform.make(); + this.applyWorldTransform( + initialDrag, t.moveBy(SnapTool.snapTool().snapTo(this.getWorldAxis(1, 0, 0).times(deltax).plus(this.getWorldAxis(0, 1, 0).times(deltay)))) + ); + t.recycle(); + return "" + this.getWObject().getPosition(); + } +} diff --git a/NET/worlds/scape/Handler.java b/NET/worlds/scape/Handler.java new file mode 100644 index 0000000..9a2a725 --- /dev/null +++ b/NET/worlds/scape/Handler.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface Handler { + boolean handle(Event var1); +} diff --git a/NET/worlds/scape/HandsOffDriver.java b/NET/worlds/scape/HandsOffDriver.java new file mode 100644 index 0000000..ede28ae --- /dev/null +++ b/NET/worlds/scape/HandsOffDriver.java @@ -0,0 +1,175 @@ +package NET.worlds.scape; + +public class HandsOffDriver extends SwitchableBehavior implements FrameHandler, AnimatedActionHandler, KeyDownHandler, KeyUpHandler { + Point2 _destPoint; + float _destYaw; + float _velocity; + int _lastFrameTime = 0; + AnimatedActionHandlerImp handler; + int _state = 0; + Transform target = null; + float cameraPan = 0.0F; + float cameraZoom = 0.0F; + int cameraPanning = 0; + int cameraZooming = 0; + static final float cameraPanRate = 45.0F; + static final float cameraZoomRate = 100.0F; + static final int noState = 0; + static final int turnToDestination = 1; + static final int moveToDestination = 2; + static final int faceDestination = 3; + + public HandsOffDriver() { + this.handler = new AnimatedActionHandlerImp(); + } + + public float getCameraPan() { + return this.cameraPan; + } + + public float getCameraZoom() { + return this.cameraZoom; + } + + public void setTarget(Transform t) { + this.target = t; + } + + @Override + public void addCallback(AnimatedActionCallback c) { + this.handler.addCallback(c); + } + + @Override + public void removeCallback(AnimatedActionCallback c) { + this.handler.removeCallback(c); + } + + @Override + public void notifyCallbacks(int completionCode) { + this.handler.notifyCallbacks(completionCode); + } + + public void setDestPos(Point2 point, float yaw, float velocity) { + if (point == null) { + System.out.println("Point is null"); + } + + this._destPoint = point; + this._destYaw = yaw; + this._velocity = velocity; + this._state = 1; + } + + @Override + public boolean handle(FrameEvent e) { + int now = e.time; + float dt = (now - this._lastFrameTime) / 1000.0F; + this._lastFrameTime = now; + this.cameraZoom = this.cameraZoom + dt * 100.0F * this.cameraZooming; + this.cameraPan = this.cameraPan + dt * 45.0F * this.cameraPanning; + Transform tgt; + if (this.target == null) { + if (!(e.receiver instanceof Pilot)) { + System.out.println("Receiver not pilot..."); + return true; + } + + Pilot pilot = (Pilot)e.receiver; + if (!pilot.isActive()) { + System.out.println("Pilot not active..."); + return true; + } + + tgt = pilot; + } else { + tgt = this.target; + } + + if (dt <= 0.0F) { + System.out.println("Negative dt"); + return true; + } else { + if (dt > 0.33F) { + dt = 0.33F; + } + + this.moveObject(tgt, dt); + return true; + } + } + + private void yawLevel(Transform pilot, float theta) { + float currentYaw = pilot.getYaw(); + Point3Temp currentSpinAxis = Point3Temp.make(); + float currentSpin = pilot.getSpin(currentSpinAxis); + Point3Temp currentPosition = pilot.getPosition(); + pilot.makeIdentity().moveTo(currentPosition).yaw(-theta); + pilot.yaw(currentYaw); + pilot.spin(currentSpinAxis, currentSpin); + } + + private void moveObject(Transform pilot, float dt) { + if (pilot != null && this._destPoint != null) { + switch (this._state) { + case 1: { + Point3Temp dest = Point3Temp.make(this._destPoint.x, this._destPoint.y, pilot.getZ()); + Point3Temp src = pilot.getPosition(); + double destYaw = Math.atan2(dest.y - src.y, dest.x - src.x); + destYaw = (Math.PI / 2) - destYaw; + destYaw *= 180.0 / Math.PI; + this.yawLevel(pilot, (float)destYaw); + this._state = 2; + break; + } + case 2: { + Point3Temp dest = Point3Temp.make(this._destPoint.x, this._destPoint.y, pilot.getZ()); + Point3Temp pos = pilot.getPosition(); + float cm = dt * this._velocity; + Point3Temp dP = Point3Temp.make(dest); + dP.minus(pilot.getPosition()); + if (dP.length() <= cm) { + pilot.moveTo(dest); + this._state = 3; + } else { + dP.normalize(); + pilot.moveBy(dP.times(cm)); + } + break; + } + case 3: + this.yawLevel(pilot, this._destYaw); + this._state = 0; + this.notifyCallbacks(0); + } + } + } + + @Override + public boolean handle(KeyDownEvent e) { + if (e.key == '\ue326') { + this.cameraZooming = -1; + } else if (e.key == '\ue328') { + this.cameraZooming = 1; + } else if (e.key == '\ue325') { + this.cameraPanning = -1; + } else if (e.key == '\ue327') { + this.cameraPanning = 1; + } + + return true; + } + + @Override + public boolean handle(KeyUpEvent e) { + if (e.key == '\ue326' || e.key == '\ue328') { + this.cameraZooming = 0; + } else if (e.key == '\ue325' || e.key == '\ue327') { + this.cameraPanning = 0; + } else if (e.key == '\ue31b') { + this.notifyCallbacks(0); + } + + return true; + } +} diff --git a/NET/worlds/scape/HighJump.java b/NET/worlds/scape/HighJump.java new file mode 100644 index 0000000..722a5ed --- /dev/null +++ b/NET/worlds/scape/HighJump.java @@ -0,0 +1,78 @@ +package NET.worlds.scape; + +import NET.worlds.console.Main; +import NET.worlds.console.MainCallback; +import NET.worlds.core.Std; +import java.util.Enumeration; + +public class HighJump extends InventoryAction implements MainCallback { + int start; + SmoothDriver sd; + + public HighJump(String id, String name) { + super(id, name); + } + + public HighJump(String id, String name, int qty) { + super(id, name, qty); + } + + public HighJump(HighJump in) { + super(in); + } + + @Override + public InventoryItem cloneItem() { + return new HighJump(this); + } + + private SmoothDriver findSD(Pilot p) { + Enumeration e = p.getHandlers(); + + while (e.hasMoreElements()) { + Object o = e.nextElement(); + if (o instanceof SmoothDriver) { + return (SmoothDriver)o; + } + } + + return null; + } + + @Override + public boolean doAction() { + if (this.itemQuantity_ > 0) { + Pilot p = Pilot.getActive(); + if (p == null) { + return false; + } else { + this.sd = this.findSD(p); + if (this.sd == null) { + return false; + } else { + if (this.sd != null) { + Main.register(this); + this.start = Std.getRealTime(); + this.itemQuantity_--; + } + + return true; + } + } + } else { + return false; + } + } + + @Override + public void mainCallback() { + int now = Std.getFastTime(); + if (now > this.start + 6000) { + Main.unregister(this); + this.sd.setEyeHeight(150.0F); + } else { + float t = 1.0F - (float)Math.pow(1.0F - (now - this.start) / 3000.0F, 4.0); + this.sd.setEyeHeight(150.0F + 150.0F * t); + } + } +} diff --git a/NET/worlds/scape/HoloCallback.java b/NET/worlds/scape/HoloCallback.java new file mode 100644 index 0000000..3f16968 --- /dev/null +++ b/NET/worlds/scape/HoloCallback.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface HoloCallback { + void holoCallback(Hologram var1, boolean var2); +} diff --git a/NET/worlds/scape/HoloDrone.java b/NET/worlds/scape/HoloDrone.java new file mode 100644 index 0000000..5dc17f8 --- /dev/null +++ b/NET/worlds/scape/HoloDrone.java @@ -0,0 +1,261 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.Main; +import NET.worlds.core.IniFile; +import NET.worlds.core.ServerTableManager; +import NET.worlds.network.ObjID; +import NET.worlds.network.URL; +import NET.worlds.network.WorldServer; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Hashtable; + +public class HoloDrone extends Drone implements HoloCallback { + private WObject _avatar; + private WObject _realAvatar = null; + private boolean _isConstructing = false; + private Hologram _proxyHCnewImage = null; + private boolean _proxyHCok = false; + private static int _debugLevel = IniFile.gamma().getIniInt("dronedebug", 0); + private boolean permitAnyAvatar = IniFile.gamma().getIniInt("permitAnyAvatar", 0) != 0; + private static String[] permittedList; + private static String[] humanList; + private static Hashtable permittedHash; + private static Hashtable humanHash; + private static Object classCookie; + + static { + if (_debugLevel > 0) { + System.out.println("DRONE DEBUGGING LEVEL = " + _debugLevel); + } + + permittedList = ServerTableManager.instance().getTable("permittedHoloList"); + humanList = ServerTableManager.instance().getTable("humanHoloList"); + permittedHash = new Hashtable(); + humanHash = new Hashtable(); + + for (int i = 0; i < permittedList.length; i += 2) { + if (permittedList[i + 1] != null) { + permittedHash.put(permittedList[i], permittedList[i + 1]); + } else { + permittedHash.put(permittedList[i], permittedList); + } + } + + for (int ix = 0; ix < humanList.length; ix++) { + humanHash.put(humanList[ix], humanList[ix]); + } + + classCookie = new Object(); + } + + public HoloDrone() { + } + + public HoloDrone(ObjID objID, WorldServer serv) { + super(objID, serv); + + assert Main.isMainThread(); + + if (this._proxyHCnewImage != null) { + this.holoCallback(this._proxyHCnewImage, this._proxyHCok); + this._proxyHCnewImage = null; + } + } + + public static String[] getPermittedList() { + String[] result = new String[permittedList.length / 2]; + + for (int i = 0; i < result.length; i++) { + result[i] = permittedList[2 * i]; + } + + return result; + } + + static URL permission(URL url) { + String name = url.getAbsolute().toLowerCase(); + if (name.startsWith("avatar:") && name.endsWith(".mov")) { + name = name.substring(7, name.length() - 4); + Object newName = permittedHash.get(name); + if (newName == null) { + return null; + } else { + return newName instanceof String ? URL.make((String)newName) : url; + } + } else { + return null; + } + } + + public static URL getHuman(URL url) { + if (!url.endsWith(".mov")) { + return PosableShape.getHuman(url); + } else if (permission(url) == null) { + return URL.make("avatar:holden.mov"); + } else { + String s = url.getAbsolute().toLowerCase(); + int len = s.length(); + + for (int i = 7; i < len; i++) { + if ("0123456789.".indexOf(s.charAt(i)) >= 0) { + if (humanHash.get(s.substring(7, i)) != null) { + return url; + } + + return URL.make(IniFile.override().getIniString("defaultHumanAv", "avatar:holden.mov")); + } + } + + return url; + } + } + + @Override + public Drone setAvatarNow(URL url) { + if (!this.shouldBeMuted() && url.endsWith(".mov")) { + if (this.shouldBeForcedHuman()) { + url = getHuman(url); + } + + url = PosableShape.getPermitted(url, this.getWorld()); + if (url.equals(this.getSourceURL())) { + return this; + } else { + this.setSourceURL(url); + URL replacementURL = permission(url); + if (replacementURL != null) { + url = replacementURL; + } else if (!this.permitAnyAvatar) { + url = Console.getDefaultURL(); + } + + this._realAvatar = this.makeAvatar(url); + if (this._proxyHCnewImage != null) { + if ((_debugLevel & 1) > 0) { + System.out.println("Holo.stAvNow(" + url + "): doing proxy"); + } + + this.holoCallback(this._proxyHCnewImage, this._proxyHCok); + this._proxyHCnewImage = null; + } + + return this; + } + } else { + return super.setAvatarNow(url); + } + } + + public WObject makeAvatar(URL url) { + if ((_debugLevel & 1) > 0) { + System.out.println("HoloDrone.makeAvatar(" + url + ")"); + } + + this._isConstructing = true; + WObject bgAvatar = new Hologram(url, this); + this._isConstructing = false; + bgAvatar.setVisible(true); + bgAvatar.setBumpable(false); + return bgAvatar; + } + + @Override + public void holoCallback(Hologram newImage, boolean ok) { + if ((_debugLevel & 1) > 0) { + System.out.println("HoloDrone.holoCallback(" + newImage + "," + ok + ")"); + } + + if (this._isConstructing) { + assert this._proxyHCnewImage == null; + + this._proxyHCnewImage = newImage; + this._proxyHCok = ok; + if ((_debugLevel & 1) > 0) { + System.out.println("holoCallback: requesting proxy"); + } + } else if (this._realAvatar == this._avatar) { + if ((_debugLevel & 1) > 0) { + System.out.println("holoCb: real avatar already loaded"); + } + } else if (!ok) { + if (newImage == this._realAvatar) { + this._realAvatar = null; + } + + if ((_debugLevel & 1) > 0) { + System.out.println("holoCb: not ok"); + } + } else { + if ((_debugLevel & 1) > 0) { + System.out.println("holoCb: swapping avatars"); + } + + if (this._avatar != null) { + this._avatar.detach(); + } + + float avatarW = newImage.getW(); + float avatarH = newImage.getH(); + float factor; + if (avatarH < avatarW) { + factor = (float)Math.sqrt(25600.0F / (avatarW * avatarH)); + } else { + factor = 160.0F / avatarH; + } + + avatarH *= factor; + avatarW *= factor; + float heightAdj = 0.0F; + if (newImage == this._avatar) { + heightAdj = -this._avatar.getZ(); + } + + this._avatar = (WObject)newImage.scale(factor).raise(avatarH / 2.0F + heightAdj); + this.add(this._avatar); + this.avatarHeightChangedTo(avatarH); + } + } + + @Override + public float getMinXYExtent() { + return this._avatar == null ? 0.0F : this._avatar.getMinXYExtent(); + } + + @Override + public Object properties(int index, int offset, int mode, Object value) throws NoSuchPropertyException { + Object ret = null; + int var10000 = index - offset; + return super.properties(index, offset + 0, mode, value); + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + Enumeration e = this.getContents(); + + while (e.hasMoreElements()) { + WObject w = (WObject)e.nextElement(); + if (w instanceof Hologram) { + Hologram h = (Hologram)w; + if (h.getMovieName() != null) { + this._avatar = h; + } + } + } + + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/HoloPilot.java b/NET/worlds/scape/HoloPilot.java new file mode 100644 index 0000000..8f8a518 --- /dev/null +++ b/NET/worlds/scape/HoloPilot.java @@ -0,0 +1,579 @@ +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(); + } + } +} diff --git a/NET/worlds/scape/Hologram.java b/NET/worlds/scape/Hologram.java new file mode 100644 index 0000000..b138ac2 --- /dev/null +++ b/NET/worlds/scape/Hologram.java @@ -0,0 +1,568 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.Main; +import NET.worlds.console.MainCallback; +import NET.worlds.network.URL; +import java.io.IOException; + +public class Hologram extends Surface implements Prerenderable, BGLoaded, Postrenderable, MainCallback { + private int isLoading; + ScapePicMovie fromMovie; + URL movieName; + protected Texture[] images; + protected Material[] materials; + private static Object classCookie = new Object(); + private int origTransformID = 0; + private HoloCallback callback; + private float scaleDist; + + static { + nativeInit(); + } + + public Hologram(float w, float h, Texture[] texs) { + super(null); + this.scale(w, 1.0F, h); + this.images = texs; + } + + public Hologram() { + super(null); + } + + public Hologram(Texture[] texs) { + this(texs[0].getW(), texs[0].getH(), texs); + } + + public Hologram(ScapePicMovie texs) { + this(texs.getW(), texs.getH(), texs.getTextures()); + this.fromMovie = texs; + } + + public Hologram(float w, float h, ScapePicMovie texs) { + this(w, h, texs.getTextures()); + this.fromMovie = texs; + } + + public Hologram(URL movieName, HoloCallback cb) { + super(null); + this.setAutosize(true); + this.scale(100.0F, 1.0F, 100.0F); + this.load(movieName, cb); + } + + public Hologram(URL movieName) { + this(movieName, null); + } + + public Hologram(float w, float h, URL movieName, HoloCallback cb) { + super(null); + this.scale(w, 1.0F, h); + this.load(movieName, cb); + } + + public Hologram(float w, float h, URL movieName) { + this(w, h, movieName, null); + } + + public static native void nativeInit(); + + private void load(URL movieName, HoloCallback cb) { + assert this.getMaterial() != null; + + this.callback = cb; + this.movieName = movieName; + if (this.callback != null || this.hasClump()) { + this.forceLoad(); + } + } + + private void lockMaterials(boolean val) { + if (this.materials != null) { + for (int i = 0; i < this.materials.length; i++) { + this.materials[i].setKeepLoaded(val); + } + } + } + + private void releaseMaterials() { + this.lockMaterials(false); + this.materials = null; + } + + private void loadMultipart(URL url, String base, int numParts, String end) { + this.images = null; + this.releaseMaterials(); + this.materials = new Material[numParts]; + + while (--numParts >= 0) { + this.materials[numParts] = new Material(URL.make(url, base + (numParts + 1) + end)); + } + + this.setMaterial(this.materials[0]); + if (this.callback != null) { + this.callback.holoCallback(this, true); + this.callback = null; + } + } + + private void forceLoad() { + URL url = HoloDrone.permission(this.movieName); + String name = (url == null ? this.movieName : url).getBase(); + int len = name.length(); + boolean isMov = len > 5 && name.regionMatches(true, len - 5, "*.mov", 0, 5); + int h = 1; + int v = 1; + int s = 1; + + int num; + for (int nextStarIndex = len - 5; + nextStarIndex > 2 && name.charAt(nextStarIndex) == '*' && (num = name.charAt(nextStarIndex - 2) - '0') > 0 && num <= 9; + nextStarIndex -= 3 + ) { + char control = Character.toLowerCase(name.charAt(nextStarIndex - 1)); + if (control == 'h') { + h = num; + } else if (control == 'v') { + v = num; + } else if (control == 's') { + if (this.getAutosize()) { + this.scale(h * 160.0F / v / this.getScaleX(), 1.0F, 160.0F / this.getScaleZ()); + } + + if (isMov) { + this.loadMultipart(this.movieName, name.substring(0, nextStarIndex - 2), num, "s*" + h + "h*" + v + "v*.mov"); + } else { + this.loadMultipart(this.movieName, name.substring(0, nextStarIndex - 2), num, name.substring(nextStarIndex + 1)); + } + + return; + } + } + + this.isLoading++; + BackgroundLoader.get(this, this.movieName); + } + + @Override + public Object asyncBackgroundLoad(String localName, URL remoteName) { + if (localName != null) { + if (localName.toLowerCase().endsWith(".mov")) { + return new ScapePicMovie(localName, remoteName).getTextures(); + } + + Texture[] texs = new Texture[]{TextureDecoder.decode(remoteName, localName)}; + if (texs[0] != null && texs[0].textureID != 0) { + return texs; + } + } + + return null; + } + + @Override + public boolean syncBackgroundLoad(Object obj, URL remoteURL) { + this.releaseMaterials(); + if (obj != null) { + this.images = (Texture[])obj; + if (this.getAutosize()) { + this.scale(this.images[0].getW() / this.getScaleX(), 1.0F, this.images[0].getH() / this.getScaleZ()); + } + } else { + if (this.movieName != null) { + Console.println(Console.message("No-load-hologram") + this.movieName); + } + + this.images = null; + this.setMaterial(null); + } + + if (this.callback != null) { + this.callback.holoCallback(this, this.images != null || this.materials != null); + this.callback = null; + } + + this.isLoading--; + return false; + } + + @Override + public Room getBackgroundLoadRoom() { + return this.getRoom(); + } + + @Override + public BoundBoxTemp getBoundBox() { + Point3Temp center = this.getWorldPosition(); + Point3Temp jog = Point3Temp.make(this.getW() / 2.0F, this.getW() / 2.0F, this.getH() / 2.0F); + return BoundBoxTemp.make(Point3Temp.make(center).minus(jog), Point3Temp.make(center).plus(jog)); + } + + @Override + public float getMinXYExtent() { + return this.getW(); + } + + public float getW() { + return this.getScaleX(); + } + + public float getH() { + return this.getScaleZ(); + } + + public int getNumSides() { + if (this.images == null) { + return this.materials == null ? 1 : this.materials.length; + } else { + return this.images.length; + } + } + + void setActiveSide(int side) { + if (side >= this.getNumSides()) { + System.out.println("Error at NET.worlds.Hologram.setActiveSide side " + side + " of " + this.getNumSides()); + side = 0; + } + + if (this.materials == null) { + Texture t = this.images == null ? null : (side < this.images.length ? this.images[side] : null); + if (t != null) { + t.incRef(); + } + + this.material.setTexture(t); + } else if (this.materials[side] != this.material) { + this.setMaterial(this.materials[side]); + } + } + + public URL getMovieName() { + return this.movieName == null && this.fromMovie != null ? this.fromMovie.getURL() : this.movieName; + } + + @Override + protected void addRwChildren(WObject container) { + this.addNewRwChild(container); + if (this.images == null && this.materials == null && this.movieName != null && this.isLoading == 0) { + this.forceLoad(); + } + + this.addVertex(0.5F, 0.0F, -0.5F, 0.0F, 1.0F); + this.addVertex(-0.5F, 0.0F, -0.5F, 1.0F, 1.0F); + this.addVertex(-0.5F, 0.0F, 0.5F, 1.0F, 0.0F); + this.addVertex(0.5F, 0.0F, 0.5F, 0.0F, 0.0F); + this.doneWithEditing(); + if (!this.isReclumping()) { + this.lockMaterials(true); + this.getRoom().addPrerenderHandler(this); + this.getRoom().addPostrenderHandler(this); + } + + if (this.images == null && this.materials == null && this.isLoading > 0) { + this.makeTemporarilyInvisible(); + } + } + + public native void makeTemporarilyInvisible(); + + @Override + protected void markVoid() { + if (!this.isReclumping()) { + this.lockMaterials(false); + this.getRoom().removePrerenderHandler(this); + this.getRoom().removePostrenderHandler(this); + } + + if (this.movieName != null && this.fromMovie == null && this.isLoading == 0) { + Main.register(this); + } + + super.markVoid(); + } + + @Override + public void mainCallback() { + if (!this.hasClump()) { + if (this.images != null) { + int i = this.images.length; + + while (--i >= 0) { + if (this.images[i] != null) { + this.images[i].decRef(); + } + } + + this.images = null; + } + + this.releaseMaterials(); + } + + Main.unregister(this); + } + + @Override + public native void prerender(Camera var1); + + @Override + public native void postrender(Camera var1); + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(6, classCookie); + s.saveFloat(this.scaleDist); + Material origMaterial = this.getMaterial(); + URL name = this.getMovieName(); + if (name != null) { + this.setMaterial(null); + } + + super.saveState(s); + this.setMaterial(origMaterial); + URL.save(s, name); + if (name == null) { + if (this.fromMovie != null) { + s.saveBoolean(true); + s.save(this.fromMovie); + } else { + s.saveBoolean(false); + if (this.images != null) { + s.saveBoolean(true); + s.saveArray(this.images); + } else { + assert this.materials == null; + + s.saveBoolean(false); + } + } + } + } + + private static Texture[] extractTextureArray(Material[] mats) { + Texture[] texs = new Texture[mats.length]; + + for (int i = 0; i < mats.length; i++) { + texs[i] = mats[i].extractTexture(0); + } + + return texs; + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + int vers = r.restoreVersion(classCookie); + switch (vers) { + case 0: + super.restoreState(r); + float w = r.restoreFloat(); + if (w == 0.0F) { + w = 100.0F; + } + + float h = r.restoreFloat(); + if (h == 0.0F) { + h = 100.0F; + } + + this.scale(w, 1.0F, h); + if (r.restoreBoolean()) { + this.fromMovie = (ScapePicMovie)r.restore(); + this.images = this.fromMovie.getTextures(); + } else { + this.setAutosize(true); + } + break; + case 1: + super.restoreState(r); + float wx = r.restoreFloat(); + if (wx == 0.0F) { + wx = 100.0F; + } + + float hx = r.restoreFloat(); + if (hx == 0.0F) { + hx = 100.0F; + } + + this.scale(wx, 1.0F, hx); + if ((this.movieName = URL.restore(r)) != null) { + this.load(this.movieName, null); + } else if (r.restoreBoolean()) { + this.fromMovie = (ScapePicMovie)r.restore(); + this.images = this.fromMovie.getTextures(); + } else { + this.setAutosize(true); + } + break; + case 2: + super.restoreState(r); + if ((this.movieName = URL.restore(r)) != null) { + this.load(this.movieName, null); + } else if (r.restoreBoolean()) { + this.fromMovie = (ScapePicMovie)r.restore(); + this.images = this.fromMovie.getTextures(); + } else { + this.setAutosize(true); + } + break; + case 3: + super.restoreState(r); + if ((this.movieName = URL.restore(r)) != null) { + this.load(this.movieName, null); + } else if (r.restoreBoolean()) { + this.fromMovie = (ScapePicMovie)r.restore(); + this.images = this.fromMovie.getTextures(); + } else { + this.setAutosize(true); + if (r.restoreBoolean()) { + this.images = extractTextureArray((Material[])r.restoreArray()); + } + } + break; + case 5: + case 6: + this.scaleDist = r.restoreFloat(); + case 4: + super.restoreState(r); + if ((this.movieName = URL.restore(r)) != null) { + this.load(this.movieName, null); + } else if (r.restoreBoolean()) { + this.fromMovie = (ScapePicMovie)r.restore(); + this.images = this.fromMovie.getTextures(); + } else { + if (vers < 6) { + this.setAutosize(true); + } + + if (r.restoreBoolean()) { + this.images = (Texture[])r.restoreArray(); + } + } + break; + default: + throw new TooNewException(); + } + } + + public Hologram setRoughCut(boolean b) { + if (b) { + this.flags |= 4; + } else { + this.flags &= -5; + } + + return this; + } + + public final boolean getRoughCut() { + return (this.flags & 4) != 0; + } + + public void setAutosize(boolean b) { + if (b) { + this.flags |= 4194304; + } else { + this.flags &= -4194305; + } + } + + public final boolean getAutosize() { + return (this.flags & 4194304) != 0; + } + + public Hologram setViewplaneAligned(boolean b) { + if (b) { + this.flags |= 262144; + } else { + this.flags &= -262145; + } + + return this; + } + + public final boolean getViewplaneAligned() { + return (this.flags & 262144) != 0; + } + + @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 = URLPropertyEditor.make(new Property(this, index, "File"), TextureDecoder.getAllExts()); + } else if (mode == 1) { + ret = this.getMovieName(); + } else if (mode == 2) { + this.load((URL)value, null); + } + break; + case 1: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Viewplane Aligned"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.getViewplaneAligned()); + } else if (mode == 2) { + this.setViewplaneAligned((Boolean)value); + } + break; + case 2: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Rough Cut Alignment"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.getRoughCut()); + } else if (mode == 2) { + this.setRoughCut((Boolean)value); + } + break; + case 3: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Scale Distance")); + } else if (mode == 1) { + ret = new Float(this.getScaleDist()); + } else if (mode == 2) { + this.setScaleDist((Float)value); + } + break; + case 4: + if (mode == 0) { + ret = Point2PropertyEditor.make(new Property(this, index, "Extent")); + } else if (mode == 1) { + ret = new Point2(this.getScaleX(), this.getScaleZ()); + } else if (mode == 2) { + this.setAutosize(false); + this.scale(((Point2)value).x / this.getScaleX(), 1.0F, ((Point2)value).y / this.getScaleZ()); + } + break; + case 5: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Autosize"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.getAutosize()); + } else if (mode == 2) { + this.setAutosize((Boolean)value); + } + break; + default: + ret = super.properties(index, offset + 6, mode, value); + } + + return ret; + } + + @Override + public String toString() { + URL name = this.getMovieName(); + return super.toString() + "[" + (name != null ? name.toString() : "") + "]"; + } + + public void setScaleDist(float dist) { + this.scaleDist = dist; + } + + public final float getScaleDist() { + return this.scaleDist; + } +} diff --git a/NET/worlds/scape/HorizontalRect.java b/NET/worlds/scape/HorizontalRect.java new file mode 100644 index 0000000..cf12fd9 --- /dev/null +++ b/NET/worlds/scape/HorizontalRect.java @@ -0,0 +1,38 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class HorizontalRect extends Surface { + private static Object classCookie = new Object(); + + @Override + public void saveState(Saver s) throws IOException { + assert false; + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + float x = r.restoreFloat(); + float y = r.restoreFloat(); + float u = r.restoreFloat(); + float v = r.restoreFloat(); + boolean faceUp = r.restoreBoolean(); + Rect rect = new Rect(1.0F, 1.0F, this.getMaterial()); + rect.setTransform(this); + if (faceUp) { + rect.pitch(-90.0F).scale(x, 1.0F, y); + } else { + rect.yaw(90.0F).pitch(90.0F).scale(y, 1.0F, x); + } + + rect.setUV(u, v); + r.replace(this, rect); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/Iconic.java b/NET/worlds/scape/Iconic.java new file mode 100644 index 0000000..cdee035 --- /dev/null +++ b/NET/worlds/scape/Iconic.java @@ -0,0 +1,9 @@ +package NET.worlds.scape; + +import NET.worlds.network.URL; + +public interface Iconic { + URL getIconURL(); + + String getIconCaption(); +} diff --git a/NET/worlds/scape/ImageConverter.java b/NET/worlds/scape/ImageConverter.java new file mode 100644 index 0000000..091ba1f --- /dev/null +++ b/NET/worlds/scape/ImageConverter.java @@ -0,0 +1,181 @@ +package NET.worlds.scape; + +import java.awt.Image; +import java.awt.Toolkit; +import java.awt.image.ColorModel; +import java.awt.image.DirectColorModel; +import java.awt.image.ImageConsumer; +import java.awt.image.IndexColorModel; +import java.util.Hashtable; + +public class ImageConverter implements ImageConsumer { + private String urlName; + private String filename; + private int width; + private int height; + private Image image; + private boolean done; + private boolean ok; + private boolean debug = false; + private ColorModel model; + private int transparentColor = -1; + private int hDIB; + private int pixelPtr; + + static { + nativeInit(); + } + + public ImageConverter(String urlName, String filename) { + this.urlName = urlName; + this.filename = filename; + } + + public static native void nativeInit(); + + public synchronized int convert() { + this.image = Toolkit.getDefaultToolkit().getImage(this.filename); + this.image.getSource().startProduction(this); + + while (!this.done) { + try { + this.wait(); + } catch (InterruptedException var2) { + } + } + + int textureID = 0; + if (this.ok) { + textureID = this.convertDIBToTexture(); + } + + this.cleanup(); + return textureID; + } + + @Override + public void setDimensions(int width, int height) { + if (this.debug) { + System.out.println("Set dimensions: w " + width + " h " + height); + } + + this.width = width; + this.height = height; + } + + @Override + public void setProperties(Hashtable props) { + if (this.debug) { + System.out.println("Set properties"); + } + } + + @Override + public void setColorModel(ColorModel model) { + if (this.debug) { + System.out.println("Set color model: " + model); + } + + this.model = model; + + assert this.width != 0 && this.height != 0; + + int[] palette = (int[])null; + int colors = 0; + if (model instanceof IndexColorModel) { + IndexColorModel im = (IndexColorModel)model; + colors = im.getMapSize(); + this.transparentColor = im.getTransparentPixel(); + palette = new int[colors * 3]; + + for (int i = 0; i < colors; i++) { + palette[i] = im.getRGB(i); + } + } else { + DirectColorModel dm = (DirectColorModel)model; + + assert dm.getBlueMask() == 255; + + assert dm.getGreenMask() == 65280; + + assert dm.getRedMask() == 16711680; + } + + this.prepareDIB(this.width, this.height, colors, palette); + } + + @Override + public void setHints(int hintflags) { + if (this.debug) { + System.out + .println( + "Set hints: " + + ((hintflags & 1) != 0 ? " RANDOM " : "") + + ((hintflags & 2) != 0 ? " TOPDOWNLEFTRIGHT " : "") + + ((hintflags & 4) != 0 ? " COMPLETESCANS " : "") + + ((hintflags & 8) != 0 ? " SINGLEPASS " : "") + + ((hintflags & 16) != 0 ? " SINGLEFRAME " : "") + ); + } + } + + @Override + public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, int scansize) { + if (this.debug) { + System.out.println("setPixels(byte): x " + x + " y " + y + " w " + w + " h " + h + " model " + model + " off " + off + " scansize " + scansize); + } + + assert model == this.model; + + this.setDIBPixelBytes(x, y, w, h, pixels, off, scansize); + } + + @Override + public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, int scansize) { + if (this.debug) { + System.out.println("setPixels(int): x " + x + " y " + y + " w " + w + " h " + h + " model " + model + " off " + off + " scansize " + scansize); + } + + assert model == this.model; + + this.setDIBPixelInts(x, y, w, h, pixels, off, scansize); + } + + @Override + public synchronized void imageComplete(int status) { + if (this.debug) { + String state = null; + switch (status) { + case 1: + state = "ERROR"; + break; + case 2: + state = "SINGLEDONE"; + break; + case 3: + state = "STATICDONE"; + break; + case 4: + state = "ABORTED"; + } + + System.out.println("Image complete: " + state); + } + + this.image.getSource().removeConsumer(this); + this.image.flush(); + this.ok = status != 1 && status != 4; + this.done = true; + this.notify(); + } + + private native void prepareDIB(int var1, int var2, int var3, int[] var4); + + private native void setDIBPixelBytes(int var1, int var2, int var3, int var4, byte[] var5, int var6, int var7); + + private native void setDIBPixelInts(int var1, int var2, int var3, int var4, int[] var5, int var6, int var7); + + private native int convertDIBToTexture(); + + private native void cleanup(); +} diff --git a/NET/worlds/scape/IncrementalRestorer.java b/NET/worlds/scape/IncrementalRestorer.java new file mode 100644 index 0000000..27b4fb4 --- /dev/null +++ b/NET/worlds/scape/IncrementalRestorer.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface IncrementalRestorer { + int incRestore(int var1, Restorer var2, URLSelfLoader var3) throws Exception; +} diff --git a/NET/worlds/scape/IndentStream.java b/NET/worlds/scape/IndentStream.java new file mode 100644 index 0000000..b7bd27d --- /dev/null +++ b/NET/worlds/scape/IndentStream.java @@ -0,0 +1,94 @@ +package NET.worlds.scape; + +import java.io.OutputStream; +import java.io.PrintStream; + +public class IndentStream extends PrintStream { + private boolean _atstart = true; + private int _indent = 0; + + public IndentStream(OutputStream os) { + super(os); + } + + public IndentStream(OutputStream os, boolean flush) { + super(os, flush); + } + + public void indent(int step) { + this._indent += step; + } + + public void indent() { + this.indent(2); + } + + public void undent(int step) { + if (this._indent >= step) { + this._indent -= step; + } else { + this._indent = 0; + } + } + + public void undent() { + this.undent(2); + } + + public int curIndent() { + return this._indent; + } + + private void startLine() { + for (int i = 0; i < this._indent; i++) { + super.write(32); + } + + this._atstart = false; + } + + @Override + public void write(int b) { + if (b == 10) { + this._atstart = true; + } else if (this._atstart) { + this.startLine(); + } + + super.write(b); + } + + @Override + public void write(byte[] b, int off, int len) { + while (len > 0) { + int firstlen = 0; + + while (firstlen < len && b[off + firstlen] != 10) { + firstlen++; + } + + if (firstlen > 0) { + if (this._atstart) { + this.startLine(); + } + + super.write(b, off, firstlen); + off += firstlen; + len -= firstlen; + this._atstart = false; + firstlen = 0; + } + + while (firstlen < len && b[off + firstlen] == 10) { + firstlen++; + } + + if (firstlen > 0) { + super.write(b, off, firstlen); + off += firstlen; + len -= firstlen; + this._atstart = true; + } + } + } +} diff --git a/NET/worlds/scape/IntegerFieldEditorDialog.java b/NET/worlds/scape/IntegerFieldEditorDialog.java new file mode 100644 index 0000000..07a0369 --- /dev/null +++ b/NET/worlds/scape/IntegerFieldEditorDialog.java @@ -0,0 +1,34 @@ +package NET.worlds.scape; + +class IntegerFieldEditorDialog extends FieldEditorDialog { + Property property; + IntegerPropertyEditor limits; + + IntegerFieldEditorDialog(EditTile parent, String title, Property property, IntegerPropertyEditor limits) { + super(parent, title); + this.property = property; + this.limits = limits; + this.ready(); + } + + @Override + protected String getValue() { + return "" + this.property.get(); + } + + @Override + protected boolean setValue(String text) { + if (text.length() != 0) { + try { + int val = Integer.parseInt(text); + if (!this.limits.rangeLimits || val >= this.limits.minVal && val <= this.limits.maxVal) { + this.parent.addUndoableSet(this.property, new Integer(val)); + return true; + } + } catch (NumberFormatException var3) { + } + } + + return false; + } +} diff --git a/NET/worlds/scape/IntegerPropertyEditor.java b/NET/worlds/scape/IntegerPropertyEditor.java new file mode 100644 index 0000000..dc210ac --- /dev/null +++ b/NET/worlds/scape/IntegerPropertyEditor.java @@ -0,0 +1,35 @@ +package NET.worlds.scape; + +import NET.worlds.console.PolledDialog; + +public class IntegerPropertyEditor extends PropEditor { + boolean rangeLimits = false; + int minVal; + int maxVal; + + private IntegerPropertyEditor(Property property) { + super(property); + } + + private IntegerPropertyEditor(Property property, int minVal, int maxVal) { + super(property); + this.rangeLimits = true; + this.minVal = minVal; + this.maxVal = maxVal; + } + + @Override + public PolledDialog edit(EditTile parent, String title) { + return new IntegerFieldEditorDialog(parent, title, this.property, this); + } + + public static Property make(Property property) { + property.setPropertyType(1); + return property.setEditor(new IntegerPropertyEditor(property)); + } + + public static Property make(Property property, int minVal, int maxVal) { + property.setPropertyType(1); + return property.setEditor(new IntegerPropertyEditor(property, minVal, maxVal)); + } +} diff --git a/NET/worlds/scape/InterpolatedDrone.java b/NET/worlds/scape/InterpolatedDrone.java new file mode 100644 index 0000000..bf50bb4 --- /dev/null +++ b/NET/worlds/scape/InterpolatedDrone.java @@ -0,0 +1,247 @@ +package NET.worlds.scape; + +import NET.worlds.console.BBAppearDroneCommand; +import NET.worlds.console.BBDisappearDroneCommand; +import NET.worlds.console.BBDroneDeltaPosCommand; +import NET.worlds.console.BBMoveDroneCommand; +import NET.worlds.console.BlackBox; +import NET.worlds.core.Std; +import NET.worlds.network.ObjID; +import NET.worlds.network.URL; +import NET.worlds.network.WorldServer; +import java.io.IOException; + +public class InterpolatedDrone extends Drone implements FrameHandler { + private int _last_FrameTime; + private int _last_PosTime; + private int _vel_x; + private int _vel_y; + private int _vel_z; + private int _vel_yaw; + private int _last_x; + private int _last_y; + private int _last_z; + private int _last_yaw; + private int _x; + private int _y; + private int _z; + private int _yaw; + private boolean inited = false; + private static Object classCookie = new Object(); + + public InterpolatedDrone(ObjID objID, WorldServer serv) { + super(objID, serv); + } + + public InterpolatedDrone() { + } + + @Override + public Point3Temp getVelocity() { + return Point3Temp.make(this._vel_x, this._vel_y, this._vel_z); + } + + @Override + public int getYawRate() { + return this._vel_yaw; + } + + @Override + public boolean handle(FrameEvent fe) { + if (this._server == null) { + return true; + } else { + int timeNow = fe.time; + this.interpolate(timeNow, this._server.getUpdateTime(), this); + return true; + } + } + + @Override + public void interpolate(int timeNow, int updateTime, Transform target) { + if (this.inited) { + if (timeNow - this._last_PosTime > updateTime) { + this._last_PosTime = timeNow; + this._vel_x = this._last_x - this._x; + this._vel_y = this._last_y - this._y; + this._vel_z = this._last_z - this._z; + this._vel_yaw = ((this._last_yaw - this._yaw) % 360 + 360) % 360; + + assert this._vel_yaw >= 0; + + if (this._vel_yaw > 180) { + this._vel_yaw -= 360; + } + } + + double timeDiff = (double)(timeNow - this._last_FrameTime) / updateTime; + if (timeNow - this._last_FrameTime > updateTime) { + timeDiff = 0.0; + } + + this._x = this._x + (int)(timeDiff * this._vel_x); + this._y = this._y + (int)(timeDiff * this._vel_y); + this._z = this._z + (int)(timeDiff * this._vel_z); + this._yaw = this._yaw + (int)(timeDiff * this._vel_yaw) % 360; + target.makeIdentity().moveBy(this._x, this._y, this._z).yaw(this._yaw); + this._last_FrameTime = timeNow; + } + } + + @Override + public void reset(short x, short y, short z, short yaw) { + this._x = x; + this._y = y; + this._z = z; + this._yaw = yaw; + this._vel_x = this._vel_y = this._vel_z = 0; + this._vel_yaw = 0; + this._last_x = this._x; + this._last_y = this._y; + this._last_z = this._z; + this._last_yaw = this._yaw; + this._last_PosTime = this._last_FrameTime = Std.getRealTime(); + this.inited = true; + } + + @Override + public void appear(Room rm, short x, short y, short z, short yaw) { + assert rm != null; + + BlackBox.getInstance().submitEvent(new BBAppearDroneCommand(rm.toString(), this.getName(), x, y, z, yaw)); + if (this.getRoom() != rm) { + this.detach(); + rm.add(this); + } + + this.makeIdentity().moveBy(x, y, z).yaw(yaw); + this._x = x; + this._y = y; + this._z = z; + this._yaw = yaw; + this._vel_x = this._vel_y = this._vel_z = 0; + this._vel_yaw = 0; + this._last_x = x; + this._last_y = y; + this._last_z = z; + this._last_yaw = yaw; + this._last_PosTime = this._last_FrameTime = Std.getRealTime(); + URL u = this.getCurrentURL(); + if (u != null) { + this.setAvatarNow(u); + } + + this.inited = true; + } + + @Override + public void disappear() { + BlackBox.getInstance().submitEvent(new BBDisappearDroneCommand(this.getName())); + this.detachFromServer(true); + this.detach(); + } + + @Override + public void longLoc(short x, short y, short z, short yaw) { + if (!(this.getOwner() instanceof Pilot)) { + BlackBox.getInstance().submitEvent(new BBMoveDroneCommand(this.getName(), x, y, z, yaw)); + } + + this._last_x = x; + this._last_y = y; + this._last_z = z; + this._last_yaw = yaw; + this._vel_x = this._last_x - this._x; + this._vel_y = this._last_y - this._y; + this._vel_z = this._last_z - this._z; + this._vel_yaw = ((this._last_yaw - this._yaw) % 360 + 360) % 360; + + assert this._vel_yaw >= 0; + + if (this._vel_yaw > 180) { + this._vel_yaw -= 360; + } + + this._last_PosTime = Std.getRealTime(); + this.inited = true; + } + + @Override + protected void transferFrom(Drone d) { + super.transferFrom(d); + if (d instanceof InterpolatedDrone) { + InterpolatedDrone i = (InterpolatedDrone)d; + this._x = i._x; + this._y = i._y; + this._z = i._z; + this._yaw = i._yaw; + this._vel_x = i._vel_x; + this._vel_y = i._vel_y; + this._vel_z = i._vel_z; + this._vel_yaw = i._vel_yaw; + this._last_x = i._last_x; + this._last_y = i._last_y; + this._last_z = i._last_z; + this._last_yaw = i._last_yaw; + this._last_PosTime = i._last_PosTime; + this._last_FrameTime = i._last_FrameTime; + this.inited = true; + } + } + + @Override + public void roomChange(Room newRoom, short x, short y, short z, short yaw) { + this.detach(); + if (newRoom != null) { + this.appear(newRoom, x, y, z, yaw); + } + } + + @Override + public void shortLoc(byte dx, byte dy, byte dyaw) { + if (!(this.getOwner() instanceof Pilot)) { + BlackBox.getInstance().submitEvent(new BBDroneDeltaPosCommand(this.getName(), dx, dy, dyaw)); + } + + this._last_x += dx; + this._last_y += dy; + this._last_yaw += dyaw; + this._last_yaw %= 360; + this._vel_x = this._last_x - this._x; + this._vel_y = this._last_y - this._y; + this._vel_z = 0; + this._vel_yaw = ((this._last_yaw - this._yaw) % 360 + 360) % 360; + + assert this._vel_yaw >= 0; + + if (this._vel_yaw > 180) { + this._vel_yaw -= 360; + } + + this._last_PosTime = Std.getRealTime(); + } + + @Override + public Object properties(int index, int offset, int mode, Object value) throws NoSuchPropertyException { + Object ret = null; + int var10000 = index - offset; + return super.properties(index, offset + 0, mode, value); + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/InventoryAction.java b/NET/worlds/scape/InventoryAction.java new file mode 100644 index 0000000..33d4e65 --- /dev/null +++ b/NET/worlds/scape/InventoryAction.java @@ -0,0 +1,28 @@ +package NET.worlds.scape; + +public class InventoryAction extends InventoryItem { + public InventoryAction(String id, String name) { + super(id, name); + } + + public InventoryAction(String id, String name, int qty) { + super(id, name, qty); + } + + public InventoryAction(InventoryAction in) { + super(in); + } + + @Override + public InventoryItem cloneItem() { + return new InventoryAction(this); + } + + public static InventoryAction createAction(String id, String name, int qty) { + return (InventoryAction)(id.equals("H") ? new HighJump(id, name, qty) : new InventoryAction(id, name, qty)); + } + + public boolean doAction() { + return true; + } +} diff --git a/NET/worlds/scape/InventoryAvatar.java b/NET/worlds/scape/InventoryAvatar.java new file mode 100644 index 0000000..dfd7b47 --- /dev/null +++ b/NET/worlds/scape/InventoryAvatar.java @@ -0,0 +1,20 @@ +package NET.worlds.scape; + +public class InventoryAvatar extends InventoryItem { + public InventoryAvatar(String id, String name) { + super(id, name); + } + + public InventoryAvatar(String id, String name, int qty) { + super(id, name, qty); + } + + public InventoryAvatar(InventoryAvatar in) { + super(in); + } + + @Override + public InventoryItem cloneItem() { + return new InventoryAvatar(this); + } +} diff --git a/NET/worlds/scape/InventoryCallback.java b/NET/worlds/scape/InventoryCallback.java new file mode 100644 index 0000000..5835472 --- /dev/null +++ b/NET/worlds/scape/InventoryCallback.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface InventoryCallback { + void droppedInventoryItem(Object var1); +} diff --git a/NET/worlds/scape/InventoryDialog.java b/NET/worlds/scape/InventoryDialog.java new file mode 100644 index 0000000..d3b1f93 --- /dev/null +++ b/NET/worlds/scape/InventoryDialog.java @@ -0,0 +1,310 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.ImageCanvas; +import NET.worlds.console.PolledDialog; +import NET.worlds.network.URL; +import java.awt.Button; +import java.awt.Color; +import java.awt.Font; +import java.awt.Frame; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Label; +import java.util.Vector; + +public class InventoryDialog extends PolledDialog { + private InventoryList rightWristItems_; + private ImageCanvas rightWristIcon_; + private InventoryList leftWristItems_; + private ImageCanvas leftWristIcon_; + private InventoryList headItems_; + private ImageCanvas headIcon_; + private InventoryList rightAnkleItems_; + private ImageCanvas rightAnkleIcon_; + private InventoryList leftAnkleItems_; + private ImageCanvas leftAnkleIcon_; + private Button okButton_; + private Button cancelButton_; + private Frame parent_; + private static final URL defaultImageURL = URL.make("home:..\\default.gif"); + private static Object lastPosAndSize; + + public InventoryDialog(Frame frame) { + super(frame, null, Console.message("Inventory"), true); + InventoryManager im = InventoryManager.getInventoryManager(); + Vector equippableItems = im.getEquippableItems(); + Vector equippedItems = im.getEquippedItems(); + this.parent_ = frame; + this.rightWristItems_ = new InventoryList(); + this.leftWristItems_ = new InventoryList(); + this.headItems_ = new InventoryList(); + this.rightAnkleItems_ = new InventoryList(); + this.leftAnkleItems_ = new InventoryList(); + this.rightWristIcon_ = new ImageCanvas(defaultImageURL); + this.leftWristIcon_ = new ImageCanvas(defaultImageURL); + this.headIcon_ = new ImageCanvas(defaultImageURL); + this.leftAnkleIcon_ = new ImageCanvas(defaultImageURL); + this.rightAnkleIcon_ = new ImageCanvas(defaultImageURL); + this.okButton_ = new Button("Ok"); + this.cancelButton_ = new Button("Cancel"); + + for (int i = 0; i < equippableItems.size(); i++) { + EquippableItem item = (EquippableItem)equippableItems.elementAt(i); + switch (item.getBodyLocation()) { + case 4: + this.headItems_.add(item); + break; + case 8: + this.rightWristItems_.add(item); + break; + case 13: + this.leftWristItems_.add(item); + break; + case 17: + this.rightAnkleItems_.add(item); + break; + case 21: + this.leftAnkleItems_.add(item); + } + } + + for (int i = 0; i < equippedItems.size(); i++) { + EquippableItem item = (EquippableItem)equippedItems.elementAt(i); + switch (item.getBodyLocation()) { + case 4: + this.headItems_.selectItem(item); + break; + case 8: + this.rightWristItems_.selectItem(item); + break; + case 13: + this.leftWristItems_.selectItem(item); + break; + case 17: + this.rightAnkleItems_.selectItem(item); + break; + case 21: + this.leftAnkleItems_.selectItem(item); + } + } + + this.ready(); + } + + @Override + protected void build() { + this.setBackground(Color.cyan); + this.setForeground(Color.black); + GridBagLayout gbag = new GridBagLayout(); + this.setLayout(gbag); + GridBagConstraints c = new GridBagConstraints(); + Font f1 = new Font(Console.message("ConsoleFont"), 1, 18); + Font f2 = new Font(Console.message("ConsoleFont"), 0, 12); + Label invLabel = new Label("Inventory"); + c.gridx = 2; + c.gridy = 0; + c.weightx = 3.0; + invLabel.setFont(f1); + this.add(gbag, invLabel, c); + Label rwLabel = new Label("Right Hand"); + c.gridx = 4; + c.gridy = 4; + c.weightx = 1.0; + rwLabel.setFont(f2); + this.add(gbag, rwLabel, c); + c.gridy = 5; + c.weighty = 1.0; + this.rightWristItems_.setFont(f2); + this.add(gbag, this.rightWristItems_, c); + c.gridx = 3; + c.gridy = 5; + c.weighty = 1.0; + c.weightx = 1.0; + this.add(gbag, this.rightWristIcon_, c); + Label lwLabel = new Label("Left Hand"); + c.gridx = 0; + c.gridy = 4; + c.weighty = 1.0; + lwLabel.setFont(f2); + this.add(gbag, lwLabel, c); + c.gridy = 5; + c.weighty = 1.0; + this.leftWristItems_.setFont(f2); + this.add(gbag, this.leftWristItems_, c); + c.gridx = 1; + c.gridy = 5; + c.weighty = 1.0; + c.weightx = 1.0; + this.add(gbag, this.leftWristIcon_, c); + Label headLabel = new Label("Head"); + c.gridx = 2; + c.gridy = 2; + c.weighty = 1.0; + headLabel.setFont(f2); + this.add(gbag, headLabel, c); + c.gridy = 3; + c.weighty = 1.0; + this.headItems_.setFont(f2); + this.add(gbag, this.headItems_, c); + c.gridx = 2; + c.gridy = 4; + c.weighty = 1.0; + c.weightx = 1.0; + this.add(gbag, this.headIcon_, c); + Label raLabel = new Label("Right Foot"); + c.gridx = 4; + c.gridy = 6; + c.weightx = 1.0; + raLabel.setFont(f2); + this.add(gbag, raLabel, c); + c.gridy = 7; + c.weighty = 0.0; + this.rightAnkleItems_.setFont(f2); + this.add(gbag, this.rightAnkleItems_, c); + c.gridx = 3; + c.gridy = 7; + c.weighty = 1.0; + c.weightx = 1.0; + this.add(gbag, this.rightAnkleIcon_, c); + Label laLabel = new Label("Left Foot"); + c.gridx = 0; + c.gridy = 6; + c.weighty = 1.0; + laLabel.setFont(f2); + this.add(gbag, laLabel, c); + c.gridy = 7; + c.weighty = 0.0; + this.leftAnkleItems_.setFont(f2); + this.add(gbag, this.leftAnkleItems_, c); + c.gridx = 1; + c.gridy = 7; + c.weighty = 1.0; + c.weightx = 1.0; + this.add(gbag, this.leftAnkleIcon_, c); + c.gridx = 0; + c.gridy = 10; + c.weightx = 2.0; + c.weighty = 1.0; + this.okButton_.setFont(f2); + this.add(gbag, this.okButton_, c); + c.gridx = 4; + c.gridy = 10; + this.cancelButton_.setFont(f2); + this.add(gbag, this.cancelButton_, c); + this.setSize(360, 300); + } + + @Override + public synchronized boolean done(boolean confirmed) { + Vector equippedItems = new Vector(); + EquippableItem eItem; + if ((eItem = this.rightWristItems_.getSelected()) != null) { + equippedItems.add(eItem); + } + + if ((eItem = this.leftWristItems_.getSelected()) != null) { + equippedItems.add(eItem); + } + + if ((eItem = this.headItems_.getSelected()) != null) { + equippedItems.add(eItem); + } + + if ((eItem = this.leftAnkleItems_.getSelected()) != null) { + equippedItems.add(eItem); + } + + if ((eItem = this.rightAnkleItems_.getSelected()) != null) { + equippedItems.add(eItem); + } + + if (confirmed) { + InventoryManager im = InventoryManager.getInventoryManager(); + im.setEquippedItems(equippedItems); + } + + return super.done(confirmed); + } + + @Override + public boolean handleEvent(java.awt.Event event) { + return super.handleEvent(event); + } + + @Override + public boolean action(java.awt.Event event, Object what) { + Object target = event.target; + URL imageURL = defaultImageURL; + if (target == this.leftWristItems_) { + InventoryItem item = this.leftWristItems_.getSelected(); + if (item != null) { + imageURL = item.getItemGraphicLocation(); + } + + this.setIcon(this.leftWristIcon_, imageURL); + return true; + } else if (target == this.rightWristItems_) { + InventoryItem item = this.rightWristItems_.getSelected(); + if (item != null) { + imageURL = item.getItemGraphicLocation(); + } + + this.setIcon(this.rightWristIcon_, imageURL); + return true; + } else if (target == this.headItems_) { + InventoryItem item = this.headItems_.getSelected(); + if (item != null) { + imageURL = item.getItemGraphicLocation(); + } + + this.setIcon(this.headIcon_, imageURL); + return true; + } else if (target == this.leftAnkleItems_) { + InventoryItem item = this.leftAnkleItems_.getSelected(); + if (item != null) { + imageURL = item.getItemGraphicLocation(); + } + + this.setIcon(this.leftAnkleIcon_, imageURL); + return true; + } else if (target == this.rightAnkleItems_) { + InventoryItem item = this.rightAnkleItems_.getSelected(); + if (item != null) { + imageURL = item.getItemGraphicLocation(); + } + + this.setIcon(this.rightAnkleIcon_, imageURL); + return true; + } else if (target == this.okButton_) { + return this.done(true); + } else { + return target == this.cancelButton_ ? this.done(false) : false; + } + } + + private void setIcon(ImageCanvas ic, URL newLoc) { + ic.setNewImage(newLoc, this.getGraphics()); + this.repaint(); + } + + @Override + public void savePosAndSize(Object state) { + lastPosAndSize = state; + } + + @Override + public Object restorePosAndSize() { + return lastPosAndSize; + } + + @Override + public boolean keyDown(java.awt.Event event, int key) { + return key == 27 ? this.done(false) : super.keyDown(event, key); + } + + @Override + protected synchronized void activeCallback() { + this.notify(); + } +} diff --git a/NET/worlds/scape/InventoryItem.java b/NET/worlds/scape/InventoryItem.java new file mode 100644 index 0000000..22fbd30 --- /dev/null +++ b/NET/worlds/scape/InventoryItem.java @@ -0,0 +1,65 @@ +package NET.worlds.scape; + +import NET.worlds.network.URL; + +public class InventoryItem { + protected String itemId_; + protected String itemName_; + protected int itemQuantity_; + protected URL itemGraphicLocation_; + + public InventoryItem(String id, String name) { + this.itemId_ = id; + this.itemName_ = name; + this.itemQuantity_ = 1; + } + + public InventoryItem(String id, String name, int qty) { + this.itemId_ = id; + this.itemName_ = name; + this.itemQuantity_ = qty; + } + + public InventoryItem(InventoryItem in) { + this.itemId_ = in.itemId_; + this.itemName_ = in.itemName_; + this.itemQuantity_ = in.itemQuantity_; + this.itemGraphicLocation_ = in.itemGraphicLocation_; + } + + public String getItemId() { + return this.itemId_; + } + + public void setItemId(String id) { + this.itemId_ = id; + } + + public String getItemName() { + return this.itemName_; + } + + public void setItemName(String name) { + this.itemName_ = name; + } + + public int getItemQuantity() { + return this.itemQuantity_; + } + + public void setQuantity(int qty) { + this.itemQuantity_ = qty; + } + + public URL getItemGraphicLocation() { + return this.itemGraphicLocation_; + } + + public void setItemGraphicLocation(URL newLoc) { + this.itemGraphicLocation_ = newLoc; + } + + public InventoryItem cloneItem() { + return new InventoryItem(this); + } +} diff --git a/NET/worlds/scape/InventoryList.java b/NET/worlds/scape/InventoryList.java new file mode 100644 index 0000000..250f9df --- /dev/null +++ b/NET/worlds/scape/InventoryList.java @@ -0,0 +1,26 @@ +package NET.worlds.scape; + +import java.awt.Choice; +import java.util.Vector; + +class InventoryList extends Choice { + private Vector invItems_ = new Vector(); + + public InventoryList() { + super.add("None"); + } + + public EquippableItem getSelected() { + int selectedIndex = super.getSelectedIndex(); + return selectedIndex > 0 ? (EquippableItem)this.invItems_.elementAt(selectedIndex - 1) : null; + } + + public void add(EquippableItem item) { + super.add(item.getItemName()); + this.invItems_.add(item); + } + + public void selectItem(EquippableItem item) { + super.select(item.getItemName()); + } +} diff --git a/NET/worlds/scape/InventoryManager.java b/NET/worlds/scape/InventoryManager.java new file mode 100644 index 0000000..641619a --- /dev/null +++ b/NET/worlds/scape/InventoryManager.java @@ -0,0 +1,315 @@ +package NET.worlds.scape; + +import NET.worlds.console.ActionsPart; +import NET.worlds.console.Console; +import NET.worlds.console.TradeDialog; +import NET.worlds.console.WhisperManager; +import NET.worlds.core.ServerTableManager; +import NET.worlds.network.URL; +import java.net.MalformedURLException; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +public class InventoryManager { + private static InventoryManager manager_; + private Hashtable<String, InventoryItem> masterList_; + private Hashtable<String, InventoryItem> inventory_ = new Hashtable<String, InventoryItem>(); + private boolean initialized_; + private Vector<InventoryItem> equipped_; + + public synchronized void setEquippedItems(Vector<InventoryItem> equippedItems) { + this.removeEquippedItems(); + this.equipped_ = equippedItems; + this.equipItems(); + } + + public synchronized Vector<InventoryItem> getEquippedItems() { + return this.equipped_; + } + + private synchronized void removeEquippedItems() { + for (int i = 0; i < this.equipped_.size(); i++) { + EquippableItem itemToEquip = (EquippableItem)this.equipped_.elementAt(i); + Shape ownedShape = itemToEquip.getOwnedShape(); + if (ownedShape != null) { + ownedShape.detach(); + } + + itemToEquip.setOwnedShape(null); + } + } + + private synchronized void equipItems() { + System.out.println("Equipped Items Size: " + this.equipped_.size()); + + for (int i = 0; i < this.equipped_.size(); i++) { + Shape itemShape = new Shape(); + EquippableItem itemToEquip = (EquippableItem)this.equipped_.elementAt(i); + if (itemToEquip != null) { + try { + itemShape.setURL(new URL(itemToEquip.getModelLocation())); + } catch (MalformedURLException var10) { + System.out.println("Badly formed URL for " + itemToEquip.getItemName()); + continue; + } + + float s = itemToEquip.getScale(); + itemShape.scale(s, s, s); + itemShape.pitch(itemToEquip.getPitch()); + itemShape.roll(itemToEquip.getRoll()); + itemShape.yaw(itemToEquip.getYaw()); + itemShape.moveBy(itemToEquip.getXPos(), itemToEquip.getYPos(), itemToEquip.getZPos()); + int properLoc = itemToEquip.getBodyLocation(); + DeepEnumeration de = new DeepEnumeration(); + Pilot.getActive().getChildren(de); + + while (de.hasMoreElements()) { + Object obj = de.nextElement(); + if (obj instanceof Shape) { + Shape objShape = (Shape)obj; + int partType = objShape.getBodPartNum(); + if (partType == properLoc) { + objShape.add(itemShape); + itemToEquip.setOwnedShape(itemShape); + break; + } + } + } + } + } + } + + public Vector<InventoryItem> getEquippableItems() { + Vector<InventoryItem> retVal = new Vector<InventoryItem>(); + Enumeration<InventoryItem> invEnum = this.inventory_.elements(); + + while (invEnum.hasMoreElements()) { + InventoryItem obj = invEnum.nextElement(); + if (obj instanceof EquippableItem) { + retVal.addElement(obj); + } + } + + return retVal; + } + + public Vector<InventoryItem> getInventoryAvatars() { + Vector<InventoryItem> retVal = new Vector<InventoryItem>(); + Enumeration<InventoryItem> invEnum = this.inventory_.elements(); + + while (invEnum.hasMoreElements()) { + InventoryItem obj = invEnum.nextElement(); + if (obj instanceof InventoryAvatar) { + retVal.addElement(obj); + } + } + + return retVal; + } + + public Hashtable<String, InventoryItem> getInventoryItems() { + return this.inventory_; + } + + public int checkInventoryFor(String nm) { + InventoryItem it = this.inventory_.get(nm); + return it != null ? it.getItemQuantity() : 0; + } + + public Vector<InventoryItem> getInventoryActionList() { + Vector<InventoryItem> retVal = new Vector<InventoryItem>(); + Enumeration<InventoryItem> invEnum = this.inventory_.elements(); + + while (invEnum.hasMoreElements()) { + InventoryItem obj = invEnum.nextElement(); + if (obj instanceof InventoryAction) { + retVal.addElement(obj); + } + } + + return retVal; + } + + public void doInventoryAction(String act) { + Vector<InventoryItem> actVector = this.getInventoryActionList(); + + for (int i = 0; i < actVector.size(); i++) { + InventoryAction invAct = (InventoryAction)actVector.elementAt(i); + if (invAct.getItemName().equalsIgnoreCase(act)) { + invAct.doAction(); + String msg = "&|+deal>trade " + invAct.getItemId() + ","; + TradeDialog.sendTradeMessage(msg); + } + } + } + + public void setInventory(String invString) { + this.initialized_ = true; + Hashtable<String, InventoryItem> newInv = this.parseInventoryString(invString); + this.inventory_ = newInv; + Enumeration<TradeDialog> e = WhisperManager.whisperManager().tradeDialogs().elements(); + + while (e.hasMoreElements()) { + TradeDialog wd = e.nextElement(); + wd.setTrading(true); + } + + if (Console.getActive() != null) { + Console a = Console.getActive(); + a.inventoryChanged(); + if (a.targetValid != a.isValidAv()) { + a.resetAvatar(); + } + } + + ActionsPart.updateActionDialog(); + } + + public Hashtable<String, InventoryItem> parseInventoryString(String invString) { + Hashtable<String, InventoryItem> newInventory = new Hashtable<String, InventoryItem>(); + if (invString == null) { + return newInventory; + } else { + int len = invString.length(); + int itemStart = 0; + + while (itemStart < len) { + char ch = invString.charAt(itemStart); + if (ch < 'A' || ch > 'Z') { + System.out.println("Bad inventory: " + invString); + return newInventory; + } + + int descLen; + for (descLen = 1; itemStart + descLen < len; descLen++) { + ch = invString.charAt(itemStart + descLen); + if (ch < 'a' || ch > 'z') { + break; + } + } + + String shortName = invString.substring(itemStart, itemStart + descLen); + int countStart = itemStart + descLen; + int countLen = 0; + + while (true) { + if (countLen + countStart < len) { + ch = invString.charAt(countStart + countLen); + if (ch >= '0' && ch <= '9') { + countLen++; + continue; + } + } + + int count = 1; + if (countLen > 0) { + count = Integer.parseInt(invString.substring(countStart, countStart + countLen)); + } + + InventoryItem foundItem = this.masterList_.get(shortName); + if (foundItem != null) { + InventoryItem newItem = foundItem.cloneItem(); + newItem.setQuantity(count); + newInventory.put(shortName, newItem); + } + + itemStart = countStart + countLen; + break; + } + } + + return newInventory; + } + } + + public String properCase(String s) { + return s.equals("") ? s : s.substring(0, 1).toUpperCase() + s.substring(1); + } + + public String getSingular(String sn) { + InventoryItem item = this.masterList_.get(sn); + return item != null ? item.getItemName() : "unknown" + sn; + } + + public String getPlural(String sn) { + return this.getSingular(sn) + "s"; + } + + public String itemName(String sn, int num) { + return num == 1 ? "a " + this.getSingular(sn) : num + " " + this.getPlural(sn); + } + + public String itemName(InventoryItem item) { + return this.itemName(item.getItemId(), item.getItemQuantity()); + } + + private InventoryManager() { + this.masterList_ = new Hashtable<String, InventoryItem>(); + this.initialized_ = false; + this.equipped_ = new Vector<InventoryItem>(); + ServerTableManager stm = ServerTableManager.instance(); + int invVersion = stm.getFileVersion(); + String[] invStrings = stm.getTable("invList"); + String[] graphicStrings = new String[0]; + if (invVersion > 1) { + graphicStrings = stm.getTable("graphicList"); + } + + URL defaultImageURL = URL.make("home:..\\default.gif"); + if (invStrings != null) { + int numStringsPerItem = 12; + + for (int i = 0; i < invStrings.length; i += numStringsPerItem) { + String id = invStrings[i]; + String name = invStrings[i + 2]; + String model = invStrings[i + 3]; + int loc = Double.valueOf(invStrings[i + 4]).intValue(); + float scale = Double.valueOf(invStrings[i + 5]).floatValue(); + int pitch = Double.valueOf(invStrings[i + 6]).intValue(); + int roll = Double.valueOf(invStrings[i + 7]).intValue(); + int yaw = Double.valueOf(invStrings[i + 8]).intValue(); + float xPos = Double.valueOf(invStrings[i + 9]).floatValue(); + float yPos = Double.valueOf(invStrings[i + 10]).floatValue(); + float zPos = Double.valueOf(invStrings[i + 11]).floatValue(); + URL graphic = null; + if (invVersion > 1 && graphicStrings.length > i / 6 + 1) { + String gString = graphicStrings[i / 6 + 1]; + if (gString != "default") { + graphic = URL.make(gString); + } + } + + if (graphic == null) { + graphic = defaultImageURL; + } + + InventoryItem newItem; + if (id.charAt(0) == 'H') { + newItem = InventoryAction.createAction(id, name, 1); + } else if (id.charAt(0) == 'W') { + newItem = new EquippableItem(id, name, 1, model, scale, loc, xPos, yPos, zPos, pitch, roll, yaw); + } else if (id.charAt(0) == 'V') { + newItem = new InventoryAvatar(id, name, 1); + } else { + newItem = new InventoryItem(id, name, 1); + } + + newItem.setItemGraphicLocation(graphic); + this.masterList_.put(id, newItem); + } + } + } + + public static InventoryManager getInventoryManager() { + if (manager_ == null) { + manager_ = new InventoryManager(); + } + + return manager_; + } + + public boolean inventoryInitialized() { + return this.initialized_; + } +} diff --git a/NET/worlds/scape/ItemNotAvailableDialog.java b/NET/worlds/scape/ItemNotAvailableDialog.java new file mode 100644 index 0000000..c70268f --- /dev/null +++ b/NET/worlds/scape/ItemNotAvailableDialog.java @@ -0,0 +1,42 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.DialogReceiver; +import NET.worlds.console.ImageButtons; +import NET.worlds.console.ImageButtonsCallback; +import NET.worlds.console.PolledDialog; +import java.awt.Component; +import java.awt.Rectangle; +import java.awt.Window; + +public class ItemNotAvailableDialog extends PolledDialog implements ImageButtonsCallback { + private ImageButtons ib; + + public ItemNotAvailableDialog(Window parent, DialogReceiver receiver) { + super(parent, receiver, Console.message("Not-Available"), false); + this.setAlignment(1); + Rectangle[] rects = new Rectangle[]{new Rectangle(101, 22, 48, 19)}; + this.ib = new ImageButtons(Console.message("notavail.gif"), rects, this); + this.ready(); + } + + @Override + protected void build() { + this.add("Center", this.ib); + } + + @Override + public Object imageButtonsCallback(Component who, int which) { + this.done(false); + return null; + } + + @Override + public boolean keyDown(java.awt.Event event, int key) { + if (key == 27) { + return this.done(false); + } else { + return key == 10 ? this.done(false) : super.keyDown(event, key); + } + } +} diff --git a/NET/worlds/scape/Key.java b/NET/worlds/scape/Key.java new file mode 100644 index 0000000..95f7cff --- /dev/null +++ b/NET/worlds/scape/Key.java @@ -0,0 +1,53 @@ +package NET.worlds.scape; + +public interface Key { + char bkspace = '\ue308'; + char tab = '\ue309'; + char enter = '\ue30d'; + char shift = '\ue310'; + char ctrl = '\ue311'; + char pause = '\ue313'; + char capLock = '\ue314'; + char esc = '\ue31b'; + char pgup = '\ue321'; + char pgdn = '\ue322'; + char end = '\ue323'; + char home = '\ue324'; + char left = '\ue325'; + char up = '\ue326'; + char right = '\ue327'; + char down = '\ue328'; + char insert = '\ue32d'; + char del = '\ue32e'; + char starPad = '\ue36a'; + char plusPad = '\ue36b'; + char minusPad = '\ue36d'; + char slashPad = '\ue36f'; + char f1 = '\ue370'; + char f2 = '\ue371'; + char f3 = '\ue372'; + char f4 = '\ue373'; + char f5 = '\ue374'; + char f6 = '\ue375'; + char f7 = '\ue376'; + char f8 = '\ue377'; + char f9 = '\ue378'; + char f11 = '\ue37a'; + char f12 = '\ue37b'; + char numLock = '\ue390'; + char scrollLock = '\ue391'; + char semicolon = '\ue3ba'; + char equals = '\ue3bb'; + char comma = '\ue3bc'; + char minusKbd = '\ue3bd'; + char period = '\ue3be'; + char slashKbd = '\ue3bf'; + char backQuote = '\ue3c0'; + char openBrkt = '\ue3db'; + char backslash = '\ue3dc'; + char closeBrkt = '\ue3dd'; + char quote = '\ue3de'; + char leftMouse = '\ue301'; + char rightMouse = '\ue302'; + char centerMouse = '\ue304'; +} diff --git a/NET/worlds/scape/KeyCharEvent.java b/NET/worlds/scape/KeyCharEvent.java new file mode 100644 index 0000000..f02227e --- /dev/null +++ b/NET/worlds/scape/KeyCharEvent.java @@ -0,0 +1,12 @@ +package NET.worlds.scape; + +public class KeyCharEvent extends KeyEvent { + public KeyCharEvent(int time, WObject target, char key) { + super(time, null, target, key); + } + + @Override + public boolean deliver(Object o) { + return o instanceof KeyCharHandler && ((KeyCharHandler)o).handle(this) ? true : super.deliver(o); + } +} diff --git a/NET/worlds/scape/KeyCharHandler.java b/NET/worlds/scape/KeyCharHandler.java new file mode 100644 index 0000000..648f7f4 --- /dev/null +++ b/NET/worlds/scape/KeyCharHandler.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface KeyCharHandler { + boolean handle(KeyCharEvent var1); +} diff --git a/NET/worlds/scape/KeyDownEvent.java b/NET/worlds/scape/KeyDownEvent.java new file mode 100644 index 0000000..5ba9ffb --- /dev/null +++ b/NET/worlds/scape/KeyDownEvent.java @@ -0,0 +1,12 @@ +package NET.worlds.scape; + +public class KeyDownEvent extends KeyEvent { + public KeyDownEvent(int time, WObject target, char key) { + super(time, null, target, key); + } + + @Override + public boolean deliver(Object o) { + return o instanceof KeyDownHandler && ((KeyDownHandler)o).handle(this) ? true : super.deliver(o); + } +} diff --git a/NET/worlds/scape/KeyDownHandler.java b/NET/worlds/scape/KeyDownHandler.java new file mode 100644 index 0000000..c2227f4 --- /dev/null +++ b/NET/worlds/scape/KeyDownHandler.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface KeyDownHandler { + boolean handle(KeyDownEvent var1); +} diff --git a/NET/worlds/scape/KeyEvent.java b/NET/worlds/scape/KeyEvent.java new file mode 100644 index 0000000..cff81f8 --- /dev/null +++ b/NET/worlds/scape/KeyEvent.java @@ -0,0 +1,19 @@ +package NET.worlds.scape; + +public class KeyEvent extends UserEvent { + char key; + + public KeyEvent(int time, Object source, WObject target, char key) { + super(time, source, target); + this.key = key; + } + + @Override + public boolean deliver(Object o) { + return o instanceof KeyHandler && ((KeyHandler)o).handle(this) ? true : super.deliver(o); + } + + public char getKey() { + return this.key; + } +} diff --git a/NET/worlds/scape/KeyHandler.java b/NET/worlds/scape/KeyHandler.java new file mode 100644 index 0000000..eb421e4 --- /dev/null +++ b/NET/worlds/scape/KeyHandler.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface KeyHandler { + boolean handle(KeyEvent var1); +} diff --git a/NET/worlds/scape/KeyUpEvent.java b/NET/worlds/scape/KeyUpEvent.java new file mode 100644 index 0000000..0976a60 --- /dev/null +++ b/NET/worlds/scape/KeyUpEvent.java @@ -0,0 +1,12 @@ +package NET.worlds.scape; + +public class KeyUpEvent extends KeyEvent { + public KeyUpEvent(int time, WObject target, char key) { + super(time, null, target, key); + } + + @Override + public boolean deliver(Object o) { + return o instanceof KeyUpHandler && ((KeyUpHandler)o).handle(this) ? true : super.deliver(o); + } +} diff --git a/NET/worlds/scape/KeyUpHandler.java b/NET/worlds/scape/KeyUpHandler.java new file mode 100644 index 0000000..d2fa2e9 --- /dev/null +++ b/NET/worlds/scape/KeyUpHandler.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface KeyUpHandler { + boolean handle(KeyUpEvent var1); +} diff --git a/NET/worlds/scape/LibEntContentEditorDialog.java b/NET/worlds/scape/LibEntContentEditorDialog.java new file mode 100644 index 0000000..2311d8c --- /dev/null +++ b/NET/worlds/scape/LibEntContentEditorDialog.java @@ -0,0 +1,131 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.OkCancelDialog; +import java.awt.Choice; +import java.awt.GridBagConstraints; +import java.awt.List; +import java.awt.TextField; +import java.util.Enumeration; +import java.util.StringTokenizer; + +class LibEntContentEditorDialog extends OkCancelDialog { + private Property property; + private TextField strField = new TextField(40); + private List list = new List(); + private Choice choice = new Choice(); + private EditTile parent; + private static String[] choices = new String[]{"WObject files", "Behavior/Action files", "Texture files"}; + private static String[] dirs = new String[]{LibrariesTile.getLibSubdir(), LibrariesTile.getLibSubdir(), LibrariesTile.getLibSubdir()}; + private static String[] exts = new String[]{WObject.getSaveExtension(), "class", TextureDecoder.getAllExts()}; + + LibEntContentEditorDialog(EditTile parent, String title, Property property) { + super(Console.getFrame(), parent, title); + this.property = property; + this.parent = parent; + this.ready(); + } + + private void matchExt(String name) { + int lastDot = name.lastIndexOf(46); + if (lastDot != -1) { + String ext = name.substring(lastDot + 1).toLowerCase(); + + for (int i = 0; i < exts.length; i++) { + StringTokenizer t = new StringTokenizer(exts[i], ";"); + + while (t.hasMoreTokens()) { + if (ext.equals(t.nextToken())) { + this.choice.select(i); + return; + } + } + } + } + } + + @Override + protected void build() { + for (int i = 0; i < choices.length; i++) { + this.choice.addItem(choices[i]); + } + + String name = (String)this.property.get(); + if (name == null) { + name = ""; + } + + this.strField.setText(name); + this.matchExt(name); + this.setListContents(); + GridBagConstraints c = new GridBagConstraints(); + c.fill = 2; + c.weightx = 1.0; + c.weighty = 1.0; + c.gridwidth = 0; + this.add(this.gbag, this.strField, c); + c.gridheight = 6; + this.add(this.gbag, this.list, c); + c.gridheight = 1; + this.add(this.gbag, this.choice, c); + super.build(); + } + + private void setListContents() { + int count = this.list.countItems(); + if (count != 0) { + this.list.delItems(0, count - 1); + } + + int chosen = this.choice.getSelectedIndex(); + Enumeration files = new FileList(dirs[chosen], exts[chosen]).getList().elements(); + + while (files.hasMoreElements()) { + this.list.addItem((String)files.nextElement()); + } + + String s = (String)this.property.get(); + this.strField.setText(s != null ? s : ""); + } + + @Override + public boolean handleEvent(java.awt.Event event) { + if (event.id == 701) { + this.strField.setText(this.list.getSelectedItem()); + this.strField.selectAll(); + } + + return super.handleEvent(event); + } + + @Override + public boolean action(java.awt.Event event, Object what) { + if (event.target == this.list) { + event.target = this.okButton; + } + + if (event.target == this.choice) { + this.setListContents(); + } + + return super.action(event, what); + } + + @Override + protected boolean setValue() { + String text = this.strField.getText().trim(); + if (text.length() != 0) { + this.parent.addUndoableSet(this.property, text); + return true; + } else { + return false; + } + } + + @Override + public void show() { + super.show(); + this.strField.requestFocus(); + this.strField.selectAll(); + } +} diff --git a/NET/worlds/scape/LibEntContentPropertyEditor.java b/NET/worlds/scape/LibEntContentPropertyEditor.java new file mode 100644 index 0000000..b7890fa --- /dev/null +++ b/NET/worlds/scape/LibEntContentPropertyEditor.java @@ -0,0 +1,18 @@ +package NET.worlds.scape; + +import NET.worlds.console.PolledDialog; + +public class LibEntContentPropertyEditor extends PropEditor { + private LibEntContentPropertyEditor(Property property) { + super(property); + } + + @Override + public PolledDialog edit(EditTile parent, String title) { + return new LibEntContentEditorDialog(parent, title, this.property); + } + + public static Property make(Property property) { + return property.setEditor(new LibEntContentPropertyEditor(property)); + } +} diff --git a/NET/worlds/scape/LibEventHandler.java b/NET/worlds/scape/LibEventHandler.java new file mode 100644 index 0000000..38d3d81 --- /dev/null +++ b/NET/worlds/scape/LibEventHandler.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface LibEventHandler { + void libraryChanged(Library var1); +} diff --git a/NET/worlds/scape/LibrariesTile.java b/NET/worlds/scape/LibrariesTile.java new file mode 100644 index 0000000..d0fcd5f --- /dev/null +++ b/NET/worlds/scape/LibrariesTile.java @@ -0,0 +1,374 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.Cursor; +import NET.worlds.console.Main; +import NET.worlds.console.MainCallback; +import NET.worlds.core.IniFile; +import NET.worlds.network.URL; +import java.awt.Color; +import java.awt.Component; +import java.awt.Point; +import java.io.File; +import java.util.Enumeration; +import java.util.Vector; + +public class LibrariesTile extends TabbedPanel implements LibEventHandler, Properties, MainCallback, LibraryDropTarget { + private static final int NOTHING = 0; + private static final int ADD_LIBRARY = 1; + private static final int ADD_ELEMENT = 2; + private static URL libURL = URL.make("home:libraries/"); + private static String libSubdir; + private Vector libraries = new Vector(); + private int queue = 0; + private boolean iconsVisible = false; + private Cursor dragCursor; + private Cursor cantCursor; + private LibraryEntry leftClickedOn; + + static { + String s = libURL.unalias(); + libSubdir = s.substring(0, s.length() - 1); + } + + public static String getLibSubdir() { + return libSubdir; + } + + public LibrariesTile() { + this.setBackground(Color.lightGray); + Vector libNames = new FileList(libSubdir, "library").getList(); + Enumeration e = libNames.elements(); + + while (e.hasMoreElements()) { + Library lib = Library.load(URL.make(libURL, (String)e.nextElement())); + if (lib != null) { + this.addLibrary(lib); + } + } + + if (this.libraries.size() != 0) { + this.select(0); + } + + Main.register(this); + } + + public synchronized void addLibrary() { + if (this.queue == 0) { + this.queue = 1; + } + } + + public synchronized void addElement() { + if (this.queue == 0) { + this.queue = 2; + } + } + + @Override + public synchronized void mainCallback() { + switch (this.queue) { + case 1: + this.syncAddLibrary(new Library()); + break; + case 2: + this.syncAddElement(new LibraryEntry()); + } + + this.queue = 0; + } + + private boolean isUniqueLibraryURL(URL name) { + if (name == null) { + return false; + } else { + Enumeration e = this.libraries.elements(); + + while (e.hasMoreElements()) { + Library lib = (Library)e.nextElement(); + if (lib.getSourceURL().equals(name)) { + return false; + } + } + + return true; + } + } + + private boolean isUniqueLibraryName(String name) { + if (name == null) { + return false; + } else { + Enumeration e = this.libraries.elements(); + + while (e.hasMoreElements()) { + Library lib = (Library)e.nextElement(); + if (lib.getName().equals(name)) { + return false; + } + } + + return true; + } + } + + private void syncAddLibrary(Library lib) { + boolean newEntry = lib.getNameMaybeNull() == null; + if (!this.isUniqueLibraryURL(lib.getSourceURL())) { + int i = 1; + + URL url; + do { + url = URL.make(libURL, "lib" + i++ + ".library"); + } while (!this.isUniqueLibraryURL(url)); + + lib.setSourceURL(url); + } + + if (this.libraries.size() == 0) { + File f = new File(libSubdir); + f.mkdir(); + } + + if (!this.isUniqueLibraryName(lib.getNameMaybeNull())) { + int num = 1; + + String libName; + do { + libName = "Category" + num++; + } while (!this.isUniqueLibraryName(libName)); + + lib.setName(libName); + } + + if (this.saveAllowed()) { + lib.save(); + } else { + Console.println(Console.message("AllowChangeLibrary")); + } + + this.addLibrary(lib); + if (newEntry) { + this.select(this.libraries.indexOf(lib)); + } + } + + private void syncDeleteLibrary(Library lib) { + if (this.saveAllowed()) { + lib.delete(); + } else { + Console.println(Console.message("AllowChangeLibrary")); + } + + int index = this.libraries.indexOf(lib); + this.libraries.removeElementAt(index); + this.removeItem(index); + } + + private void syncAddElement(LibraryEntry ent) { + if (this.libraries.size() != 0) { + int selected = this.selected(); + Library lib = (Library)this.libraries.elementAt(selected); + lib.add(ent); + } + } + + private void addLibrary(Library lib) { + int count = this.libraries.size(); + String name = lib.getName(); + int i = 0; + + while (i < count && name.compareTo(((Library)this.libraries.elementAt(i)).getName()) >= 0) { + i++; + } + + this.libraries.insertElementAt(lib, i); + this.insertItem(i, lib.getName(), new ScrollingImagePanel(this, lib.getContents(), this.iconsVisible)); + lib.setEventHandler(this); + lib.setOwningDialog(this); + } + + public boolean isIconsVisible() { + return this.iconsVisible; + } + + public void setIconsVisible(boolean showIcons) { + this.iconsVisible = showIcons; + int count = this.libraries.size(); + + for (int i = 0; i < count; i++) { + ScrollingImagePanel c = (ScrollingImagePanel)this.getComponent(i); + c.setIconsVisible(showIcons); + } + } + + @Override + public void libraryChanged(Library lib) { + Library selected = (Library)this.libraries.elementAt(this.selected()); + int index = this.libraries.indexOf(lib); + this.libraries.removeElementAt(index); + this.removeItem(index); + this.addLibrary(lib); + this.select(this.libraries.indexOf(selected)); + if (this.saveAllowed()) { + lib.save(); + } else { + Console.println(Console.message("AllowChangeLibrary")); + } + } + + private boolean saveAllowed() { + return IniFile.gamma().getIniInt("AllowChangeLibrary", 0) == 1; + } + + private Library getLibrary(ScrollingImagePanel panel) { + int count = this.libraries.size(); + + for (int i = 0; i < count; i++) { + if (this.getComponent(i) == panel) { + return (Library)this.libraries.elementAt(i); + } + } + + return null; + } + + private LibraryEntry getLibraryEntry(Component comp, Point location) { + if (comp instanceof ScrollingImagePanel) { + ScrollingImagePanel panel = (ScrollingImagePanel)comp; + Library lib = this.getLibrary(panel); + if (lib != null) { + int item = panel.itemAt(location); + if (item >= 0) { + return lib.getEntry(item); + } + } + } + + return null; + } + + private boolean maybeMoveEntry(LibraryEntry src, Component comp, Point loc) { + LibraryEntry dst = this.getLibraryEntry(comp, loc); + if (dst != null && dst != src) { + Library srcOwner = (Library)src.getOwner(); + Library dstOwner = (Library)dst.getOwner(); + + assert srcOwner == dstOwner; + + srcOwner.move(src, dst); + return true; + } else { + if (comp == this) { + Library newLib = (Library)this.libraries.elementAt(this.itemAt(loc)); + Library oldLib = (Library)src.getOwner(); + if (newLib != oldLib) { + oldLib.delete(src); + newLib.add(src); + return true; + } + } + + return false; + } + } + + @Override + public void clickEvent(Component who, Point location, int flags) { + if ((flags & 1) != 0) { + if ((flags & 4) != 0 && who == this) { + Console.getFrame().getEditTile().viewProperties(this.libraries.elementAt(this.itemAt(location))); + } else { + LibraryEntry ent; + if ((ent = this.getLibraryEntry(who, location)) != null) { + this.leftClickedOn = null; + if (ent != null) { + if ((flags & 4) != 0) { + Console.getFrame().getEditTile().viewProperties(ent); + } else { + this.leftClickedOn = ent; + Console console = Console.getActive(); + if (this.dragCursor == null) { + this.dragCursor = new Cursor(URL.make("home:drag.cur")); + } else { + this.dragCursor.detach(); + console.addCursor(this.dragCursor); + this.dragCursor.activate(); + } + } + } + } + } + } else if ((flags & 2) != 0) { + Cursor active = Cursor.getActive(); + if (active != null && (active == this.dragCursor || active == this.cantCursor)) { + Console.getActive().getCursor().activate(); + } + + if (this.leftClickedOn != null) { + if (!this.maybeMoveEntry(this.leftClickedOn, who, location)) { + URL url = this.leftClickedOn.getContentURL(); + String propName = this.leftClickedOn.getPropertyName(true); + if (url != null) { + Console.getFrame().getEditTile().libraryDrop(url, propName, who, location); + } + } + + this.leftClickedOn = null; + } + } else { + Cursor activex = Cursor.getActive(); + boolean isDropTarget = who instanceof LibraryDropTarget; + if (activex == this.dragCursor) { + if (!isDropTarget) { + Console console = Console.getActive(); + if (this.cantCursor == null) { + this.cantCursor = new Cursor(URL.make("system:CANNOT_CURSOR")); + } else { + this.cantCursor.detach(); + console.addCursor(this.cantCursor); + this.cantCursor.activate(); + } + + this.cantCursor.activate(); + } + } else if (activex != null && activex == this.cantCursor && isDropTarget) { + this.dragCursor.activate(); + } + } + } + + @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 = PropAdder.make(new VectorProperty(this, index, "Contents")); + } else if (mode == 1) { + ret = this.libraries; + } else if (mode == 3) { + this.syncAddLibrary((Library)value); + } else if (mode == 4) { + this.syncDeleteLibrary((Library)value); + } else if (mode == 5 && value instanceof Library) { + ret = value; + } + + return ret; + default: + throw new NoSuchPropertyException(); + } + } + + @Override + public Object propertyParent() { + return null; + } + + @Override + public String toString() { + return "Libraries"; + } +} diff --git a/NET/worlds/scape/Library.java b/NET/worlds/scape/Library.java new file mode 100644 index 0000000..a531d71 --- /dev/null +++ b/NET/worlds/scape/Library.java @@ -0,0 +1,191 @@ +package NET.worlds.scape; + +import NET.worlds.network.URL; +import java.io.File; +import java.io.IOException; +import java.util.Vector; + +public class Library extends SuperRoot { + private Object owningDialog; + private Vector contents = new Vector(); + private LibEventHandler handler; + protected String propertyName; + private static Object classCookie = new Object(); + + public static Library load(URL url) { + return (Library)SuperRoot.readFile(url); + } + + public Library(URL url, String name) { + this.setSourceURL(url); + this.setName(name); + } + + public Library() { + } + + public void save() { + try { + this.saveFile(this.getSourceURL()); + } catch (IOException var2) { + } + } + + public void delete() { + new File(this.getSourceURL().unalias()).delete(); + } + + public void add(LibraryEntry ent) { + assert ent.getOwner() == null; + + this.contents.addElement(ent); + super.add(ent); + this.changed(); + } + + public void delete(LibraryEntry ent) { + boolean found = this.contents.removeElement(ent); + + assert found; + + assert ent.getOwner() == this; + + ent.detach(); + this.changed(); + } + + public void move(LibraryEntry src, LibraryEntry dst) { + int oldPos = this.contents.indexOf(src); + + assert oldPos != -1; + + int newPos = this.contents.indexOf(dst); + + assert newPos != -1; + + this.contents.removeElement(src); + this.contents.insertElementAt(src, newPos); + this.changed(); + } + + void entryChanged(LibraryEntry which) { + this.changed(); + } + + private void changed() { + if (this.handler != null) { + this.handler.libraryChanged(this); + } + } + + public Object getOwningDialog() { + return this.owningDialog; + } + + public Vector getContents() { + return (Vector)this.contents.clone(); + } + + public String getPropertyName() { + return this.propertyName; + } + + public LibraryEntry getEntry(int index) { + return (LibraryEntry)this.contents.elementAt(index); + } + + public void setOwningDialog(Object o) { + this.owningDialog = o; + } + + @Override + public void setName(String s) { + super.setName(s); + this.changed(); + } + + public void setPropertyName(String s) { + this.propertyName = s; + this.changed(); + } + + public void setEventHandler(LibEventHandler handler) { + this.handler = handler; + } + + @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 = PropAdder.make(new VectorProperty(this, index, "Contents")); + } else if (mode == 1) { + ret = this.getContents(); + } else if (mode == 4) { + this.delete((LibraryEntry)value); + } else if (mode == 3) { + this.add((LibraryEntry)value); + } else if (mode == 5 && value instanceof LibraryEntry) { + ret = value; + } + break; + case 1: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Property Name").allowSetNull()); + } else if (mode == 1) { + ret = this.getPropertyName(); + } else if (mode == 2) { + this.setPropertyName((String)value); + } + break; + default: + ret = super.properties(index, offset + 2, mode, value); + } + + return ret; + } + + @Override + public Object propertyParent() { + return this.getOwningDialog(); + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(2, classCookie); + super.saveState(s); + s.saveVector(this.contents); + s.saveString(this.propertyName); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + Vector newContents = null; + switch (r.restoreVersion(classCookie)) { + case 0: + this.setName(r.restoreString()); + r.restoreString(); + r.restoreString(); + newContents = r.restoreVector(); + break; + case 1: + super.restoreState(r); + r.restoreString(); + r.restoreString(); + newContents = r.restoreVector(); + break; + case 2: + super.restoreState(r); + newContents = r.restoreVector(); + this.propertyName = r.restoreString(); + break; + default: + throw new TooNewException(); + } + + for (int i = 0; i < newContents.size(); i++) { + this.add((LibraryEntry)newContents.elementAt(i)); + } + } +} diff --git a/NET/worlds/scape/LibraryDrop.java b/NET/worlds/scape/LibraryDrop.java new file mode 100644 index 0000000..1987859 --- /dev/null +++ b/NET/worlds/scape/LibraryDrop.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface LibraryDrop { + boolean libraryDrop(EditTile var1, Object var2, boolean var3, boolean var4); +} diff --git a/NET/worlds/scape/LibraryDropTarget.java b/NET/worlds/scape/LibraryDropTarget.java new file mode 100644 index 0000000..1c26d13 --- /dev/null +++ b/NET/worlds/scape/LibraryDropTarget.java @@ -0,0 +1,4 @@ +package NET.worlds.scape; + +public interface LibraryDropTarget { +} diff --git a/NET/worlds/scape/LibraryEntry.java b/NET/worlds/scape/LibraryEntry.java new file mode 100644 index 0000000..415c35a --- /dev/null +++ b/NET/worlds/scape/LibraryEntry.java @@ -0,0 +1,141 @@ +package NET.worlds.scape; + +import NET.worlds.network.URL; +import java.io.IOException; + +public class LibraryEntry extends SuperRoot implements Iconic { + protected URL iconURL; + protected URL contentURL; + protected String propertyName; + private static Object classCookie = new Object(); + + public LibraryEntry() { + } + + public LibraryEntry(String name, URL iconURL) { + this.setName(name); + this.iconURL = iconURL; + } + + private void changed() { + Library owner = (Library)this.getOwner(); + if (owner != null) { + owner.entryChanged(this); + } + } + + @Override + public String getIconCaption() { + return this.getName(); + } + + @Override + public URL getIconURL() { + return this.iconURL; + } + + public URL getContentURL() { + return this.contentURL; + } + + public String getPropertyName(boolean checkParent) { + Library owner; + return this.propertyName == null && checkParent && (owner = (Library)this.getOwner()) != null ? owner.getPropertyName() : this.propertyName; + } + + @Override + public void setName(String s) { + super.setName(s); + this.changed(); + } + + public void setIconURL(URL s) { + this.iconURL = s; + this.changed(); + } + + public void setContentURL(URL s) { + this.contentURL = s; + this.changed(); + } + + public void setPropertyName(String s) { + this.propertyName = s; + this.changed(); + } + + @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 = URLPropertyEditor.make(new Property(this, index, "Icon").allowSetNull(), TextureDecoder.getJavaExts()); + } else if (mode == 1) { + ret = this.getIconURL(); + } else if (mode == 2) { + this.setIconURL((URL)value); + } + break; + case 1: + if (mode == 0) { + ret = URLPropertyEditor.make(new Property(this, index, "Content URL").allowSetNull(), "*wob"); + } else if (mode == 1) { + ret = this.contentURL; + } else if (mode == 2) { + this.setContentURL((URL)value); + } + break; + case 2: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Property Name").allowSetNull()); + } else if (mode == 1) { + ret = this.getPropertyName(false); + } else if (mode == 2) { + this.setPropertyName((String)value); + } + break; + default: + ret = super.properties(index, offset + 3, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(3, classCookie); + super.saveState(s); + URL.save(s, this.iconURL); + URL.save(s, this.contentURL); + s.saveString(this.propertyName); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 1: + super.restoreState(r); + case 0: + this.setName(r.restoreString()); + this.iconURL = URL.restore(r); + this.contentURL = URL.restore(r); + r.restoreMaybeNull(); + break; + case 2: + super.restoreState(r); + this.setName(r.restoreString()); + this.iconURL = URL.restore(r); + this.contentURL = URL.restore(r); + break; + case 3: + super.restoreState(r); + this.iconURL = URL.restore(r); + this.contentURL = URL.restore(r); + this.propertyName = r.restoreString(); + break; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/Light.java b/NET/worlds/scape/Light.java new file mode 100644 index 0000000..a1e64f6 --- /dev/null +++ b/NET/worlds/scape/Light.java @@ -0,0 +1,58 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class Light extends WObject { + protected int lightID; + private static Object classCookie = new Object(); + + @Override + protected void addRwChildren(WObject parent) { + super.addRwChildren(parent); + Point3Temp p = this.getWorldPosition(); + } + + @Override + protected void markVoid() { + super.markVoid(); + if (this.lightID != 0) { + destroyLight(this.lightID); + } + } + + @Override + protected void noteTransformChange() { + super.noteTransformChange(); + if (this.lightID != 0) { + setLightTransform(this.lightID, this.clumpID); + } + } + + private static native void setLightTransform(int var0, int var1); + + private static native void destroyLight(int var0); + + @Override + public Object properties(int index, int offset, int mode, Object value) throws NoSuchPropertyException { + Object ret = null; + int var10000 = index - offset; + return super.properties(index, offset + 0, mode, value); + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/ListAdderDialog.java b/NET/worlds/scape/ListAdderDialog.java new file mode 100644 index 0000000..ae3115c --- /dev/null +++ b/NET/worlds/scape/ListAdderDialog.java @@ -0,0 +1,84 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.OkCancelDialog; +import java.awt.Choice; +import java.awt.GridBagConstraints; +import java.util.Enumeration; +import java.util.Vector; + +public abstract class ListAdderDialog extends OkCancelDialog { + private Choice list = new Choice(); + private boolean doSet = false; + private int choice; + protected EditTile parent; + + public ListAdderDialog(EditTile parent, String title) { + super(Console.getFrame(), parent, title); + this.parent = parent; + } + + @Override + protected void build() { + GridBagConstraints c = new GridBagConstraints(); + c.fill = 1; + c.weightx = 1.0; + c.weighty = 1.0; + c.gridwidth = 0; + this.add(this.gbag, this.list, c); + super.build(); + } + + protected void setListContents(String[] options) { + this.list.removeAll(); + + for (int i = 0; i < options.length; i++) { + this.list.addItem(options[i]); + } + } + + protected void setListContents(Vector options) { + this.list.removeAll(); + Enumeration e = options.elements(); + + while (e.hasMoreElements()) { + this.list.addItem((String)e.nextElement()); + } + } + + protected abstract void add(int var1); + + @Override + protected final synchronized void activeCallback() { + if (this.doSet) { + this.add(this.choice); + this.doSet = false; + this.notify(); + } + } + + @Override + protected synchronized boolean setValue() { + if ((this.choice = this.list.getSelectedIndex()) == -1) { + return false; + } else { + this.doSet = true; + + while (this.doSet) { + try { + this.wait(); + } catch (InterruptedException var2) { + } + } + + return true; + } + } + + @Override + public void show() { + super.show(); + this.list.select(0); + this.list.requestFocus(); + } +} diff --git a/NET/worlds/scape/ListChooserDialog.java b/NET/worlds/scape/ListChooserDialog.java new file mode 100644 index 0000000..8b9f1ff --- /dev/null +++ b/NET/worlds/scape/ListChooserDialog.java @@ -0,0 +1,55 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.OkCancelDialog; +import java.awt.GridBagConstraints; +import java.awt.List; + +public abstract class ListChooserDialog extends OkCancelDialog { + private List _listField = new List(5, false); + protected EditTile _parent; + + protected ListChooserDialog(EditTile parent, String title) { + super(Console.getFrame(), parent, title); + this._parent = parent; + } + + @Override + protected void build() { + GridBagConstraints c = new GridBagConstraints(); + c.weightx = 1.0; + c.weighty = 1.0; + c.gridwidth = 0; + c.fill = 1; + this.add(this.gbag, this._listField, c); + super.build(); + } + + protected abstract String getEntry(int var1); + + protected abstract int getSelected(); + + protected abstract boolean setValue(String var1, int var2); + + @Override + protected boolean setValue() { + return this.setValue(this._listField.getSelectedItem(), this._listField.getSelectedIndex()); + } + + @Override + public void show() { + super.show(); + int index = 0; + + for (String entry = this.getEntry(index); entry != null; entry = this.getEntry(++index)) { + this._listField.addItem(entry, index); + } + + index = this.getSelected(); + if (index != -1) { + this._listField.select(index); + } + + this._listField.requestFocus(); + } +} diff --git a/NET/worlds/scape/ListEditorDialog.java b/NET/worlds/scape/ListEditorDialog.java new file mode 100644 index 0000000..4bdb939 --- /dev/null +++ b/NET/worlds/scape/ListEditorDialog.java @@ -0,0 +1,36 @@ +package NET.worlds.scape; + +import java.util.StringTokenizer; + +public abstract class ListEditorDialog extends FieldEditorDialog { + public ListEditorDialog(EditTile parent, String title) { + super(parent, title); + } + + protected abstract int getElementCount(); + + protected abstract String getElement(int var1); + + protected abstract boolean setElements(StringTokenizer var1); + + @Override + protected String getValue() { + String text = ""; + int count = this.getElementCount(); + + for (int i = 0; i < count; i++) { + if (i != 0) { + text = text + ", "; + } + + text = text + this.getElement(i); + } + + return text; + } + + @Override + protected boolean setValue(String text) { + return this.setElements(new StringTokenizer(text, ", \t", false)); + } +} diff --git a/NET/worlds/scape/LoadedAttribute.java b/NET/worlds/scape/LoadedAttribute.java new file mode 100644 index 0000000..ee458c3 --- /dev/null +++ b/NET/worlds/scape/LoadedAttribute.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface LoadedAttribute { + void loadedAttribute(Attribute var1, String var2); +} diff --git a/NET/worlds/scape/LoadedURLSelf.java b/NET/worlds/scape/LoadedURLSelf.java new file mode 100644 index 0000000..6c4881c --- /dev/null +++ b/NET/worlds/scape/LoadedURLSelf.java @@ -0,0 +1,7 @@ +package NET.worlds.scape; + +import NET.worlds.network.URL; + +public interface LoadedURLSelf { + void loadedURLSelf(URLSelf var1, URL var2, String var3); +} diff --git a/NET/worlds/scape/MCISoundCommand.java b/NET/worlds/scape/MCISoundCommand.java new file mode 100644 index 0000000..00bffcd --- /dev/null +++ b/NET/worlds/scape/MCISoundCommand.java @@ -0,0 +1,14 @@ +package NET.worlds.scape; + +abstract class MCISoundCommand { + boolean isOnQueue; + float left; + float right; + int frameNum; + + public abstract void run(); + + public void onQueue(boolean f) { + this.isOnQueue = f; + } +} diff --git a/NET/worlds/scape/MCISoundPlayer.java b/NET/worlds/scape/MCISoundPlayer.java new file mode 100644 index 0000000..d87d245 --- /dev/null +++ b/NET/worlds/scape/MCISoundPlayer.java @@ -0,0 +1,161 @@ +package NET.worlds.scape; + +import NET.worlds.network.URL; + +public class MCISoundPlayer extends SoundPlayer { + private static MCIThread mciThread = new MCIThread(); + float ang; + float dist; + float vol; + int leftToRepeat; + int running; + MCISoundCommand poll = new MCISoundCommand() { + @Override + public void run() { + MCISoundPlayer.this.gotFinished(MCISoundPlayer.this.nativeIsFinished()); + } + }; + private URL url; + private static MCISoundCommand activeStopCmd; + MCISoundCommand volumeCmd = new MCISoundCommand() { + @Override + public void run() { + if (!WavSoundPlayer.ignoreVolumeChanges) { + MCISoundPlayer.this.nativeVolume(this.left, this.right); + } + } + }; + + public MCISoundPlayer(Sound owner) { + super(owner); + } + + @Override + public boolean open(float volume, float stopDist, boolean atten, boolean pan) { + return true; + } + + @Override + public void close() { + this.stop(); + } + + @Override + public boolean position(Point3Temp cam, Point3Temp obj, Point3Temp out, Point3Temp up) { + Point3Temp toObj = Point3Temp.make(obj).minus(cam); + Point3Temp right = Point3Temp.make(out).cross(up); + float y = toObj.dot(out); + float x = toObj.dot(right); + this.ang = (float)(Math.atan2(y, x) / Math.PI); + this.dist = toObj.length(); + return this.setVolume(this.vol); + } + + @Override + public boolean setVolume(float v) { + this.vol = v; + float leftFrac = 0.5F; + if (this.owner != null && this.owner.getPanning()) { + leftFrac = Math.abs(this.ang); + if (this.ang < 0.0F) { + v = this.vol * (float)(0.5 + Math.abs(0.5 + this.ang)); + } + } + + if (this.owner != null && this.owner.getAttenuate()) { + float stopDist = this.owner.getStopDistance(); + if (this.dist > stopDist) { + this.volume(0.0F, 0.0F); + return false; + } + + v *= (stopDist - this.dist) / stopDist; + } + + this.volume(v * leftFrac, v * (1.0F - leftFrac)); + return true; + } + + @Override + public int getState() { + if (!this.poll.isOnQueue) { + mciThread.pushCommand(this.poll); + } + + return this.running != 0 ? 0 : 1; + } + + @Override + public synchronized void start(int repeatCount) { + if (repeatCount == 0) { + this.running = 0; + } else { + this.leftToRepeat = repeatCount; + if (this.leftToRepeat > 0) { + this.leftToRepeat--; + } + + this.running = 1; + activeStopCmd = null; + mciThread.pushCommand(new MCISoundCommand() { + @Override + public void run() { + MCISoundPlayer.this.doStart(); + } + }); + } + } + + public synchronized void start(URL u) { + this.url = u; + this.start(1); + } + + synchronized void doStart() { + this.running = 2; + if (!this.nativeStart((this.owner == null ? this.url : this.owner.getURL()).unalias())) { + this.running = 3; + } + } + + synchronized void gotFinished(boolean f) { + if (f && this.running == 2) { + this.start(this.leftToRepeat); + } + } + + @Override + public synchronized void stop() { + this.leftToRepeat = 0; + activeStopCmd = new MCISoundCommand() { + @Override + public void run() { + if (MCISoundPlayer.activeStopCmd == this) { + MCISoundPlayer.activeStopCmd = null; + MCISoundPlayer.this.nativeStop(); + } + } + }; + mciThread.pushCommand(activeStopCmd); + } + + public void volume(float left, float right) { + this.volumeCmd.left = left; + this.volumeCmd.right = right; + if (!this.volumeCmd.isOnQueue) { + mciThread.pushCommand(this.volumeCmd); + } + } + + private native void nativeVolume(float var1, float var2); + + private native boolean nativeStart(String var1); + + private native boolean nativeIsFinished(); + + private native void nativeStop(); + + public static native boolean isActive(); + + static native void shutdown(); +} diff --git a/NET/worlds/scape/MCIThread.java b/NET/worlds/scape/MCIThread.java new file mode 100644 index 0000000..e63518a --- /dev/null +++ b/NET/worlds/scape/MCIThread.java @@ -0,0 +1,44 @@ +package NET.worlds.scape; + +import NET.worlds.console.Main; +import NET.worlds.console.MainCallback; +import NET.worlds.console.MainTerminalCallback; +import java.util.Vector; + +class MCIThread implements MainCallback, MainTerminalCallback { + private Vector queue = new Vector(); + private int frameNum; + + public MCIThread() { + Main.register(this); + } + + public synchronized void pushCommand(MCISoundCommand c) { + this.queue.addElement(c); + c.onQueue(true); + c.frameNum = this.frameNum + 2; + } + + @Override + public synchronized void mainCallback() { + this.frameNum++; + + while (this.queue.size() > 0) { + MCISoundCommand command = (MCISoundCommand)this.queue.elementAt(0); + if (command.frameNum > this.frameNum) { + return; + } + + command.onQueue(false); + this.queue.removeElementAt(0); + command.run(); + } + } + + @Override + public synchronized void terminalCallback() { + MCISoundPlayer.shutdown(); + ASFSoundPlayer.shutdown(); + Main.unregister(this); + } +} diff --git a/NET/worlds/scape/Manifest.java b/NET/worlds/scape/Manifest.java new file mode 100644 index 0000000..dc888a9 --- /dev/null +++ b/NET/worlds/scape/Manifest.java @@ -0,0 +1,92 @@ +package NET.worlds.scape; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +public class Manifest { + private IndentStream _out; + private Hashtable<Object, String> _ht = new Hashtable<Object, String>(); + private int _lastID = 0; + + public Manifest(IndentStream out) { + this._out = out; + this._out.println("MANIFEST Worlds, Inc."); + this._out.indent(); + } + + public Manifest(String name) throws IOException { + this(new IndentStream(new FileOutputStream(name))); + } + + public void done() { + this._out.undent(); + this._out.println("END MANIFEST"); + this._out.close(); + this._out = null; + this._ht = null; + } + + private void printID(String s) { + this._out.print(" (#" + s + ")"); + } + + private void printRef(Object obj) { + if (obj instanceof SuperRoot) { + this._out.print(((SuperRoot)obj).getName()); + } else { + this._out.print("<anonymous>"); + } + + if (this._ht.containsKey(obj)) { + this.printID(this._ht.get(obj)); + this._out.println(" --q.v.--"); + } else { + String newID = Integer.toString(this._lastID++); + this._ht.put(obj, newID); + this.printID(newID); + this._out.println(":" + obj.getClass().getName() + " ["); + this._out.indent(); + this.saveProps((Properties)obj); + this._out.undent(); + this._out.println("]"); + } + } + + private void saveMaybeProp(Object obj) { + if (obj instanceof Properties && !obj.getClass().getName().equals("NET.worlds.scape.Transform")) { + this.printRef(obj); + } else { + this._out.println(obj); + } + } + + public void saveProps(Properties obj) { + Enumeration<Object> pe = new EnumProperties(obj); + + while (pe.hasMoreElements()) { + Property prop = (Property)pe.nextElement(); + this._out.print(prop.getName()); + this._out.print(" := "); + if (prop instanceof VectorProperty) { + this._out.println("{"); + this._out.indent(); + Vector<Object> v = (Vector<Object>)prop.get(); + if (v != null) { + Enumeration<Object> ve = v.elements(); + + while (ve.hasMoreElements()) { + this.saveMaybeProp(ve.nextElement()); + } + } + + this._out.undent(); + this._out.println("}"); + } else { + this.saveMaybeProp(prop.get()); + } + } + } +} diff --git a/NET/worlds/scape/Material.java b/NET/worlds/scape/Material.java new file mode 100644 index 0000000..36e4a45 --- /dev/null +++ b/NET/worlds/scape/Material.java @@ -0,0 +1,783 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.Main; +import NET.worlds.console.MainCallback; +import NET.worlds.core.IniFile; +import NET.worlds.network.NetUpdate; +import NET.worlds.network.URL; +import java.awt.Color; +import java.io.IOException; + +public class Material extends SuperRoot implements BGLoaded, MainCallback { + static int serial = 0; + public static boolean botMode = false; + private boolean keepLoaded = false; + private int[] ids; + private Texture[] textures; + private int vRes = 1; + private int hRes = 1; + private int sPos = -1; + private final boolean loResMode = false; + URL textureName; + protected URL[] subnames; + private boolean doReclump; + private static boolean tryBMP = IniFile.gamma().getIniInt("TRYBMP", 0) != 0; + private float ambient; + private float diffuse; + private float specular; + private float opacity; + private boolean smooth; + private boolean filter; + private int r; + private int g; + private int b; + private Color color; + private static Object classCookie = new Object(); + + static { + nativeInit(); + } + + public static native void nativeInit(); + + public Material(float ambient, float diffuse, float specular, Color color, Texture texture, float opacity, boolean smooth, boolean filter) { + if (botMode) { + texture = null; + } + + this.ambient = ambient; + this.diffuse = diffuse; + this.specular = specular; + this.setColor(color); + if (texture != null) { + this.textures = new Texture[1]; + this.textures[0] = texture; + } + + this.opacity = opacity; + this.smooth = smooth; + this.filter = filter; + } + + public Material(Color color) { + this(0.75F, 0.0F, 0.0F, color, null, 1.0F, false, false); + } + + public Material(Texture texture) { + this(0.75F, 0.0F, 0.0F, Color.black, texture, 1.0F, false, false); + } + + public Material(Color initialColor, URL textureName) { + this(initialColor != null ? initialColor : new Color(128, 128, 128)); + if (!botMode) { + this.loadTexture(textureName); + } + } + + public Material(URL tileTexture, int x, int y) { + this(0.75F, 0.0F, 0.0F, Color.black, null, 1.0F, false, false); + this.hRes = x; + this.vRes = y; + serial++; + int numSubs = this.getHRes() * this.getVRes(); + this.textures = new Texture[numSubs]; + this.makeMaterials(); + this.subnames = new URL[numSubs]; + String lowResBaseName = tileTexture.getBase(); + int nextSubname = 0; + + for (int v = this.vRes; v > 0; v--) { + String vExt = "" + v; + + for (int h = 0; h < this.hRes; nextSubname++) { + URL subname = URL.make(tileTexture, lowResBaseName + serial + vExt + (h + 1) + ".cmp"); + this.subnames[nextSubname] = subname; + this.syncBackgroundLoad(tileTexture.unalias(), subname); + h++; + } + } + } + + public Material(URL textureName) { + this(null, textureName); + } + + public Material() { + } + + @Override + protected void noteAddingTo(SuperRoot owner) { + if (((WObject)owner).hasClump()) { + this.addRwChildren(); + } + } + + @Override + public void detach() { + if (this.ids != null) { + this.markVoid(); + } + + super.detach(); + } + + public Texture[] getTextures() { + return this.textures; + } + + public void addRwChildren() { + if (this.ids == null) { + if (this.textures == null && this.textureName != null) { + this.loadTextures(); + } else { + this.makeMaterials(); + if (this.textures != null) { + for (int i = 0; i < this.ids.length; i++) { + this.nativeSetTexture(i, this.textures[i]); + } + } + } + } + } + + public void markVoid() { + if (!this.keepLoaded) { + if (this.textureName != null) { + this.removeTextures(); + } + + this.closeMaterials(); + } + } + + public void setKeepLoaded(boolean f) { + boolean klWas = this.keepLoaded; + this.keepLoaded = f; + if (!f && klWas) { + SuperRoot o = this.getOwner(); + if (o == null || !((WObject)o).hasClump()) { + this.markVoid(); + } + } + } + + public static Material restore(Restorer r) throws IOException, TooNewException { + Material m = (Material)r.restoreMaybeNull(); + if (m != null && r.version() < 6 && m.getOwner() != null) { + m = (Material)m.clone(); + } + + return m; + } + + private native void nativeSetTexture(int var1, Texture var2); + + private synchronized void setTexture(int texNum, Texture texture) { + if (this.textures[texNum] != null) { + Texture t = this.extractTexture(texNum); + if (t != null) { + t.decRef(); + } + } + + this.textures[texNum] = texture; + this.nativeSetTexture(texNum, texture); + if (!this.doReclump) { + this.doReclump = true; + Main.register(this); + } + } + + @Override + public void mainCallback() { + Main.unregister(this); + if (this.doReclump) { + this.propagateTextureChange(); + } + + this.doReclump = false; + } + + private void propagateTextureChange() { + if (this.ids != null) { + Object o = this.getOwner(); + if (o instanceof WObject) { + if (o instanceof Surface && ((Surface)o).getMaterial() == this) { + ((Surface)o).setMaterial(this, true); + } else if (o instanceof Shape && ((Shape)o).getMaterial() == this) { + ((Shape)o).setMaterial(this); + } else { + ((WObject)o).reclump(); + } + } + } + + this.doReclump = false; + } + + public synchronized void setTexture(Texture texture) { + this.textureName = null; + if (this.textures != null && this.textures.length != 1) { + this.removeTextures(); + this.textures = new Texture[1]; + this.setTexture(0, texture); + } else { + if (this.textures == null) { + this.textures = new Texture[1]; + } else if (texture == this.textures[0]) { + return; + } + + this.setTexture(0, texture); + } + } + + synchronized native Texture extractTexture(int var1); + + private void removeTextures() { + if (this.textures != null) { + for (int i = 0; i < this.textures.length; i++) { + Texture t = this.extractTexture(i); + if (t != null) { + t.decRef(); + } + } + + this.textures = null; + } + + this.hRes = this.vRes = 1; + this.sPos = -1; + this.closeMaterials(); + } + + @Override + protected void finalize() { + this.removeTextures(); + super.finalize(); + } + + private native void closeMaterial(int var1); + + private void closeMaterials() { + if (this.ids != null) { + for (int i = 0; i < this.ids.length; i++) { + this.closeMaterial(i); + } + + this.ids = null; + } + } + + private int calcRes() { + this.hRes = 1; + this.vRes = 1; + this.sPos = -1; + if (this.textureName == null) { + return -1; + } else { + String name = this.textureName.getInternal(); + int len = name.length(); + if (len >= 4 && name.regionMatches(true, len - 4, ".mov", 0, 4)) { + this.sPos = 0; + } + + if (len > 7 && name.regionMatches(true, len - 5, "*.", 0, 2)) { + int num; + int nextStarIndex; + for (nextStarIndex = len - 5; + nextStarIndex > 2 && name.charAt(nextStarIndex) == '*' && (num = name.charAt(nextStarIndex - 2) - '0') > 0 && num <= 9; + nextStarIndex -= 3 + ) { + char control = Character.toLowerCase(name.charAt(nextStarIndex - 1)); + if (control == 'h') { + this.hRes = num; + } else if (control == 'v') { + this.vRes = num; + } else if (control == 's' && this.sPos >= 0) { + this.sPos = num - 1; + } + } + + return len - (nextStarIndex + 1); + } else { + return -1; + } + } + } + + private void loadTextures() { + int endLen = this.calcRes(); + if (endLen >= 0) { + String lowResBaseName = this.textureName.getBase(); + int baseEnd = lowResBaseName.length() - endLen; + lowResBaseName = lowResBaseName.substring(0, baseEnd); + int numSubs = this.getHRes() * this.getVRes(); + this.textures = new Texture[numSubs]; + this.makeMaterials(); + if (this.sPos >= 0) { + this.subnames = new URL[1]; + this.subnames[0] = URL.make(this.textureName, lowResBaseName + ".mov"); + BackgroundLoader.get(this, this.subnames[0]); + } else { + this.subnames = new URL[numSubs]; + int nextSubname = 0; + + for (int v = this.vRes; v > 0; v--) { + String vExt = "" + v; + + for (int h = 0; h < this.hRes; nextSubname++) { + URL subname = URL.make(this.textureName, lowResBaseName + vExt + (h + 1) + ".cmp"); + this.subnames[nextSubname] = subname; + BackgroundLoader.get(this, subname); + h++; + } + } + } + } else { + this.subnames = null; + this.textures = new Texture[1]; + this.makeMaterials(); + BackgroundLoader.get(this, this.textureName); + } + } + + public void loadTexture(URL textureName) { + boolean vis = this.ids != null; + this.removeTextures(); + this.textureName = textureName; + this.calcRes(); + if (vis) { + this.addRwChildren(); + } + + Object o = this.getOwner(); + if (o instanceof WObject) { + ((WObject)o).reclump(); + } + } + + private static native int makeMaterial(float var0, float var1, float var2, float var3, int var4, int var5, int var6, boolean var7); + + private void makeMaterials() { + int numSubs = this.getHRes() * this.getVRes(); + this.ids = new int[numSubs]; + + for (int i = 0; i < numSubs; i++) { + this.ids[i] = makeMaterial( + this.ambient, this.diffuse, this.specular, this.opacity, this.color.getRed(), this.color.getGreen(), this.color.getBlue(), this.smooth + ); + } + } + + private void loadError(URL name) { + SuperRoot owner = this.getOwner(); + System.out.println("Unable to load texture " + name + (owner == null ? "" : " for " + owner.getName()) + "."); + } + + public float getAmbient() { + return this.ambient; + } + + public float getDiffuse() { + return this.diffuse; + } + + public float getSpecular() { + return this.specular; + } + + public float getOpacity() { + return this.opacity; + } + + public boolean getSmooth() { + return this.smooth; + } + + public boolean getFilter() { + return this.filter; + } + + public boolean getHiRes() { + return this.vRes > 1 || this.hRes > 1; + } + + public int getVRes() { + return this.vRes; + } + + public int getHRes() { + return this.hRes; + } + + public int getRed() { + return this.r; + } + + public int getGreen() { + return this.g; + } + + public int getBlue() { + return this.b; + } + + public Color getColor() { + return this.color; + } + + public native void paramChange(); + + public void setAmbient(float ambient) { + this.ambient = ambient; + this.paramChange(); + } + + public void setDiffuse(float diffuse) { + this.diffuse = diffuse; + this.paramChange(); + } + + public void setSpecular(float specular) { + this.specular = specular; + this.paramChange(); + } + + public void setOpacity(float opacity) { + this.opacity = opacity; + this.paramChange(); + } + + public void setSmooth(boolean smooth) { + this.smooth = smooth; + this.paramChange(); + } + + public void setFilter(boolean filter) { + this.filter = filter; + this.paramChange(); + } + + public void setColor(Color color) { + this.color = color; + this.r = color.getRed(); + this.g = color.getGreen(); + this.b = color.getBlue(); + this.paramChange(); + } + + @Override + public Object asyncBackgroundLoad(String localName, URL remoteURL) { + return localName; + } + + @Override + public boolean syncBackgroundLoad(Object obj, URL remoteURL) { + int texNum = 0; + if (this.textures == null) { + return false; + } else { + String urlString = remoteURL.getAbsolute(); + String avatarDir = IniFile.gamma().getIniString("avatarDir", "avatar/"); + if (!avatarDir.endsWith("/")) { + avatarDir = avatarDir + "/"; + } + + String avStart = URL.make(NetUpdate.getUpgradeServerURL() + avatarDir).getAbsolute(); + String remoteBase = remoteURL == null ? null : remoteURL.getBase(); + String textureBase = this.textureName == null ? null : this.textureName.getBase(); + if (!remoteBase.equals(textureBase)) { + if (this.textureName != null && this.textureName.endsWith(".mov")) { + String rawBase = this.textureName.getBaseWithoutExt(); + String rawRemote = remoteURL.getBaseWithoutExt(); + if (!rawBase.startsWith(rawRemote)) { + return false; + } + } else { + if (this.subnames == null) { + return false; + } + + while (texNum < this.subnames.length) { + String subBase = this.subnames[texNum].getBase(); + if (remoteBase.equals(subBase)) { + break; + } + + texNum++; + } + + if (texNum == this.textures.length) { + return false; + } + } + } + + String localName = (String)obj; + if (this.ids == null) { + return false; + } else { + if (localName != null) { + if (this.sPos < 0) { + Texture t = TextureDecoder.decode(remoteURL, localName); + if (t != null && t.textureID != 0) { + this.setTexture(texNum, t); + } else { + localName = null; + } + } else { + Texture[] ts = new ScapePicMovie(localName, remoteURL).getTextures(); + if (ts != null && this.hRes * this.vRes * (this.sPos + 1) <= ts.length) { + int i = this.hRes * this.vRes * this.sPos; + + for (int v = (this.vRes - 1) * this.hRes; v >= 0; v -= this.hRes) { + for (int h = 0; h < this.hRes; i++) { + this.setTexture(v + h, ts[i]); + h++; + } + } + } else { + localName = null; + } + } + } else { + int len = urlString.length(); + if (tryBMP && this.sPos == -1 && len > 4 && urlString.regionMatches(true, len - 4, ".cmp", 0, 4) && !remoteURL.isRemote()) { + String lName = urlString.substring(0, len - 4) + ".bmp"; + Texture t = TextureDecoder.decode(URL.make(lName), lName); + if (t != null && t.textureID != 0) { + this.setTexture(texNum, t); + localName = lName; + } + } + } + + if (localName == null) { + if (urlString.startsWith("avatar:")) { + BackgroundLoader.get(this, URL.make(avStart + urlString.substring(7))); + return false; + } + + this.loadError(remoteURL); + } + + return false; + } + } + } + + @Override + public Room getBackgroundLoadRoom() { + WObject owner = (WObject)this.getOwner(); + return owner == null ? null : owner.getRoom(); + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(4, classCookie); + super.saveState(s); + s.saveFloat(this.getAmbient()); + s.saveFloat(this.getDiffuse()); + s.saveFloat(this.getSpecular()); + s.saveFloat(this.getOpacity()); + s.saveBoolean(this.getSmooth()); + s.saveBoolean(this.getFilter()); + s.saveInt(this.getRed()); + s.saveInt(this.getGreen()); + s.saveInt(this.getBlue()); + URL.save(s, this.textureName); + s.saveBoolean(this.keepLoaded); + if (this.textureName == null) { + if (this.textures != null && this.textures.length != 1) { + s.saveMaybeNull(null); + } else { + s.saveMaybeNull(this.textures == null ? null : this.textures[0]); + } + } + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + Texture texture = null; + int vers = r.restoreVersion(classCookie); + switch (vers) { + case 1: + super.restoreState(r); + case 0: { + this.ambient = r.restoreFloat(); + this.diffuse = r.restoreFloat(); + this.specular = r.restoreFloat(); + this.opacity = r.restoreFloat(); + int red = r.restoreInt(); + int green = r.restoreInt(); + int blue = r.restoreInt(); + this.setColor(new Color(red, green, blue)); + texture = (Texture)r.restoreMaybeNull(); + break; + } + case 2: + case 3: + case 4: { + super.restoreState(r); + this.ambient = r.restoreFloat(); + this.diffuse = r.restoreFloat(); + this.specular = r.restoreFloat(); + this.opacity = r.restoreFloat(); + if (vers > 3) { + this.smooth = r.restoreBoolean(); + this.filter = r.restoreBoolean(); + } + + int red = r.restoreInt(); + int green = r.restoreInt(); + int blue = r.restoreInt(); + this.setColor(new Color(red, green, blue)); + URL name = URL.restore(r); + if (vers > 2) { + this.setKeepLoaded(r.restoreBoolean()); + } + + if (name == null) { + texture = (Texture)r.restoreMaybeNull(); + } else { + this.loadTexture(name); + } + break; + } + default: + throw new TooNewException(); + } + + if (texture != null) { + this.textures = new Texture[1]; + this.textures[0] = texture; + } + + assert r.version() >= 6 || this.getOwner() == null; + } + + @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 = new Property(this, index, "Texture").allowSetNull(); + } else if (mode == 1) { + MaterialTexture mt; + if (this.textures != null && this.textures[0] instanceof StringTexture) { + mt = new MaterialTexture((StringTexture)this.textures[0]); + } else { + mt = new MaterialTexture(this.textureName); + } + + this.add(mt); + ret = mt; + } else if (mode == 2) { + if (value == null) { + this.loadTexture(null); + } else { + Console.println(Console.message("Cant-undo-tex")); + } + } + break; + case 1: + if (mode == 0) { + ret = ColorPropertyEditor.make(new Property(this, index, "Color")); + } else if (mode == 1) { + ret = this.getColor(); + } else if (mode == 2) { + this.setColor((Color)value); + } + break; + case 2: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Ambient Reflection Coefficient"), 0.0F, 1.0F); + } else if (mode == 1) { + ret = new Float(this.getAmbient()); + } else if (mode == 2) { + this.setAmbient((Float)value); + } + break; + case 3: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Diffuse Reflection Coefficient"), 0.0F, 1.0F); + } else if (mode == 1) { + ret = new Float(this.getDiffuse()); + } else if (mode == 2) { + this.setDiffuse((Float)value); + } + break; + case 4: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Specular Reflection Coefficient"), 0.0F, 1.0F); + } else if (mode == 1) { + ret = new Float(this.getSpecular()); + } else if (mode == 2) { + this.setSpecular((Float)value); + } + break; + case 5: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Opacity"), 0.0F, 1.0F); + } else if (mode == 1) { + ret = new Float(this.getOpacity()); + } else if (mode == 2) { + this.setOpacity((Float)value); + } + break; + case 6: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Smooth"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.getSmooth()); + } else if (mode == 2) { + this.setSmooth((Boolean)value); + } + break; + case 7: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Filter"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.getFilter()); + } else if (mode == 2) { + this.setFilter((Boolean)value); + } + break; + default: + ret = super.properties(index, offset + 8, mode, value); + } + + return ret; + } + + @Override + public String toString() { + return this.getName() + + "[" + + (this.textureName != null ? this.textureName.toString() : (this.textures == null ? null : this.textures.toString())) + + ", " + + this.getColor() + + ", Ambient " + + this.getAmbient() + + ", Diffuse " + + this.getDiffuse() + + ", Specular " + + this.getSpecular() + + ", Opacity " + + this.getOpacity() + + ", Smooth " + + this.getSmooth() + + ", Filter " + + this.getFilter() + + ", hRes " + + this.hRes + + ", vRes " + + this.vRes + + ", loResMode " + + false + + "]"; + } +} diff --git a/NET/worlds/scape/MaterialTexture.java b/NET/worlds/scape/MaterialTexture.java new file mode 100644 index 0000000..4fb5363 --- /dev/null +++ b/NET/worlds/scape/MaterialTexture.java @@ -0,0 +1,201 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.network.URL; +import java.awt.Color; + +class MaterialTexture extends SuperRoot implements NonPersister { + private URL fileName; + private StringTexture stexture; + private String text = ""; + private String font = Console.message("MaterialFont"); + private int size = 48; + private Color foregroundColor = Color.white; + private Color backgroundColor = Color.black; + + MaterialTexture(URL textureName) { + this.fileName = textureName; + } + + MaterialTexture(StringTexture texture) { + this.stexture = texture; + this.text = this.stexture.getText(); + this.font = this.stexture.getFont(); + this.size = this.stexture.getSize(); + this.foregroundColor = this.stexture.getForegroundColor(); + this.backgroundColor = this.stexture.getBackgroundColor(); + } + + private void setFile(URL name, boolean force) { + this.fileName = name; + if (this.stexture == null || force) { + this.stexture = null; + ((Material)this.getOwner()).loadTexture(name); + } + } + + private void makeString() { + Material owner = (Material)this.getOwner(); + this.stexture = new StringTexture(this.text, this.font, this.size, this.foregroundColor, this.backgroundColor); + owner.setTexture(this.stexture); + } + + private String getText() { + return this.text; + } + + private void setText(String text) { + this.text = text; + if (this.stexture != null) { + this.makeString(); + } + } + + private void setFont(String font) { + this.font = font; + if (this.stexture != null) { + this.makeString(); + } + } + + private void setSize(int size) { + if (size >= 1 && size <= 720) { + this.size = size; + if (this.stexture != null) { + this.makeString(); + } + } else { + Console.println(Console.message("Font-sizes")); + } + } + + private void setForegroundColor(Color color) { + this.foregroundColor = color; + if (this.stexture != null) { + this.makeString(); + } + } + + private void setBackgroundColor(Color color) { + this.backgroundColor = color; + if (this.stexture != null) { + this.makeString(); + } + } + + @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 = BooleanPropertyEditor.make( + new Property(this, index, "Texture Type (Text String)"), "Texture loaded from an image file.", "Texture created from a text string." + ); + } else if (mode == 1) { + ret = new Boolean(this.stexture != null); + } else if (mode == 2) { + boolean stringTexture = (Boolean)value; + if (stringTexture && this.stexture == null) { + this.makeString(); + } else if (!stringTexture && this.stexture != null) { + this.setFile(this.fileName, true); + } + } + break; + case 1: + if (mode == 0) { + ret = new Property(this, index, "File"); + if (this.stexture == null) { + ret = URLPropertyEditor.make((Property)ret, TextureDecoder.getAllExts()); + } + } else if (mode == 1) { + ret = this.fileName; + } else if (mode == 2) { + this.setFile((URL)value, false); + } + break; + case 2: + if (mode == 0) { + ret = new Property(this, index, "Text"); + if (this.stexture != null) { + ret = StringPropertyEditor.make((Property)ret); + } + } else if (mode == 1) { + ret = this.getText(); + } else if (mode == 2) { + this.setText((String)value); + } + break; + case 3: + if (mode == 0) { + ret = new Property(this, index, "Font"); + if (this.stexture != null) { + ret = StringPropertyEditor.make((Property)ret); + } + } else if (mode == 1) { + ret = this.font; + } else if (mode == 2) { + this.setFont((String)value); + } + + System.out.println("Setting font " + (String)value + " in Material.java"); + break; + case 4: + if (mode == 0) { + ret = new Property(this, index, "Size"); + if (this.stexture != null) { + ret = IntegerPropertyEditor.make((Property)ret); + } + } else if (mode == 1) { + ret = new Integer(this.size); + } else if (mode == 2) { + this.setSize((Integer)value); + } + break; + case 5: + if (mode == 0) { + ret = new Property(this, index, "Foreground Color"); + if (this.stexture != null) { + ret = ColorPropertyEditor.make((Property)ret); + } + } else if (mode == 1) { + ret = this.foregroundColor; + } else if (mode == 2) { + this.setForegroundColor((Color)value); + } + break; + case 6: + if (mode == 0) { + ret = new Property(this, index, "Background Color"); + if (this.stexture != null) { + ret = ColorPropertyEditor.make((Property)ret); + } + } else if (mode == 1) { + ret = this.backgroundColor; + } else if (mode == 2) { + this.setBackgroundColor((Color)value); + } + break; + default: + ret = super.properties(index, offset + 7, mode, value); + } + + return ret; + } + + @Override + public String toString() { + if (this.stexture != null) { + return "" + this.stexture; + } else { + Material owner = (Material)this.getOwner(); + URL name = null; + if (owner != null) { + name = owner.textureName; + } + + return name == null ? "File " : "File " + name; + } + } +} diff --git a/NET/worlds/scape/MaybeNullDialog.java b/NET/worlds/scape/MaybeNullDialog.java new file mode 100644 index 0000000..773bdcd --- /dev/null +++ b/NET/worlds/scape/MaybeNullDialog.java @@ -0,0 +1,24 @@ +package NET.worlds.scape; + +import NET.worlds.console.ConfirmDialog; +import NET.worlds.console.Console; + +class MaybeNullDialog extends ConfirmDialog { + private Property property; + private Object newOne; + private EditTile parent; + + MaybeNullDialog(EditTile parent, String title, String prompt, Property property, Object newOne) { + super(Console.getFrame(), parent, title, prompt); + this.property = property; + this.newOne = newOne; + this.parent = parent; + this.ready(); + } + + @Override + protected boolean setValue() { + this.parent.addUndoableSet(this.property, this.newOne); + return true; + } +} diff --git a/NET/worlds/scape/MaybeNullPropertyEditor.java b/NET/worlds/scape/MaybeNullPropertyEditor.java new file mode 100644 index 0000000..1753cb7 --- /dev/null +++ b/NET/worlds/scape/MaybeNullPropertyEditor.java @@ -0,0 +1,21 @@ +package NET.worlds.scape; + +import NET.worlds.console.PolledDialog; + +public class MaybeNullPropertyEditor extends PropEditor { + private Object newOne; + + private MaybeNullPropertyEditor(Property property, Object newOne) { + super(property); + this.newOne = newOne; + } + + @Override + public PolledDialog edit(EditTile parent, String title) { + return new MaybeNullDialog(parent, title, "Create a new instance?", this.property, this.newOne); + } + + public static Property make(Property property, Object newOne) { + return property.setEditor(new MaybeNullPropertyEditor(property, newOne)); + } +} diff --git a/NET/worlds/scape/MetaEnumeration.java b/NET/worlds/scape/MetaEnumeration.java new file mode 100644 index 0000000..1eafe57 --- /dev/null +++ b/NET/worlds/scape/MetaEnumeration.java @@ -0,0 +1,38 @@ +package NET.worlds.scape; + +import java.util.Enumeration; +import java.util.Vector; + +public class MetaEnumeration implements Enumeration { + private Vector v; + private int index; + + MetaEnumeration(Vector v) { + assert v.size() > 0; + + this.v = v; + this.index = 0; + this.advanceToNext(); + } + + @Override + public boolean hasMoreElements() { + return ((Enumeration)this.v.elementAt(this.index)).hasMoreElements(); + } + + @Override + public Object nextElement() { + Object e = ((Enumeration)this.v.elementAt(this.index)).nextElement(); + this.advanceToNext(); + return e; + } + + private void advanceToNext() { + while (!((Enumeration)this.v.elementAt(this.index)).hasMoreElements()) { + if (++this.index == this.v.size()) { + this.index--; + break; + } + } + } +} diff --git a/NET/worlds/scape/Mirror.java b/NET/worlds/scape/Mirror.java new file mode 100644 index 0000000..a410a18 --- /dev/null +++ b/NET/worlds/scape/Mirror.java @@ -0,0 +1,34 @@ +package NET.worlds.scape; + +public class Mirror extends Portal { + public Mirror(float w, float h) { + super(w, h); + this.connectTo(this); + this.flags |= 4; + } + + public Mirror(float llx, float lly, float llz, float urx, float ury, float urz) { + super(llx, lly, llz, urx, ury, urz); + this.connectTo(this); + this.flags |= 4; + } + + public Mirror(Point3Temp llc, Point3Temp urc) { + super(llc, urc); + this.connectTo(this); + this.flags |= 4; + } + + @Override + public BumpCalc getBumpCalc(BumpEventTemp b) { + return this.bumpCalc == null ? Rect.standardPlaneBumpCalc : this.bumpCalc; + } + + public Mirror() { + } + + @Override + public boolean handle(BumpEventTemp b) { + return true; + } +} diff --git a/NET/worlds/scape/MomentumBehavior.java b/NET/worlds/scape/MomentumBehavior.java new file mode 100644 index 0000000..f3c2304 --- /dev/null +++ b/NET/worlds/scape/MomentumBehavior.java @@ -0,0 +1,7 @@ +package NET.worlds.scape; + +import java.util.Enumeration; + +public interface MomentumBehavior { + void transferFrom(Enumeration var1); +} diff --git a/NET/worlds/scape/MontyDoor.java b/NET/worlds/scape/MontyDoor.java new file mode 100644 index 0000000..0c128ad --- /dev/null +++ b/NET/worlds/scape/MontyDoor.java @@ -0,0 +1,185 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.Main; +import NET.worlds.console.MainCallback; +import NET.worlds.network.URL; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.Enumeration; + +public class MontyDoor extends Portal implements MouseDownHandler, MainCallback { + boolean setsAvatar = false; + URL url; + String description = ""; + DialogAction action; + String viewName; + URL viewURL; + Persister lastTrigger; + private static Object classCookie = new Object(); + + public MontyDoor() { + this.flags |= 262144; + } + + @Override + public boolean handle(MouseDownEvent e) { + if ((e.key & 1) == 0) { + return false; + } else if (this.action == null && this.url != null) { + if (this.setsAvatar) { + SelectAvatarAction a = new SelectAvatarAction(); + a.url = this.viewURL; + a.description = this.description; + this.action = a; + } else { + SendURLAction a = new SendURLAction(); + a.destination = this.url; + a.description = this.description; + this.action = a; + } + + this.action.cancelOnly = true; + Main.register(this); + return true; + } else { + return true; + } + } + + @Override + public void mainCallback() { + if (this.action.cancelOnly) { + this.lastTrigger = this.action.trigger(null, this.lastTrigger); + if (this.lastTrigger != null) { + return; + } + + if (this.viewURL != null && this.viewName != null && this._farSideRoomName != null) { + Room r = this.getRoom(); + World w; + if (r != null && (w = r.getWorld()) != null) { + r = w.getRoom(this._farSideRoomName); + if (r == null) { + Main.unregister(this); + this.action = null; + Object[] arguments = new Object[]{new String(this.getName()), new String(this._farSideRoomName)}; + Console.println(MessageFormat.format(Console.message("MontyDoor"), arguments)); + return; + } + + Enumeration list = r.getDeepOwned(); + SetPropertyAction.propHelper(2, this.viewURL, "File", SuperRoot.nameSearch(list, this.viewName)); + } + } + + this.action.cancelOnly = false; + this.flags &= -262145; + this.reset(); + } + + this.lastTrigger = this.action.trigger(null, this.lastTrigger); + if (this.lastTrigger == null) { + Main.unregister(this); + this.action = null; + this.flags |= 262144; + this.reset(); + } + } + + @Override + public BumpCalc getBumpCalc(BumpEventTemp b) { + return standardPlaneBumpCalc; + } + + @Override + public boolean handle(BumpEventTemp b) { + return true; + } + + @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 = BooleanPropertyEditor.make(new Property(this, index, "Avatar type"), "SendURL", "SelectAvatar"); + } else if (mode == 1) { + ret = new Boolean(this.setsAvatar); + } else if (mode == 2) { + this.setsAvatar = (Boolean)value; + } + break; + case 1: + if (mode == 0) { + ret = URLPropertyEditor.make(new Property(this, index, "URL (used only for non-avatar)").allowSetNull(), null); + } else if (mode == 1) { + ret = this.url; + } else if (mode == 2) { + this.url = (URL)value; + } + break; + case 2: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Description")); + } else if (mode == 1) { + ret = this.description; + } else if (mode == 2) { + this.description = ((String)value).toString().trim(); + } + break; + case 3: + if (mode == 0) { + ret = URLPropertyEditor.make(new Property(this, index, "Display URL").allowSetNull(), null); + } else if (mode == 1) { + ret = this.viewURL; + } else if (mode == 2) { + this.viewURL = (URL)value; + } + break; + case 4: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Display Name")); + } else if (mode == 1) { + ret = this.viewName; + } else if (mode == 2) { + this.viewName = ((String)value).toString().trim(); + } + break; + default: + ret = super.properties(index, offset + 5, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + int f = this.flags; + this.flags |= 262144; + super.saveState(s); + this.flags = f; + s.saveBoolean(this.setsAvatar); + URL.save(s, this.url); + s.saveString(this.description); + URL.save(s, this.viewURL); + s.saveString(this.viewName); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this.setsAvatar = r.restoreBoolean(); + this.url = URL.restore(r); + this.description = r.restoreString(); + this.viewURL = URL.restore(r); + this.viewName = r.restoreString(); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/MoreInfoDialog.java b/NET/worlds/scape/MoreInfoDialog.java new file mode 100644 index 0000000..877faf6 --- /dev/null +++ b/NET/worlds/scape/MoreInfoDialog.java @@ -0,0 +1,54 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.DialogReceiver; +import NET.worlds.console.ImageButtons; +import NET.worlds.console.ImageButtonsCallback; +import NET.worlds.console.PolledDialog; +import NET.worlds.core.IniFile; +import java.awt.Component; +import java.awt.Rectangle; +import java.awt.Window; + +public class MoreInfoDialog extends PolledDialog implements ImageButtonsCallback { + private ImageButtons ib; + + public MoreInfoDialog(Window parent, DialogReceiver receiver) { + super(parent, receiver, Console.message("BrowseQ"), false); + this.setAlignment(1); + Rectangle[] rects = new Rectangle[2]; + int yesX = IniFile.override().getIniInt("moreinfoYesX", 48); + int yesY = IniFile.override().getIniInt("moreinfoYesY", 22); + int yesW = IniFile.override().getIniInt("moreinfoYesW", 60); + int yesH = IniFile.override().getIniInt("moreinfoYesH", 19); + rects[0] = new Rectangle(yesX, yesY, yesW, yesH); + int noX = IniFile.override().getIniInt("moreinfoNoX", 139); + int noY = IniFile.override().getIniInt("moreinfoNoY", 22); + int noW = IniFile.override().getIniInt("moreinfoNoW", 54); + int noH = IniFile.override().getIniInt("moreinfoNoH", 19); + rects[1] = new Rectangle(noX, noY, noW, noH); + String migif = IniFile.override().getIniString("moreInfoDlg", Console.message("moreinfo.gif")); + this.ib = new ImageButtons(migif, rects, this); + this.ready(); + } + + @Override + protected void build() { + this.add("Center", this.ib); + } + + @Override + public Object imageButtonsCallback(Component who, int which) { + this.done(which == 0); + return null; + } + + @Override + public boolean keyDown(java.awt.Event event, int key) { + if (key == 27) { + return this.done(false); + } else { + return key == 10 ? this.done(true) : super.keyDown(event, key); + } + } +} diff --git a/NET/worlds/scape/Motion.java b/NET/worlds/scape/Motion.java new file mode 100644 index 0000000..9283376 --- /dev/null +++ b/NET/worlds/scape/Motion.java @@ -0,0 +1,398 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.Date; + +class Motion extends TriggeredSwitchableBehavior implements FrameHandler, Persister, MouseDownHandler, BumpHandler { + long startMotionTime; + protected float cycleTime; + protected String frameList; + protected int cycles; + protected Transform motionTransform; + protected Point3 startPoint; + protected Point3 endPoint; + protected Point3 deltaPoint; + protected Point3 startScale; + protected Point3 endScale; + protected Point3 deltaScale; + protected Point3 startSpin; + protected Point3 endSpin; + protected Point3 currentSpin; + protected float startRotation; + protected float endRotation; + protected float currentRotation; + protected boolean motionTransformInitialized; + protected boolean variableInitialized; + protected boolean motionEnd = true; + + public Motion() { + this.cycleTime = 1000.0F; + this.trigger = new String("none"); + this.externalTriggerTag = new String(""); + this.cycles = 0; + this.motionTransformInitialized = false; + this.variableInitialized = false; + this.startPoint = new Point3(); + this.endPoint = new Point3(); + this.deltaPoint = new Point3(); + this.startScale = new Point3(); + this.endScale = new Point3(); + this.deltaScale = new Point3(); + this.startSpin = new Point3(); + this.endSpin = new Point3(); + this.currentSpin = new Point3(); + this.startMotion(); + } + + @Override + public void ExternalTrigger(Trigger trigger_source, int sequence_no, int event_no) { + this.trigger_source = trigger_source; + this.sequence_no = sequence_no; + this.event_no = event_no; + this.startMotion(); + } + + public boolean equivalent(Point3Temp a, Point3Temp b) { + return Math.round(a.x) == Math.round(b.x) && Math.round(a.y) == Math.round(b.y) && Math.round(a.z) == Math.round(b.z); + } + + public void startMotion() { + if (this.motionTransform != null + && this.equivalent(this.startPoint, this.motionTransform.getPosition()) + && Math.round(this.startScale.x) == Math.round(this.motionTransform.getTotalScale())) { + this.currentRotation = Math.round(this.motionTransform.getSpin(this.currentSpin)); + this.startRotation = Math.round(this.startRotation); + if ((this.startRotation == this.currentRotation || this.startRotation - 360.0F == this.currentRotation) + && this.equivalent(this.startSpin, this.currentSpin) + || (-this.startRotation == this.currentRotation || 360.0F - this.startRotation == this.currentRotation) + && this.equivalent(this.startSpin, this.currentSpin.negate())) { + Date timer = new Date(); + this.startMotionTime = timer.getTime(); + this.motionEnd = true; + } + } + } + + @Override + public boolean handle(FrameEvent e) { + if (!this.motionTransformInitialized) { + this.motionTransform = e.target; + this.motionTransformInitialized = true; + } + + if (!this.variableInitialized) { + this.startPoint.copy(this.motionTransform.getPosition()); + this.endPoint.copy(this.startPoint); + this.startScale.x = this.motionTransform.getTotalScale(); + this.startScale.y = this.motionTransform.getTotalScale(); + this.startScale.z = this.motionTransform.getTotalScale(); + this.endScale.copy(this.startScale); + this.startRotation = this.motionTransform.getSpin(this.startSpin); + this.endRotation = 0.0F; + this.variableInitialized = true; + } + + if (this.enabled) { + Date timer = new Date(); + long currentTime = timer.getTime(); + float frameLoc = (float)(-this.startMotionTime + currentTime) % this.cycleTime / this.cycleTime; + int cycleNo = (int)((float)(-this.startMotionTime + currentTime) / this.cycleTime); + if (cycleNo < this.cycles || this.cycles == 0 || !this.motionEnd) { + this.motionEnd = false; + if (cycleNo >= this.cycles && this.cycles != 0) { + this.motionEnd = true; + frameLoc = 1.0F; + if (this.trigger_source != null) { + this.trigger_source.registerFinishedTriggerTag(this.sequence_no, this.event_no); + } + } + + e.receiver.makeIdentity(); + e.receiver + .scale( + this.startScale.x + (this.endScale.x - this.startScale.x) * frameLoc, + this.startScale.x + (this.endScale.x - this.startScale.x) * frameLoc, + this.startScale.x + (this.endScale.x - this.startScale.x) * frameLoc + ); + e.receiver + .moveTo( + this.startPoint.x + (this.endPoint.x - this.startPoint.x) * frameLoc, + this.startPoint.y + (this.endPoint.y - this.startPoint.y) * frameLoc, + this.startPoint.z + (this.endPoint.z - this.startPoint.z) * frameLoc + ); + e.receiver.spin(this.startSpin, this.startRotation); + e.receiver.spin(this.endSpin, this.endRotation * frameLoc); + } + } + + return true; + } + + @Override + public boolean handle(MouseDownEvent e) { + if (this.enabled && this.trigger.equals("click")) { + this.startMotion(); + } + + return true; + } + + @Override + public boolean handle(BumpEventTemp e) { + if (this.enabled && this.trigger.equals("bump")) { + this.startMotion(); + } + + return true; + } + + public void startTransform() { + if (this.motionTransform != null) { + this.motionTransform.makeIdentity(); + this.motionTransform.scale(this.startScale.x, this.startScale.x, this.startScale.x); + this.motionTransform.moveTo(this.startPoint.x, this.startPoint.y, this.startPoint.z); + this.motionTransform.spin(this.startSpin, this.startRotation); + } else { + System.out.println("motionTransform is null!!!!"); + } + } + + public void endTransform() { + if (this.motionTransform != null) { + this.motionTransform.makeIdentity(); + this.motionTransform.scale(this.endScale.x, this.endScale.x, this.endScale.x); + this.motionTransform.moveTo(this.endPoint.x, this.endPoint.y, this.endPoint.z); + this.motionTransform.spin(this.startSpin, this.startRotation); + this.motionTransform.spin(this.endSpin, this.endRotation); + } else { + System.out.println("motionTransform is null!!!!"); + } + } + + @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 = new ClassProperty(this, index, "Motion"); + } + break; + case 1: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Cycle Time")); + } else if (mode == 1) { + ret = new Float(this.cycleTime); + } else if (mode == 2) { + this.cycleTime = (Float)value; + } + break; + case 2: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Cycles")); + } else if (mode == 1) { + ret = new Integer(this.cycles); + } else if (mode == 2) { + this.cycles = (Integer)value; + } + break; + case 3: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Trigger")); + } else if (mode == 1) { + ret = new String(this.trigger); + } else if (mode == 2) { + this.trigger = ((String)value).toString().trim(); + if (this.trigger.equals("external")) { + Trigger.TriggeredSwitchableBehaviorList[Trigger.TriggeredSwitchableBehaviorListCount] = this; + Trigger.TriggeredSwitchableBehaviorListCount++; + } + } + break; + case 4: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "External Trigger Tag")); + } else if (mode == 1) { + ret = new String(this.externalTriggerTag); + } else if (mode == 2) { + this.externalTriggerTag = ((String)value).toString().trim(); + } + break; + case 5: + if (mode == 0) { + ret = Point3PropertyEditor.make(new Property(this, index, "End Point")); + } else if (mode == 1) { + ret = new Point3(this.endPoint); + this.endTransform(); + } else if (mode == 2) { + this.endPoint.copy((Point3)value); + this.endTransform(); + } + break; + case 6: + if (mode == 0) { + ret = Point3PropertyEditor.make(new Property(this, index, "Start Point")); + } else if (mode == 1) { + ret = new Point3(this.startPoint); + this.startTransform(); + } else if (mode == 2) { + this.startPoint.copy((Point3)value); + this.startTransform(); + } + break; + case 7: + if (mode == 0) { + ret = Point3PropertyEditor.make(new Property(this, index, "End Scale")); + } else if (mode == 1) { + ret = new Point3(this.endScale); + this.endTransform(); + } else if (mode == 2) { + this.endScale.copy((Point3)value); + this.endTransform(); + } + break; + case 8: + if (mode == 0) { + ret = Point3PropertyEditor.make(new Property(this, index, "Start Scale")); + } else if (mode == 1) { + ret = new Point3(this.startScale); + this.startTransform(); + } else if (mode == 2) { + this.startScale.copy((Point3)value); + this.startTransform(); + } + break; + case 9: + if (mode == 0) { + ret = Point3PropertyEditor.make(new Property(this, index, "End Spin (Relative)")); + } else if (mode == 1) { + ret = new Point3(this.endSpin); + this.endTransform(); + } else if (mode == 2) { + this.endSpin.copy((Point3)value); + this.endTransform(); + } + break; + case 10: + if (mode == 0) { + ret = Point3PropertyEditor.make(new Property(this, index, "Start Spin")); + } else if (mode == 1) { + ret = new Point3(this.startSpin); + this.startTransform(); + } else if (mode == 2) { + this.startSpin.copy((Point3)value); + this.startTransform(); + } + break; + case 11: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "End Rotation (Relative)")); + } else if (mode == 1) { + ret = new Float(this.endRotation); + this.endTransform(); + } else if (mode == 2) { + this.endRotation = (Float)value; + this.endTransform(); + } + break; + case 12: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Start Rotation")); + } else if (mode == 1) { + ret = new Float(this.startRotation); + this.startTransform(); + } else if (mode == 2) { + this.startRotation = (Float)value; + this.startTransform(); + } + break; + default: + ret = super.properties(index, offset + 13, mode, value); + } + + if (mode == 2 && this.trigger.equals("none")) { + this.startMotion(); + } + + return ret; + } + + @Override + public String toString() { + return "Motion: cycleTime " + + this.cycleTime + + ", cycles " + + this.cycles + + ", enabled " + + this.enabled + + ", trigger " + + this.trigger + + ", externalTriggerTag " + + this.externalTriggerTag; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveFloat(this.cycleTime); + s.saveInt(this.cycles); + s.saveString(this.trigger); + s.saveString(this.externalTriggerTag); + this.endPoint.saveState(s); + this.startPoint.saveState(s); + this.endScale.saveState(s); + this.startScale.saveState(s); + this.endSpin.saveState(s); + this.startSpin.saveState(s); + s.saveFloat(this.endRotation); + s.saveFloat(this.startRotation); + } + + @Override + public void restoreState(Restorer r) throws IOException { + this.cycleTime = r.restoreFloat(); + this.cycles = r.restoreInt(); + this.trigger = r.restoreString(); + if (this.trigger.equals("external")) { + Trigger.TriggeredSwitchableBehaviorList[Trigger.TriggeredSwitchableBehaviorListCount] = this; + Trigger.TriggeredSwitchableBehaviorListCount++; + } + + this.externalTriggerTag = r.restoreString(); + + try { + this.endPoint.restoreState(r); + this.startPoint.restoreState(r); + this.endScale.restoreState(r); + this.startScale.restoreState(r); + this.endSpin.restoreState(r); + this.startSpin.restoreState(r); + } catch (Exception var3) { + } + + this.endRotation = r.restoreFloat(); + this.startRotation = r.restoreFloat(); + this.variableInitialized = true; + if (!this.trigger.equals("none")) { + this.startMotionTime = (int)(-(this.cycles * this.cycleTime)); + } else { + this.startMotion(); + } + } + + @Override + public void postRestore(int version) { + String name = this.getName(); + String arg1 = name == null ? "<null>" : name; + SuperRoot owner = this.getOwner(); + String oname = ""; + if (owner != null) { + oname = owner.getName(); + } + + String arg2 = oname == null ? "<null>" : oname; + Object[] arguments = new Object[]{new String(arg1), new String(arg2)}; + Console.println(MessageFormat.format(Console.message("Motion-obs"), arguments)); + } +} diff --git a/NET/worlds/scape/MouseButtonEvent.java b/NET/worlds/scape/MouseButtonEvent.java new file mode 100644 index 0000000..2f62ad4 --- /dev/null +++ b/NET/worlds/scape/MouseButtonEvent.java @@ -0,0 +1,15 @@ +package NET.worlds.scape; + +public class MouseButtonEvent extends MouseEvent { + public char key; + + public MouseButtonEvent(int time, WObject target, char key, int x, int y) { + super(time, target, x, y); + this.key = key; + } + + @Override + public boolean deliver(Object o) { + return o instanceof MouseButtonHandler && ((MouseButtonHandler)o).handle(this) ? true : super.deliver(o); + } +} diff --git a/NET/worlds/scape/MouseButtonHandler.java b/NET/worlds/scape/MouseButtonHandler.java new file mode 100644 index 0000000..7f2a8b0 --- /dev/null +++ b/NET/worlds/scape/MouseButtonHandler.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface MouseButtonHandler { + boolean handle(MouseButtonEvent var1); +} diff --git a/NET/worlds/scape/MouseDeltaEvent.java b/NET/worlds/scape/MouseDeltaEvent.java new file mode 100644 index 0000000..b530b3c --- /dev/null +++ b/NET/worlds/scape/MouseDeltaEvent.java @@ -0,0 +1,17 @@ +package NET.worlds.scape; + +public class MouseDeltaEvent extends MouseEvent { + public int dx; + public int dy; + + public MouseDeltaEvent(int time, WObject target, int dx, int dy) { + super(time, target, 0, 0); + this.dx = dx; + this.dy = dy; + } + + @Override + public boolean deliver(Object o) { + return o instanceof MouseDeltaHandler && ((MouseDeltaHandler)o).handle(this) ? true : super.deliver(o); + } +} diff --git a/NET/worlds/scape/MouseDeltaHandler.java b/NET/worlds/scape/MouseDeltaHandler.java new file mode 100644 index 0000000..0da21bf --- /dev/null +++ b/NET/worlds/scape/MouseDeltaHandler.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface MouseDeltaHandler { + boolean handle(MouseDeltaEvent var1); +} diff --git a/NET/worlds/scape/MouseDownEvent.java b/NET/worlds/scape/MouseDownEvent.java new file mode 100644 index 0000000..71ea54f --- /dev/null +++ b/NET/worlds/scape/MouseDownEvent.java @@ -0,0 +1,27 @@ +package NET.worlds.scape; + +import NET.worlds.console.BBWObjClickedCommand; +import NET.worlds.console.BlackBox; + +public class MouseDownEvent extends MouseButtonEvent { + public MouseDownEvent(int time, WObject target, char key, int x, int y) { + super(time, target, key, x, y); + } + + @Override + public boolean deliver(Object o) { + if (o instanceof MouseDownHandler) { + BlackBox.getInstance().submitEvent(new BBWObjClickedCommand(((SuperRoot)o).getName(), this.key, this.x, this.y)); + if (((MouseDownHandler)o).handle(this)) { + return true; + } + } + + return super.deliver(o); + } + + @Override + public String toString() { + return "MouseDown" + super.toString(); + } +} diff --git a/NET/worlds/scape/MouseDownHandler.java b/NET/worlds/scape/MouseDownHandler.java new file mode 100644 index 0000000..aa1141e --- /dev/null +++ b/NET/worlds/scape/MouseDownHandler.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface MouseDownHandler { + boolean handle(MouseDownEvent var1); +} diff --git a/NET/worlds/scape/MouseDragEvent.java b/NET/worlds/scape/MouseDragEvent.java new file mode 100644 index 0000000..2294bc7 --- /dev/null +++ b/NET/worlds/scape/MouseDragEvent.java @@ -0,0 +1,12 @@ +package NET.worlds.scape; + +public class MouseDragEvent extends MousePositionEvent { + public MouseDragEvent(int time, WObject target, int x, int y) { + super(time, target, x, y); + } + + @Override + public boolean deliver(Object o) { + return o instanceof MouseDragHandler && ((MouseDragHandler)o).handle(this) ? true : super.deliver(o); + } +} diff --git a/NET/worlds/scape/MouseDragHandler.java b/NET/worlds/scape/MouseDragHandler.java new file mode 100644 index 0000000..28b7105 --- /dev/null +++ b/NET/worlds/scape/MouseDragHandler.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface MouseDragHandler { + boolean handle(MouseDragEvent var1); +} diff --git a/NET/worlds/scape/MouseEnterEvent.java b/NET/worlds/scape/MouseEnterEvent.java new file mode 100644 index 0000000..4fdf3d6 --- /dev/null +++ b/NET/worlds/scape/MouseEnterEvent.java @@ -0,0 +1,12 @@ +package NET.worlds.scape; + +public class MouseEnterEvent extends MousePositionEvent { + public MouseEnterEvent(int time, WObject target, int x, int y) { + super(time, target, x, y); + } + + @Override + public boolean deliver(Object o) { + return o instanceof MouseEnterHandler && ((MouseEnterHandler)o).handle(this) ? true : super.deliver(o); + } +} diff --git a/NET/worlds/scape/MouseEnterHandler.java b/NET/worlds/scape/MouseEnterHandler.java new file mode 100644 index 0000000..fa83b3a --- /dev/null +++ b/NET/worlds/scape/MouseEnterHandler.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface MouseEnterHandler { + boolean handle(MouseEnterEvent var1); +} diff --git a/NET/worlds/scape/MouseEvent.java b/NET/worlds/scape/MouseEvent.java new file mode 100644 index 0000000..1e73583 --- /dev/null +++ b/NET/worlds/scape/MouseEvent.java @@ -0,0 +1,17 @@ +package NET.worlds.scape; + +public class MouseEvent extends UserEvent { + public int x; + public int y; + + public MouseEvent(int time, WObject target, int x, int y) { + super(time, null, target); + this.x = x; + this.y = y; + } + + @Override + public boolean deliver(Object o) { + return o instanceof MouseHandler && ((MouseHandler)o).handle(this) ? true : super.deliver(o); + } +} diff --git a/NET/worlds/scape/MouseExitEvent.java b/NET/worlds/scape/MouseExitEvent.java new file mode 100644 index 0000000..7a19347 --- /dev/null +++ b/NET/worlds/scape/MouseExitEvent.java @@ -0,0 +1,12 @@ +package NET.worlds.scape; + +public class MouseExitEvent extends MousePositionEvent { + public MouseExitEvent(int time, WObject target, int x, int y) { + super(time, target, x, y); + } + + @Override + public boolean deliver(Object o) { + return o instanceof MouseExitHandler && ((MouseExitHandler)o).handle(this) ? true : super.deliver(o); + } +} diff --git a/NET/worlds/scape/MouseExitHandler.java b/NET/worlds/scape/MouseExitHandler.java new file mode 100644 index 0000000..d6c3462 --- /dev/null +++ b/NET/worlds/scape/MouseExitHandler.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface MouseExitHandler { + boolean handle(MouseExitEvent var1); +} diff --git a/NET/worlds/scape/MouseHandler.java b/NET/worlds/scape/MouseHandler.java new file mode 100644 index 0000000..dbbdc5b --- /dev/null +++ b/NET/worlds/scape/MouseHandler.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface MouseHandler { + boolean handle(MouseEvent var1); +} diff --git a/NET/worlds/scape/MouseMoveEvent.java b/NET/worlds/scape/MouseMoveEvent.java new file mode 100644 index 0000000..3a9a11b --- /dev/null +++ b/NET/worlds/scape/MouseMoveEvent.java @@ -0,0 +1,12 @@ +package NET.worlds.scape; + +public class MouseMoveEvent extends MousePositionEvent { + public MouseMoveEvent(int time, WObject target, int x, int y) { + super(time, target, x, y); + } + + @Override + public boolean deliver(Object o) { + return o instanceof MouseMoveHandler && ((MouseMoveHandler)o).handle(this) ? true : super.deliver(o); + } +} diff --git a/NET/worlds/scape/MouseMoveHandler.java b/NET/worlds/scape/MouseMoveHandler.java new file mode 100644 index 0000000..e421ae9 --- /dev/null +++ b/NET/worlds/scape/MouseMoveHandler.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface MouseMoveHandler { + boolean handle(MouseMoveEvent var1); +} diff --git a/NET/worlds/scape/MousePositionEvent.java b/NET/worlds/scape/MousePositionEvent.java new file mode 100644 index 0000000..5223ec1 --- /dev/null +++ b/NET/worlds/scape/MousePositionEvent.java @@ -0,0 +1,12 @@ +package NET.worlds.scape; + +public class MousePositionEvent extends MouseEvent { + public MousePositionEvent(int time, WObject target, int x, int y) { + super(time, target, x, y); + } + + @Override + public boolean deliver(Object o) { + return o instanceof MousePositionHandler && ((MousePositionHandler)o).handle(this) ? true : super.deliver(o); + } +} diff --git a/NET/worlds/scape/MousePositionHandler.java b/NET/worlds/scape/MousePositionHandler.java new file mode 100644 index 0000000..9a6d6ec --- /dev/null +++ b/NET/worlds/scape/MousePositionHandler.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface MousePositionHandler { + boolean handle(MousePositionEvent var1); +} diff --git a/NET/worlds/scape/MouseUpEvent.java b/NET/worlds/scape/MouseUpEvent.java new file mode 100644 index 0000000..5c70713 --- /dev/null +++ b/NET/worlds/scape/MouseUpEvent.java @@ -0,0 +1,17 @@ +package NET.worlds.scape; + +public class MouseUpEvent extends MouseButtonEvent { + public MouseUpEvent(int time, WObject target, char key, int x, int y) { + super(time, target, key, x, y); + } + + @Override + public boolean deliver(Object o) { + return o instanceof MouseUpHandler && ((MouseUpHandler)o).handle(this) ? true : super.deliver(o); + } + + @Override + public String toString() { + return "MouseUp" + super.toString(); + } +} diff --git a/NET/worlds/scape/MouseUpHandler.java b/NET/worlds/scape/MouseUpHandler.java new file mode 100644 index 0000000..00457ae --- /dev/null +++ b/NET/worlds/scape/MouseUpHandler.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface MouseUpHandler { + boolean handle(MouseUpEvent var1); +} diff --git a/NET/worlds/scape/MoveAction.java b/NET/worlds/scape/MoveAction.java new file mode 100644 index 0000000..3ba4be7 --- /dev/null +++ b/NET/worlds/scape/MoveAction.java @@ -0,0 +1,444 @@ +package NET.worlds.scape; + +import NET.worlds.core.Std; +import java.io.IOException; +import java.util.Enumeration; + +public class MoveAction extends Action { + int startTime; + boolean killOthers = true; + boolean killed = false; + public int cycleTime = 1000; + public int cycles = 1; + public boolean loopInfinite = false; + public Point3 startPoint = new Point3(); + public Point3 startScale = new Point3(1.0F, 1.0F, 1.0F); + public Point3 startSpin = new Point3(0.0F, 0.0F, -1.0F); + public float startRotation; + public Point3 extentPoint = new Point3(); + public Point3 extentScale = new Point3(1.0F, 1.0F, 1.0F); + public Point3 extentSpin = new Point3(0.0F, 0.0F, -1.0F); + public float extentRotation; + protected Persister activeID; + private static Object classCookie = new Object(); + + @Override + public void noteAddingTo(SuperRoot owner) { + if (this.startPoint.x == 0.0F + && this.startPoint.y == 0.0F + && this.startPoint.z == 0.0F + && this.startScale.x == 1.0F + && this.startScale.y == 1.0F + && this.startScale.z == 1.0F + && this.startSpin.x == 0.0F + && this.startSpin.y == 0.0F + && this.startSpin.z == -1.0F + && this.startRotation == 0.0F) { + this.updateStored(true); + } + } + + public void updateStored(boolean start) { + Object owner = this.getOwner(); + if (owner != null && owner instanceof WObject) { + WObject o = (WObject)owner; + if (!start) { + this.extentPoint.copy(o.getPosition()); + this.extentScale.copy(o.getScale()); + Point3Temp newSpin = Point3Temp.make(); + this.endToExtent(o.getSpin(newSpin), newSpin); + } else { + this.startPoint.copy(o.getPosition()); + this.startScale.copy(o.getScale()); + this.startRotation = o.getSpin(this.startSpin); + } + } + } + + public void endToExtent(float rot, Point3Temp spinAxis) { + this.extentPoint.minus(this.startPoint); + this.extentScale.dividedBy(this.startScale); + Transform t = Transform.make(); + t.spin(spinAxis, rot); + t.spin(this.startSpin, -this.startRotation); + rot = t.getSpin(spinAxis); + t.recycle(); + if (this.equivalentSpinAxises(spinAxis, this.extentSpin)) { + int wholeTurns = Math.round((this.extentRotation - rot) / 360.0F); + this.extentRotation = rot + wholeTurns * 360; + } else if (this.equivalentSpinAxises(spinAxis, this.extentSpin.negate())) { + this.extentSpin.negate(); + rot = -rot; + int wholeTurns = Math.round((this.extentRotation - rot) / 360.0F); + this.extentRotation = rot + wholeTurns * 360; + } else { + this.extentSpin.copy(spinAxis); + this.extentRotation = rot; + } + } + + private boolean equivalentSpinAxises(Point3Temp a, Point3Temp b) { + return Math.abs(a.x - b.x) + Math.abs(a.y - b.y) + Math.abs(a.z - b.z) < 0.001F; + } + + public void updateOwner(boolean start) { + Object owner = this.getOwner(); + if (owner != null && owner instanceof WObject) { + WObject o = (WObject)owner; + o.makeIdentity(); + if (!start) { + o.spin(this.extentSpin, this.extentRotation); + o.moveBy(this.extentPoint); + o.scale(this.extentScale); + } + + o.scale(this.startScale); + o.spin(this.startSpin, this.startRotation); + o.moveBy(this.startPoint); + } + } + + public void kill() { + this.killed = true; + } + + public boolean isRunning() { + return this.activeID != null; + } + + @Override + public Persister trigger(Event e, Persister seqID) { + Object owner = this.getOwner(); + if (owner != null && owner instanceof WObject) { + WObject o = (WObject)owner; + if (this.killed) { + this.killed = false; + this.activeID = null; + return null; + } else { + if (seqID == null) { + if (this.activeID != null) { + return this.activeID; + } + + if (this.killOthers) { + Enumeration acts = o.getActions(); + + while (acts.hasMoreElements()) { + Action a = (Action)acts.nextElement(); + if (a != this && a instanceof MoveAction) { + MoveAction ma = (MoveAction)a; + if (ma.isRunning()) { + ma.kill(); + } + } + } + } + + this.startTime = Std.getRealTime(); + this.activeID = new SuperRoot(); + seqID = this.activeID; + } + + if (seqID != this.activeID) { + return null; + } else { + int currentTime = Std.getRealTime(); + int cycleNo = (currentTime - this.startTime) / this.cycleTime; + float frameLoc = 1.0F; + if (cycleNo >= this.cycles && !this.loopInfinite) { + this.activeID = null; + } else { + frameLoc = (float)((currentTime - this.startTime) % this.cycleTime) / this.cycleTime; + } + + boolean var10000 = o instanceof Camera; + if (o instanceof PosableDrone) { + float yaw = -(this.startRotation + this.extentRotation * frameLoc); + Point3Temp dest = Point3Temp.make(this.extentPoint).times(frameLoc).plus(this.startPoint); + o.makeIdentity().moveTo(dest).yaw(yaw); + } else { + o.makeIdentity(); + o.spin(this.extentSpin, this.extentRotation * frameLoc); + o.spin(this.startSpin, this.startRotation); + Point3Temp p = Point3Temp.make( + (float)Math.pow(this.extentScale.x, frameLoc), + (float)Math.pow(this.extentScale.y, frameLoc), + (float)Math.pow(this.extentScale.z, frameLoc) + ); + o.scale(p.times(this.startScale)); + o.moveTo(Point3Temp.make(this.extentPoint).times(frameLoc).plus(this.startPoint)); + } + + return this.activeID; + } + } + } else { + return null; + } + } + + @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 = FloatPropertyEditor.make(new Property(this, index, "Cycle Time (in seconds)")); + } else if (mode == 1) { + ret = new Float(this.cycleTime / 1000.0F); + } else if (mode == 2) { + this.cycleTime = (int)(1000.0F * (Float)value); + } + break; + case 1: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Cycles")); + } else if (mode == 1) { + ret = new Integer(this.cycles); + } else if (mode == 2) { + this.cycles = (Integer)value; + } + break; + case 2: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Copy Start/End 1/2:Action->Owner 3/4:Owner->Action")); + } else if (mode == 1) { + ret = new Integer(0); + } else if (mode == 2) { + switch ((Integer)value) { + case 1: + this.updateOwner(true); + return ret; + case 2: + this.updateOwner(false); + return ret; + case 3: + this.updateStored(true); + return ret; + case 4: + this.updateStored(false); + } + } + break; + case 3: + if (mode == 0) { + ret = Point3PropertyEditor.make(new Property(this, index, "Translation Extent")); + } else if (mode == 1) { + ret = new Point3(this.extentPoint); + } else if (mode == 2) { + this.extentPoint.copy((Point3)value); + } + break; + case 4: + if (mode == 0) { + ret = Point3PropertyEditor.make(new Property(this, index, "Scale Extent")); + } else if (mode == 1) { + ret = new Point3(this.extentScale); + } else if (mode == 2) { + this.extentScale.copy((Point3)value); + } + break; + case 5: + if (mode == 0) { + ret = Point3PropertyEditor.make(new Property(this, index, "Spin Axis For Extent")); + } else if (mode == 1) { + Point3 p = new Point3(this.extentSpin); + p.x = Math.round(p.x * 10000.0F) / 10000.0F; + p.y = Math.round(p.y * 10000.0F) / 10000.0F; + p.z = Math.round(p.z * 10000.0F) / 10000.0F; + ret = p; + } else if (mode == 2) { + this.extentSpin.copy((Point3)value); + } + break; + case 6: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Extent Rotation Amount")); + } else if (mode == 1) { + ret = new Float(this.extentRotation); + } else if (mode == 2) { + this.extentRotation = (Float)value; + } + break; + case 7: + if (mode == 0) { + ret = Point3PropertyEditor.make(new Property(this, index, "Start Point")); + } else if (mode == 1) { + ret = new Point3(this.startPoint); + } else if (mode == 2) { + this.startPoint.copy((Point3)value); + } + break; + case 8: + if (mode == 0) { + ret = Point3PropertyEditor.make(new Property(this, index, "Start Scale")); + } else if (mode == 1) { + ret = new Point3(this.startScale); + } else if (mode == 2) { + this.startScale.copy((Point3)value); + } + break; + case 9: + if (mode == 0) { + ret = Point3PropertyEditor.make(new Property(this, index, "Start Spin")); + } else if (mode == 1) { + ret = new Point3(this.startSpin); + } else if (mode == 2) { + this.startSpin.copy((Point3)value); + } + break; + case 10: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Start Rotation")); + } else if (mode == 1) { + ret = new Float(this.startRotation); + } else if (mode == 2) { + this.startRotation = (Float)value; + } + break; + case 11: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Kill Other Move Actions"), "Let other moves finish", "Kill other move actions"); + } else if (mode == 1) { + ret = new Boolean(this.killOthers); + } else if (mode == 2) { + this.killOthers = (Boolean)value; + } + break; + case 12: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Loop Infinite"), "False", "True"); + } else if (mode == 1) { + ret = new Boolean(this.loopInfinite); + } else if (mode == 2) { + this.loopInfinite = (Boolean)value; + } + break; + default: + ret = super.properties(index, offset + 13, mode, value); + } + + return ret; + } + + @Override + public String toString() { + String retVal = super.toString() + "[cycleTime " + this.cycleTime / 1000.0F + ", cycles " + this.cycles + ","; + if (!this.loopInfinite) { + retVal = retVal + " not "; + } + + return retVal + " Infinite ]"; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(6, classCookie); + super.saveState(s); + s.saveBoolean(this.loopInfinite); + s.saveInt(this.cycleTime); + s.saveInt(this.cycles); + s.save(this.extentPoint); + s.save(this.startPoint); + s.save(this.extentScale); + s.save(this.startScale); + s.save(this.extentSpin); + s.save(this.startSpin); + s.saveFloat(this.extentRotation); + s.saveFloat(this.startRotation); + s.saveBoolean(this.killOthers); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + this.restoreStateMoveActionHelper(r, classCookie); + } + + public void restoreStateMoveActionHelper(Restorer r, Object cookie) throws IOException, TooNewException { + switch (r.restoreVersion(cookie)) { + case 1: + super.restoreState(r); + case 0: + r.setOldFlag(); + this.cycleTime = (int)r.restoreFloat(); + this.cycles = r.restoreInt(); + this.loopInfinite = this.cycles == 0; + this.extentPoint = (Point3)r.restore(); + this.startPoint = (Point3)r.restore(); + this.extentScale = (Point3)r.restore(); + this.startScale = (Point3)r.restore(); + this.extentSpin = (Point3)r.restore(); + this.startSpin = (Point3)r.restore(); + this.extentRotation = r.restoreFloat(); + this.startRotation = r.restoreFloat(); + this.extentPoint.minus(this.startPoint); + this.extentScale.dividedBy(this.startScale); + break; + case 2: + r.setOldFlag(); + super.restoreState(r); + this.cycleTime = r.restoreInt(); + this.cycles = r.restoreInt(); + this.loopInfinite = this.cycles == 0; + this.extentPoint = (Point3)r.restore(); + this.startPoint = (Point3)r.restore(); + this.extentScale = (Point3)r.restore(); + this.startScale = (Point3)r.restore(); + this.extentSpin = (Point3)r.restore(); + this.startSpin = (Point3)r.restore(); + this.extentRotation = r.restoreFloat(); + this.startRotation = r.restoreFloat(); + r.restoreBoolean(); + break; + case 3: + case 4: + r.setOldFlag(); + super.restoreState(r); + this.cycleTime = r.restoreInt(); + this.cycles = r.restoreInt(); + this.loopInfinite = this.cycles == 0; + this.extentPoint = (Point3)r.restore(); + this.startPoint = (Point3)r.restore(); + this.extentScale = (Point3)r.restore(); + this.startScale = (Point3)r.restore(); + this.extentSpin = (Point3)r.restore(); + this.startSpin = (Point3)r.restore(); + this.extentRotation = r.restoreFloat(); + this.startRotation = r.restoreFloat(); + break; + case 5: + super.restoreState(r); + this.cycleTime = r.restoreInt(); + this.cycles = r.restoreInt(); + this.loopInfinite = this.cycles == 0; + this.extentPoint = (Point3)r.restore(); + this.startPoint = (Point3)r.restore(); + this.extentScale = (Point3)r.restore(); + this.startScale = (Point3)r.restore(); + this.extentSpin = (Point3)r.restore(); + this.startSpin = (Point3)r.restore(); + this.extentRotation = r.restoreFloat(); + this.startRotation = r.restoreFloat(); + this.killOthers = r.restoreBoolean(); + break; + case 6: + super.restoreState(r); + this.loopInfinite = r.restoreBoolean(); + this.cycleTime = r.restoreInt(); + this.cycles = r.restoreInt(); + this.extentPoint = (Point3)r.restore(); + this.startPoint = (Point3)r.restore(); + this.extentScale = (Point3)r.restore(); + this.startScale = (Point3)r.restore(); + this.extentSpin = (Point3)r.restore(); + this.startSpin = (Point3)r.restore(); + this.extentRotation = r.restoreFloat(); + this.startRotation = r.restoreFloat(); + this.killOthers = r.restoreBoolean(); + break; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/MoveCameraAction.java b/NET/worlds/scape/MoveCameraAction.java new file mode 100644 index 0000000..d772588 --- /dev/null +++ b/NET/worlds/scape/MoveCameraAction.java @@ -0,0 +1,85 @@ +package NET.worlds.scape; + +import NET.worlds.core.Std; +import java.util.Enumeration; + +public class MoveCameraAction extends MoveAction { + private static Object classCookie = new Object(); + + @Override + public Persister trigger(Event e, Persister seqID) { + Pilot pl = Pilot.getActive(); + if (!(pl instanceof HoloPilot)) { + return null; + } else { + HoloPilot holo = (HoloPilot)pl; + holo.releaseCamera(); + Object owner = holo.getCamera(); + if (owner != null && owner instanceof WObject) { + WObject o = (WObject)owner; + if (this.killed) { + this.killed = false; + this.activeID = null; + holo.reclaimCamera(); + return null; + } else { + if (seqID == null) { + if (this.activeID != null) { + return this.activeID; + } + + if (this.killOthers) { + Enumeration acts = o.getActions(); + + while (acts.hasMoreElements()) { + Action a = (Action)acts.nextElement(); + if (a != this && a instanceof MoveAction) { + MoveAction ma = (MoveAction)a; + if (ma.isRunning()) { + ma.kill(); + } + } + } + } + + this.startTime = Std.getRealTime(); + this.activeID = new SuperRoot(); + seqID = this.activeID; + } + + if (seqID != this.activeID) { + return null; + } else { + int currentTime = Std.getRealTime(); + int cycleNo = (currentTime - this.startTime) / this.cycleTime; + float frameLoc = 1.0F; + if (cycleNo >= this.cycles && !this.loopInfinite) { + System.out.println("Killing MoveCameraAction. loopInfinite = " + this.loopInfinite); + this.activeID = null; + } else { + frameLoc = (float)((currentTime - this.startTime) % this.cycleTime) / this.cycleTime; + } + + o.makeIdentity(); + o.spin(this.extentSpin, this.extentRotation * frameLoc); + o.spin(this.startSpin, this.startRotation); + Point3Temp p = Point3Temp.make( + (float)Math.pow(this.extentScale.x, frameLoc), + (float)Math.pow(this.extentScale.y, frameLoc), + (float)Math.pow(this.extentScale.z, frameLoc) + ); + o.scale(p.times(this.startScale)); + o.moveTo(Point3Temp.make(this.extentPoint).times(frameLoc).plus(this.startPoint)); + if (this.activeID == null) { + holo.reclaimCamera(); + } + + return this.activeID; + } + } + } else { + return null; + } + } + } +} diff --git a/NET/worlds/scape/MultiManifestAction.java b/NET/worlds/scape/MultiManifestAction.java new file mode 100644 index 0000000..4852d36 --- /dev/null +++ b/NET/worlds/scape/MultiManifestAction.java @@ -0,0 +1,112 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.network.URL; +import java.io.File; +import java.io.IOException; + +public class MultiManifestAction extends Action implements LoadedURLSelf { + private String _directory; + private static Object classCookie = new Object(); + private String[] _files; + private File _dir; + private int _curFile; + private String _file; + + @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 = StringPropertyEditor.make(new Property(this, index, "Directory")); + } else if (mode == 1) { + if (this._directory == null) { + this._directory = new String(); + } + + ret = new String(this._directory); + } else if (mode == 2) { + this._directory = ((String)value).trim(); + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + s.saveString(this._directory); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this._directory = r.restoreString(); + return; + default: + throw new TooNewException(); + } + } + + @Override + public Persister trigger(Event e, Persister seqId) { + if (seqId == null) { + System.out.println("MMAState:starting"); + this._dir = new File(this._directory); + this._files = this._dir.list(new ExtensionFilter(".world")); + this._curFile = 0; + this.startFile(); + } + + return this._curFile >= this._files.length ? null : this; + } + + public void startFile() { + if (this._curFile >= this._files.length) { + System.out.println("MMAState:Done"); + } else { + this._file = new File(this._dir, this._files[this._curFile]).getAbsolutePath(); + System.out.println("MMAState:Loading: " + this._file); + World.load(URL.make(this._file), this); + } + } + + @Override + public void loadedURLSelf(URLSelf o, URL url, String err) { + if (err == null && o instanceof World) { + World w = (World)o; + String mftname = this._file.substring(0, this._file.lastIndexOf(".world")) + ".mft"; + System.out.println("MMAState:Manifesting: " + mftname); + + try { + Manifest mft = new Manifest(mftname); + mft.saveProps(w); + mft.done(); + } catch (Exception var7) { + var7.printStackTrace(System.out); + } + + if (w != Pilot.getActive().getWorld()) { + w.discard(); + } + } else { + if (err == null) { + err = Console.message("No-contain-world"); + o.decRef(); + } + + Console.println(Console.message("Cant-load-remote") + url + "' "); + } + + this._curFile++; + this.startFile(); + } +} diff --git a/NET/worlds/scape/MultiMotion.java b/NET/worlds/scape/MultiMotion.java new file mode 100644 index 0000000..7bede30 --- /dev/null +++ b/NET/worlds/scape/MultiMotion.java @@ -0,0 +1,531 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.Date; + +class MultiMotion extends TriggeredSwitchableBehavior implements FrameHandler, Persister, MouseDownHandler, BumpHandler { + protected int motionNumber = 0; + protected int motionNumberCount = 0; + protected int motionNumberMax = 100; + long startMultiMotionTime; + long totalMultiMotionTime = 0L; + protected String cycleTime; + protected float[] cycleTimeArray; + protected int cycles; + protected Transform MultiMotionTransform; + protected String startPoint; + protected String endPoint; + protected String deltaPoint; + protected String startScale; + protected String endScale; + protected String deltaScale; + protected String startSpin; + protected String endSpin; + protected Point3[] startPointArray; + protected Point3[] endPointArray; + protected Point3[] deltaPointArray; + protected Point3[] startScaleArray; + protected Point3[] endScaleArray; + protected Point3[] deltaScaleArray; + protected Point3[] startSpinArray; + protected Point3[] endSpinArray; + protected String startRotation; + protected String endRotation; + protected float[] startRotationArray; + protected float[] endRotationArray; + protected boolean MultiMotionTransformInitialized; + protected boolean variableInitialized; + protected boolean multiMotionEnd = true; + + public MultiMotion() { + this.cycleTime = new String("1000"); + this.cycleTimeArray = new float[this.motionNumberMax]; + this.cycleTimeArray[0] = 1000.0F; + this.trigger = new String("none"); + this.externalTriggerTag = new String(""); + this.cycles = 0; + this.MultiMotionTransformInitialized = false; + this.variableInitialized = false; + this.startPointArray = new Point3[this.motionNumberMax]; + this.endPointArray = new Point3[this.motionNumberMax]; + this.deltaPointArray = new Point3[this.motionNumberMax]; + this.startScaleArray = new Point3[this.motionNumberMax]; + this.endScaleArray = new Point3[this.motionNumberMax]; + this.deltaScaleArray = new Point3[this.motionNumberMax]; + this.startSpinArray = new Point3[this.motionNumberMax]; + this.endSpinArray = new Point3[this.motionNumberMax]; + + for (int i = 0; i < this.motionNumberMax; i++) { + this.startPointArray[i] = new Point3(); + this.endPointArray[i] = new Point3(); + this.deltaPointArray[i] = new Point3(); + this.startScaleArray[i] = new Point3(); + this.endScaleArray[i] = new Point3(); + this.deltaScaleArray[i] = new Point3(); + this.startSpinArray[i] = new Point3(); + this.endSpinArray[i] = new Point3(); + } + + this.startRotationArray = new float[this.motionNumberMax]; + this.endRotationArray = new float[this.motionNumberMax]; + this.startMultiMotion(); + } + + @Override + public void ExternalTrigger(Trigger trigger_source, int sequence_no, int event_no) { + this.trigger_source = trigger_source; + this.sequence_no = sequence_no; + this.event_no = event_no; + this.startMultiMotion(); + } + + public void startMultiMotion() { + Date timer = new Date(); + this.startMultiMotionTime = timer.getTime(); + this.motionNumber = 0; + this.multiMotionEnd = false; + } + + public void setTotalMultiMotionTime() { + this.totalMultiMotionTime = 0L; + + for (int i = 0; i < this.motionNumberCount; i++) { + this.totalMultiMotionTime = this.totalMultiMotionTime + (int)this.cycleTimeArray[i]; + } + } + + public void parseFloatString(String floatList, float[] floatArray) { + int currentIndex = 0; + int currentSeparator = 0; + int nextSeparator = 0; + int lastSeparator = floatList.lastIndexOf(" "); + if (lastSeparator != -1 || floatList.length() != 0) { + if (lastSeparator == -1) { + floatArray[currentIndex] = Float.valueOf(floatList); + } else { + nextSeparator = floatList.indexOf(" "); + floatArray[currentIndex] = Float.valueOf(floatList.substring(0, nextSeparator)); + currentIndex++; + + while (nextSeparator != lastSeparator) { + currentSeparator = nextSeparator; + nextSeparator = floatList.indexOf(" ", nextSeparator + 1); + floatArray[currentIndex] = Float.valueOf(floatList.substring(currentSeparator + 1, nextSeparator)); + currentIndex++; + } + + floatArray[currentIndex] = Float.valueOf(floatList.substring(nextSeparator + 1)); + } + } + } + + public Point3 StringToPoint3(String Point3String) { + Point3 newPoint3 = new Point3(); + int currentIndex = 0; + newPoint3.x = Float.valueOf(Point3String.substring(currentIndex, Point3String.indexOf(",", currentIndex))); + currentIndex = Point3String.indexOf(",", currentIndex) + 1; + newPoint3.y = Float.valueOf(Point3String.substring(currentIndex, Point3String.indexOf(",", currentIndex))); + currentIndex = Point3String.indexOf(",", currentIndex) + 1; + newPoint3.z = Float.valueOf(Point3String.substring(currentIndex, Point3String.length())); + return newPoint3; + } + + public void parsePoint3String(String Point3List, Point3[] Point3Array) { + int currentIndex = 0; + int currentSeparator = 0; + int nextSeparator = 0; + int lastSeparator = Point3List.lastIndexOf(" "); + if (lastSeparator != -1 || Point3List.length() != 0) { + if (lastSeparator == -1) { + Point3Array[currentIndex] = this.StringToPoint3(Point3List); + } else { + nextSeparator = Point3List.indexOf(" "); + Point3Array[currentIndex] = this.StringToPoint3(Point3List.substring(0, nextSeparator)); + currentIndex++; + + while (nextSeparator != lastSeparator) { + currentSeparator = nextSeparator; + nextSeparator = Point3List.indexOf(" ", nextSeparator + 1); + Point3Array[currentIndex] = this.StringToPoint3(Point3List.substring(currentSeparator + 1, nextSeparator)); + currentIndex++; + } + + Point3Array[currentIndex] = this.StringToPoint3(Point3List.substring(nextSeparator + 1)); + } + } + } + + @Override + public boolean handle(FrameEvent e) { + if (!this.MultiMotionTransformInitialized) { + this.MultiMotionTransform = e.target; + this.MultiMotionTransformInitialized = true; + } + + if (!this.variableInitialized) { + this.startPoint = this.MultiMotionTransform.getPosition().toString(); + this.startPointArray[0].copy(this.MultiMotionTransform.getPosition()); + this.endPoint = new String(this.startPoint); + this.endPointArray[0].copy(this.startPointArray[0]); + this.startScaleArray[0].x = this.MultiMotionTransform.getTotalScale(); + this.startScaleArray[0].y = this.MultiMotionTransform.getTotalScale(); + this.startScaleArray[0].z = this.MultiMotionTransform.getTotalScale(); + this.startScale = this.startScaleArray[0].toString(); + this.endScaleArray[0].copy(this.startScaleArray[0]); + this.endScale = this.endScaleArray[0].toString(); + this.startRotation = new Float(this.MultiMotionTransform.getSpin(this.startSpinArray[0])).toString(); + this.startRotationArray[0] = Float.valueOf(this.startRotation); + this.startSpin = this.startSpinArray[0].toString(); + this.endRotation = new String("0.0"); + this.endRotationArray[0] = Float.valueOf(this.endRotation); + this.endSpinArray[0] = new Point3(); + this.endSpin = this.endSpinArray[0].toString(); + this.variableInitialized = true; + } + + if (this.enabled) { + Date timer = new Date(); + long currentTime = timer.getTime(); + int cycleNo = 0; + if (this.totalMultiMotionTime > 0L) { + cycleNo = (int)((-this.startMultiMotionTime + currentTime) / this.totalMultiMotionTime); + } + + if (this.totalMultiMotionTime > 0L && (cycleNo < this.cycles || this.cycles == 0)) { + long totalTime = 0L; + int currentCycleTime = (int)((currentTime - this.startMultiMotionTime) % this.totalMultiMotionTime); + int currentMotionTime = 0; + + for (this.motionNumber = 0; this.motionNumber < this.motionNumberCount && totalTime <= currentCycleTime; this.motionNumber++) { + currentMotionTime = (int)this.cycleTimeArray[this.motionNumber]; + totalTime += currentMotionTime; + } + + this.motionNumber--; + if (totalTime < currentCycleTime) { + System.out.print("Error in totalMultiMotionTime computation.\n"); + } + + currentMotionTime = (int)(currentMotionTime - (totalTime - currentCycleTime)); + float frameLoc = currentMotionTime % this.cycleTimeArray[this.motionNumber] / this.cycleTimeArray[this.motionNumber]; + e.receiver.makeIdentity(); + e.receiver + .scale( + this.startScaleArray[this.motionNumber].x + (this.endScaleArray[this.motionNumber].x - this.startScaleArray[this.motionNumber].x) * frameLoc, + this.startScaleArray[this.motionNumber].x + (this.endScaleArray[this.motionNumber].x - this.startScaleArray[this.motionNumber].x) * frameLoc, + this.startScaleArray[this.motionNumber].x + (this.endScaleArray[this.motionNumber].x - this.startScaleArray[this.motionNumber].x) * frameLoc + ); + e.receiver + .moveTo( + this.startPointArray[this.motionNumber].x + (this.endPointArray[this.motionNumber].x - this.startPointArray[this.motionNumber].x) * frameLoc, + this.startPointArray[this.motionNumber].y + (this.endPointArray[this.motionNumber].y - this.startPointArray[this.motionNumber].y) * frameLoc, + this.startPointArray[this.motionNumber].z + (this.endPointArray[this.motionNumber].z - this.startPointArray[this.motionNumber].z) * frameLoc + ); + e.receiver.spin(this.startSpinArray[this.motionNumber], this.startRotationArray[this.motionNumber]); + e.receiver.spin(this.endSpinArray[this.motionNumber], this.endRotationArray[this.motionNumber] * frameLoc); + } else if (cycleNo >= this.cycles && this.cycles != 0 && !this.multiMotionEnd) { + this.multiMotionEnd = true; + if (this.trigger_source != null) { + this.trigger_source.registerFinishedTriggerTag(this.sequence_no, this.event_no); + } + } + } + + return true; + } + + @Override + public boolean handle(MouseDownEvent e) { + if (this.enabled && this.trigger.equals("click")) { + this.startMultiMotion(); + } + + return true; + } + + @Override + public boolean handle(BumpEventTemp e) { + if (this.enabled && this.trigger.equals("bump")) { + this.startMultiMotion(); + } + + return true; + } + + public void startTransform() { + if (this.MultiMotionTransform != null) { + this.MultiMotionTransform.makeIdentity(); + this.MultiMotionTransform + .scale(this.startScaleArray[this.motionNumber].x, this.startScaleArray[this.motionNumber].x, this.startScaleArray[this.motionNumber].x); + this.MultiMotionTransform + .moveTo(this.startPointArray[this.motionNumber].x, this.startPointArray[this.motionNumber].y, this.startPointArray[this.motionNumber].z); + this.MultiMotionTransform.spin(this.startSpinArray[this.motionNumber], this.startRotationArray[this.motionNumber]); + } + } + + public void endTransform() { + if (this.MultiMotionTransform != null) { + this.MultiMotionTransform.makeIdentity(); + this.MultiMotionTransform + .scale(this.endScaleArray[this.motionNumber].x, this.endScaleArray[this.motionNumber].x, this.endScaleArray[this.motionNumber].x); + this.MultiMotionTransform + .moveTo(this.endPointArray[this.motionNumber].x, this.endPointArray[this.motionNumber].y, this.endPointArray[this.motionNumber].z); + this.MultiMotionTransform.spin(this.startSpinArray[this.motionNumber], this.startRotationArray[this.motionNumber]); + this.MultiMotionTransform.spin(this.endSpinArray[this.motionNumber], this.endRotationArray[this.motionNumber]); + } + } + + @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 = new ClassProperty(this, index, "MultiMotion"); + } + break; + case 1: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Number of Motions")); + } else if (mode == 1) { + ret = new Integer(this.motionNumberCount); + } else if (mode == 2) { + this.motionNumberCount = (Integer)value; + this.setTotalMultiMotionTime(); + } + break; + case 2: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Cycles")); + } else if (mode == 1) { + ret = new Integer(this.cycles); + } else if (mode == 2) { + this.cycles = (Integer)value; + } + break; + case 3: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Trigger")); + } else if (mode == 1) { + ret = new String(this.trigger); + } else if (mode == 2) { + this.trigger = ((String)value).toString().trim(); + if (this.trigger.equals("external")) { + Trigger.TriggeredSwitchableBehaviorList[Trigger.TriggeredSwitchableBehaviorListCount] = this; + Trigger.TriggeredSwitchableBehaviorListCount++; + } + } + break; + case 4: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "External Trigger Tag")); + } else if (mode == 1) { + ret = new String(this.externalTriggerTag); + } else if (mode == 2) { + this.externalTriggerTag = ((String)value).toString().trim(); + } + break; + case 5: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Cycle Time")); + } else if (mode == 1) { + ret = new String(this.cycleTime); + } else if (mode == 2) { + this.cycleTime = (String)value; + this.parseFloatString(this.cycleTime, this.cycleTimeArray); + this.setTotalMultiMotionTime(); + } + break; + case 6: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "End Point")); + } else if (mode == 1) { + ret = new String(this.endPoint); + this.endTransform(); + } else if (mode == 2) { + this.endPoint = (String)value; + this.parsePoint3String(this.endPoint, this.endPointArray); + this.endTransform(); + } + break; + case 7: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Start Point")); + } else if (mode == 1) { + ret = new String(this.startPoint); + this.startTransform(); + } else if (mode == 2) { + this.startPoint = (String)value; + this.parsePoint3String(this.startPoint, this.startPointArray); + this.startTransform(); + } + break; + case 8: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "End Scale")); + } else if (mode == 1) { + ret = new String(this.endScale); + this.endTransform(); + } else if (mode == 2) { + this.endScale = (String)value; + this.parsePoint3String(this.endScale, this.endScaleArray); + this.endTransform(); + } + break; + case 9: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Start Scale")); + } else if (mode == 1) { + ret = new String(this.startScale); + this.startTransform(); + } else if (mode == 2) { + this.startScale = (String)value; + this.parsePoint3String(this.startScale, this.startScaleArray); + this.startTransform(); + } + break; + case 10: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "End Spin (Relative)")); + } else if (mode == 1) { + ret = new String(this.endSpin); + this.endTransform(); + } else if (mode == 2) { + this.endSpin = (String)value; + this.parsePoint3String(this.endSpin, this.endSpinArray); + this.endTransform(); + } + break; + case 11: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Start Spin")); + } else if (mode == 1) { + ret = new String(this.startSpin); + this.startTransform(); + } else if (mode == 2) { + this.startSpin = (String)value; + this.parsePoint3String(this.startSpin, this.startSpinArray); + this.startTransform(); + } + break; + case 12: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "End Rotation (Relative)")); + } else if (mode == 1) { + ret = new String(this.endRotation); + this.endTransform(); + } else if (mode == 2) { + this.endRotation = (String)value; + this.parseFloatString(this.endRotation, this.endRotationArray); + this.endTransform(); + } + break; + case 13: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Start Rotation")); + } else if (mode == 1) { + ret = new String(this.startRotation); + this.startTransform(); + } else if (mode == 2) { + this.startRotation = (String)value; + this.parseFloatString(this.startRotation, this.startRotationArray); + this.startTransform(); + } + break; + default: + ret = super.properties(index, offset + 14, mode, value); + } + + if (mode == 2 && this.trigger.equals("none")) { + this.startMultiMotion(); + } + + return ret; + } + + @Override + public String toString() { + return "Multimotion: cycleTime " + + this.cycleTime + + ", cycles " + + this.cycles + + ", enabled " + + this.enabled + + ", trigger " + + this.trigger + + ", externalTriggerTag " + + this.externalTriggerTag; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveInt(this.motionNumberCount); + s.saveInt(this.cycles); + s.saveString(this.trigger); + s.saveString(this.externalTriggerTag); + s.saveString(this.cycleTime); + s.saveString(this.endPoint); + s.saveString(this.startPoint); + s.saveString(this.endScale); + s.saveString(this.startScale); + s.saveString(this.endSpin); + s.saveString(this.startSpin); + s.saveString(this.endRotation); + s.saveString(this.startRotation); + } + + @Override + public void restoreState(Restorer r) throws IOException { + this.motionNumberCount = r.restoreInt(); + this.cycles = r.restoreInt(); + this.trigger = r.restoreString(); + if (this.trigger.equals("external")) { + Trigger.TriggeredSwitchableBehaviorList[Trigger.TriggeredSwitchableBehaviorListCount] = this; + Trigger.TriggeredSwitchableBehaviorListCount++; + } + + this.externalTriggerTag = r.restoreString(); + this.cycleTime = r.restoreString(); + this.parseFloatString(this.cycleTime, this.cycleTimeArray); + this.endPoint = r.restoreString(); + this.parsePoint3String(this.endPoint, this.endPointArray); + this.setTotalMultiMotionTime(); + this.startPoint = r.restoreString(); + this.parsePoint3String(this.startPoint, this.startPointArray); + this.endScale = r.restoreString(); + this.parsePoint3String(this.endScale, this.endScaleArray); + this.startScale = r.restoreString(); + this.parsePoint3String(this.startScale, this.startScaleArray); + this.endSpin = r.restoreString(); + this.parsePoint3String(this.endSpin, this.endSpinArray); + this.startSpin = r.restoreString(); + this.parsePoint3String(this.startSpin, this.startSpinArray); + this.endRotation = r.restoreString(); + this.parseFloatString(this.endRotation, this.endRotationArray); + this.startRotation = r.restoreString(); + this.parseFloatString(this.startRotation, this.startRotationArray); + this.variableInitialized = true; + if (!this.trigger.equals("none")) { + this.startMultiMotionTime = (int)(-(this.cycles * this.cycleTimeArray[this.motionNumber])); + } else { + this.startMultiMotion(); + } + } + + @Override + public void postRestore(int version) { + String name = this.getName(); + String arg1 = name == null ? "<null>" : name; + SuperRoot owner = this.getOwner(); + String oname = ""; + if (owner != null) { + oname = owner.getName(); + } + + String arg2 = oname == null ? "<null>" : oname; + Object[] arguments = new Object[]{new String(arg1), new String(arg2)}; + Console.println(MessageFormat.format(Console.message("MultiMotion-obs"), arguments)); + } +} diff --git a/NET/worlds/scape/MusicManager.java b/NET/worlds/scape/MusicManager.java new file mode 100644 index 0000000..9ef0cac --- /dev/null +++ b/NET/worlds/scape/MusicManager.java @@ -0,0 +1,258 @@ +package NET.worlds.scape; + +import NET.worlds.console.DialogReceiver; +import NET.worlds.console.Main; +import NET.worlds.console.MainCallback; +import NET.worlds.core.Sort; +import NET.worlds.network.URL; +import java.io.DataInputStream; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.StringTokenizer; + +public class MusicManager implements MainCallback, DialogReceiver { + private static Hashtable managers = new Hashtable(); + private static MusicManagerDialog dialog; + private static boolean registered; + private static URL lastWorldURL; + private static boolean showDialog; + private static MusicManager curManager; + private static String lastRoomName = ""; + private static int lastCDTrack; + private static URL lastMIDIFile; + private String name; + private Hashtable tracks = new Hashtable(); + private Hashtable rooms = new Hashtable(); + private World world; + private String fileName; + private boolean maybeMusicChange; + + public static void showDialog() { + if (dialog == null) { + showDialog = true; + } + } + + public MusicManager() { + if (!registered) { + Main.register(this); + registered = true; + curManager = this; + } + } + + private MusicManager(World world, URL url) { + this.world = world; + this.name = world.getName(); + String file = url.unalias().toLowerCase(); + int index = file.lastIndexOf(".world"); + if (index != -1) { + this.fileName = url.unalias().substring(0, index) + ".music"; + this.load(); + } + } + + public World getWorld() { + return this.world; + } + + public String getName() { + return this.name; + } + + public String getFileName() { + return this.fileName; + } + + public Hashtable getMusic() { + return this.tracks; + } + + public MusicTrack getMusic(String name) { + return (MusicTrack)this.tracks.get(name); + } + + public Hashtable getRooms() { + return this.rooms; + } + + public MusicRoom getRoom(String name) { + return (MusicRoom)this.rooms.get(name); + } + + public synchronized void maybeChangedMusic() { + this.maybeMusicChange = true; + } + + public void save() { + PrintStream out = null; + + try { + out = new PrintStream(new FileOutputStream(this.fileName)); + Enumeration e = this.tracks.elements(); + String[] keys = Sort.sortKeys(this.tracks); + + for (int i = 0; i < keys.length; i++) { + MusicTrack m = (MusicTrack)this.tracks.get(keys[i]); + String midiName = m.getMIDIFileName(); + if (midiName.length() == 0) { + midiName = "-"; + } + + out.println("MUSIC|" + m.getName() + "|" + m.getVirtTrackNumber() + "|" + midiName + "|" + m.getLooping()); + } + + keys = Sort.sortKeys(this.rooms); + + for (int i = 0; i < keys.length; i++) { + MusicRoom r = (MusicRoom)this.rooms.get(keys[i]); + out.println("ROOM|" + r.getRoomName() + "|" + r.getMusicName()); + } + } catch (Exception var10) { + } finally { + if (out != null) { + out.close(); + } + } + } + + private void load() { + this.tracks.clear(); + this.rooms.clear(); + DataInputStream in = null; + String line = null; + + try { + in = new DataInputStream(new FileInputStream(this.fileName)); + + while ((line = in.readLine()) != null) { + StringTokenizer tok = new StringTokenizer(line, "|"); + String type = tok.nextToken(); + if (type.equals("MUSIC")) { + MusicTrack track = new MusicTrack(tok.nextToken(), Integer.parseInt(tok.nextToken()), tok.nextToken(), Boolean.valueOf(tok.nextToken())); + this.tracks.put(track.getName(), track); + } else if (type.equals("ROOM")) { + MusicRoom room = new MusicRoom(tok.nextToken(), tok.nextToken()); + this.rooms.put(room.getRoomName(), room); + } + } + } catch (Exception var14) { + } finally { + try { + if (in != null) { + in.close(); + } + } catch (IOException var13) { + } + } + } + + @Override + public void mainCallback() { + Pilot pilot = Pilot.getActive(); + if (pilot != null) { + World world = pilot.getWorld(); + boolean worldChange = false; + String newRoomName = ""; + if (world != null) { + URL url = world.getSourceURL(); + if (!url.equals(lastWorldURL)) { + MusicManager manager = (MusicManager)managers.get(url); + if (manager == null) { + manager = new MusicManager(world, url); + managers.put(url, manager); + } + + lastWorldURL = url; + curManager = manager; + worldChange = true; + } + + Room room = pilot.getRoom(); + if (room != null) { + String roomName = room.getName(); + if (roomName != null) { + newRoomName = roomName; + } + } + } else { + lastWorldURL = null; + } + + synchronized (this) { + if (worldChange || !newRoomName.equals(lastRoomName) || curManager.maybeMusicChange) { + curManager.maybeMusicChange = false; + lastRoomName = newRoomName; + MusicRoom mr = curManager.getRoom(lastRoomName); + CDAudio cd = CDAudio.get(); + boolean found = false; + if (mr != null) { + MusicTrack mt = curManager.getMusic(mr.getMusicName()); + if (mt != null) { + found = true; + int track = mt.getVirtTrackNumber(); + boolean changed = false; + if (track != cd.getCDTrack()) { + lastCDTrack = track; + cd.setCDTrack(track); + changed = true; + } + + String name = mt.getMIDIFileName(); + URL midiPath; + if (name.length() != 0) { + midiPath = URL.make(world.getSourceURL(), mt.getMIDIFileName()); + } else { + midiPath = cd.getDefaultMIDIFile(); + } + + if (!midiPath.equals(cd.getMIDIFile())) { + lastMIDIFile = midiPath; + cd.setMIDIFile(midiPath); + changed = true; + } + + if (changed) { + cd.change(mt.getLooping()); + } + } + } + + if (!found) { + if (lastCDTrack != 0 && cd.getCDTrack() == lastCDTrack || lastMIDIFile != null && lastMIDIFile.equals(cd.getMIDIFile())) { + cd.setCDTrack(0); + cd.setMIDIFile(cd.getDefaultMIDIFile()); + cd.stop(); + } + + lastCDTrack = 0; + lastMIDIFile = null; + } + } + } + } else { + lastWorldURL = null; + } + + if (lastWorldURL != null && dialog == null && showDialog) { + showDialog = false; + dialog = new MusicManagerDialog((MusicManager)managers.get(lastWorldURL)); + } + } + + @Override + public void dialogDone(Object who, boolean confirmed) { + if (confirmed) { + this.save(); + } else { + this.load(); + this.maybeChangedMusic(); + } + + dialog = null; + } +} diff --git a/NET/worlds/scape/MusicManagerDialog.java b/NET/worlds/scape/MusicManagerDialog.java new file mode 100644 index 0000000..50e643d --- /dev/null +++ b/NET/worlds/scape/MusicManagerDialog.java @@ -0,0 +1,397 @@ +package NET.worlds.scape; + +import NET.worlds.console.ConfirmDialog; +import NET.worlds.console.Console; +import NET.worlds.console.DialogReceiver; +import NET.worlds.console.OkCancelDialog; +import NET.worlds.console.PolledDialog; +import NET.worlds.core.Sort; +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Checkbox; +import java.awt.CheckboxGroup; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Label; +import java.awt.List; +import java.awt.Panel; +import java.awt.Point; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +class MusicManagerDialog extends PolledDialog implements DialogReceiver { + private MusicManager manager; + private String lastRoom = ""; + private Label curRoom = new Label(); + private Label curMusic = new Label(); + private Button assignCurButton = new Button(Console.message("Assign-Current")); + private Checkbox autoAssign = new Checkbox(Console.message("Auto-assign")); + private CheckboxGroup group = new CheckboxGroup(); + private Checkbox musicBox = new Checkbox(Console.message("Music"), this.group, true); + private Checkbox aRoomsBox = new Checkbox(Console.message("Assigned-rooms"), this.group, false); + private Checkbox uRoomsBox = new Checkbox(Console.message("Unassigned-rooms"), this.group, false); + private List list = new List(10); + private Button editButton = new Button(Console.message("Edit")); + private Button addButton = new Button(Console.message("Add")); + private Button delButton = new Button(Console.message("Delete")); + private Button assignButton = new Button(Console.message("Assign")); + private Button saveButton = new Button(Console.message("Save-Changes")); + private Button okButton = new Button(Console.message("OK")); + private Button cancelButton = new Button(Console.message("Cancel")); + private PolledDialog subDialog; + private Vector allRooms; + private boolean madeChanges; + private boolean confirmingState; + static Point lastWindowLocation = null; + private static Font font = new Font(Console.message("MenuFont"), 0, 12); + private static Font bfont = new Font(Console.message("ButtonFont"), 0, 12); + private static final String title = Console.message("Music-Manager"); + + public MusicManagerDialog(MusicManager manager) { + super(Console.getFrame(), manager, title + manager.getName(), false); + this.setAlignment(2); + this.manager = manager; + this.ready(); + } + + public MusicManager getManager() { + return this.manager; + } + + public String getCurRoom() { + return this.curRoom.getText(); + } + + public Vector getAllRooms() { + return this.allRooms; + } + + @Override + protected void build() { + GridBagLayout gbag = new GridBagLayout(); + this.setLayout(gbag); + GridBagConstraints c = new GridBagConstraints(); + Panel p = new Panel(new BorderLayout()); + this.musicBox.setFont(font); + this.aRoomsBox.setFont(font); + this.uRoomsBox.setFont(font); + p.add("West", this.musicBox); + p.add("Center", this.aRoomsBox); + p.add("East", this.uRoomsBox); + c.weightx = 0.0; + c.gridwidth = 0; + this.add(gbag, p, c); + c.fill = 1; + c.weightx = 1.0; + c.weighty = 1.0; + c.gridwidth = 2; + c.gridheight = 6; + this.list.setFont(font); + this.add(gbag, this.list, c); + c.fill = 2; + c.weightx = 0.0; + c.weighty = 0.0; + c.gridwidth = 0; + c.gridheight = 1; + this.assignButton.setFont(bfont); + this.editButton.setFont(bfont); + this.addButton.setFont(bfont); + this.delButton.setFont(bfont); + this.add(gbag, this.assignButton, c); + this.add(gbag, this.editButton, c); + this.add(gbag, this.addButton, c); + this.add(gbag, this.delButton, c); + + for (int i = 0; i < 2; i++) { + this.add(gbag, new Label(""), c); + } + + c.gridwidth = 1; + c.fill = 0; + Label cRoom = new Label(Console.message("Current-room")); + cRoom.setFont(font); + this.add(gbag, cRoom, c); + c.gridwidth = 0; + c.weightx = 1.0; + c.fill = 2; + this.curRoom.setFont(font); + this.add(gbag, this.curRoom, c); + c.gridwidth = 1; + c.weightx = 0.0; + Label aMusic = new Label(Console.message("Assigned-music")); + aMusic.setFont(font); + this.add(gbag, aMusic, c); + c.fill = 0; + c.gridwidth = 0; + c.fill = 2; + c.weightx = 1.0; + this.curMusic.setFont(font); + this.add(gbag, this.curMusic, c); + c.weightx = 0.0; + c.weighty = 0.0; + c.gridwidth = 1; + c.fill = 0; + this.assignCurButton.setFont(bfont); + this.autoAssign.setFont(bfont); + this.add(gbag, this.assignCurButton, c); + c.gridwidth = 0; + this.add(gbag, this.autoAssign, c); + p = new Panel(); + p.setFont(bfont); + p.add(this.saveButton); + p.add(this.okButton); + p.add(this.cancelButton); + c.fill = 2; + this.add(gbag, p, c); + this.rebuildList(false); + this.buildAllRoomsList(); + } + + @Override + protected boolean done(boolean confirmed) { + lastWindowLocation = this.getLocation(); + return super.done(confirmed); + } + + @Override + protected void initialSize(int width, int height) { + if (lastWindowLocation == null) { + super.initialSize(width, height); + } else { + this.setLocation(lastWindowLocation); + this.setSize(width, height); + } + } + + private void buildAllRoomsList() { + this.allRooms = new Vector(); + Pilot pilot = Pilot.getActive(); + if (pilot != null) { + World world = pilot.getWorld(); + if (world != null) { + Enumeration rooms = world.getRooms(); + + while (rooms.hasMoreElements()) { + this.allRooms.addElement(((Room)rooms.nextElement()).getName()); + } + } + } + } + + private void rebuildList(boolean changed) { + boolean enable = !this.uRoomsBox.getState(); + this.assignButton.setEnabled(!this.musicBox.getState()); + this.editButton.setEnabled(enable); + this.addButton.setEnabled(enable); + this.delButton.setEnabled(enable); + this.list.removeAll(); + if (this.musicBox.getState()) { + Sort.sortInto(this.list, this.manager.getMusic()); + } else if (this.aRoomsBox.getState()) { + String[] content = Sort.sortKeys(this.manager.getRooms()); + + for (int i = 0; i < content.length; i++) { + String name = content[i]; + this.list.add(name + " (" + this.manager.getRoom(name).getMusicName() + ")"); + } + } else { + Enumeration e = this.allRooms.elements(); + Hashtable aRooms = this.manager.getRooms(); + Vector v = new Vector(); + + while (e.hasMoreElements()) { + String name = (String)e.nextElement(); + if (!aRooms.containsKey(name)) { + v.addElement(name); + } + } + + Sort.sortInto(this.list, v); + } + + if (changed) { + this.madeChanges = true; + this.manager.maybeChangedMusic(); + } + } + + @Override + protected synchronized void activeCallback() { + Pilot pilot = Pilot.getActive(); + if (pilot != null) { + World world = pilot.getWorld(); + if (world != null && world.getSourceURL().equals(this.manager.getWorld().getSourceURL())) { + Room room = pilot.getRoom(); + if (room != null) { + String name = room.getName(); + if (!name.equals(this.lastRoom)) { + this.lastRoom = name; + this.curRoom.setText(name); + MusicRoom mr = this.manager.getRoom(name); + if (mr != null) { + this.curMusic.setText(mr.getMusicName()); + } else { + this.curMusic.setText(""); + if (this.autoAssign.getState() && this.subDialog == null) { + this.subDialog = new EditRoomDialog(this, null, name); + } + } + } + + return; + } + } + } + + this.curRoom.setText(""); + this.curMusic.setText(""); + } + + @Override + public synchronized boolean action(java.awt.Event event, Object what) { + Object target = event.target; + String selected = this.list.getSelectedItem(); + boolean isMusic = this.musicBox.getState(); + boolean haveMusic = this.manager.getMusic().size() != 0; + if (isMusic && target == this.editButton && selected != null) { + this.subDialog = new EditMusicDialog(this, this.manager.getMusic(selected)); + } else if (isMusic && target == this.addButton) { + this.subDialog = new EditMusicDialog(this, null); + } else if (isMusic && target == this.delButton && selected != null) { + if (!this.isMusicInUse(selected)) { + this.manager.getMusic().remove(selected); + if (this.manager.getMusic().size() == 0) { + this.autoAssign.setState(false); + } + + this.rebuildList(true); + } else { + this.cantChangeMusic(); + } + } else if (!isMusic && target == this.editButton && selected != null && haveMusic) { + selected = selected.substring(0, selected.lastIndexOf(40) - 1); + this.subDialog = new EditRoomDialog(this, this.manager.getRoom(selected), selected); + } else if (!isMusic && target == this.addButton) { + if (haveMusic) { + this.subDialog = new EditRoomDialog(this, null, this.getCurRoom()); + } else { + this.needMusic(); + } + } else if (!isMusic && target == this.delButton && selected != null) { + selected = selected.substring(0, selected.lastIndexOf(40) - 1); + this.manager.getRooms().remove(selected); + this.rebuildList(true); + } else if (target == this.saveButton) { + this.manager.save(); + this.madeChanges = false; + } else if (target == this.okButton) { + if (this.madeChanges) { + this.confirmingState = true; + new ConfirmDialog(this, this, Console.message("Save-Changes2"), Console.message("sure-save")); + } else { + this.done(false); + } + } else if (target == this.cancelButton) { + if (this.madeChanges) { + this.confirmingState = false; + new ConfirmDialog(this, this, Console.message("Abandon-Changes"), Console.message("sure-cancel")); + } else { + this.done(false); + } + } else if (target != this.musicBox && target != this.aRoomsBox && target != this.uRoomsBox) { + if ((target != this.assignButton || selected == null) && target != this.assignCurButton) { + if (target != this.autoAssign || !this.autoAssign.getState()) { + return false; + } + + if (haveMusic) { + if (this.manager.getRoom(this.lastRoom) == null) { + this.subDialog = new EditRoomDialog(this, null, this.lastRoom); + } + } else { + this.autoAssign.setState(false); + this.needMusic(); + } + } else if (haveMusic) { + String selection = target == this.assignButton ? selected : this.lastRoom; + this.subDialog = new EditRoomDialog(this, this.manager.getRoom(selection), selection); + } else { + this.needMusic(); + } + } else { + this.rebuildList(false); + } + + return true; + } + + @Override + public boolean handleEvent(java.awt.Event event) { + if (event.key != 1004 && event.key != 1005 && event.key != 1006 && event.key != 1007) { + return super.handleEvent(event); + } else { + Console.getFrame().requestFocus(); + return true; + } + } + + private void needMusic() { + this.subDialog = new OkCancelDialog(this, this, Console.message("Need-Music"), null, Console.message("OK"), Console.message("at-least-one"), true); + } + + private boolean isMusicInUse(String name) { + Enumeration e = this.manager.getRooms().elements(); + + while (e.hasMoreElements()) { + if (name.equals(((MusicRoom)e.nextElement()).getMusicName())) { + return true; + } + } + + return false; + } + + private void cantChangeMusic() { + this.subDialog = new OkCancelDialog(this, this, Console.message("Cant-Change"), null, Console.message("OK"), Console.message("may-not-delete"), true); + } + + @Override + public synchronized void dialogDone(Object who, boolean confirmed) { + boolean showCantChange = false; + if (confirmed) { + if (who instanceof EditMusicDialog) { + EditMusicDialog em = (EditMusicDialog)who; + MusicTrack music = em.getMusicTrack(); + String oldName = em.getOldName(); + if (oldName != null && !oldName.equals(music.getName()) && this.isMusicInUse(oldName)) { + music.setName(oldName); + showCantChange = true; + } + + this.manager.getMusic().put(music.getName(), music); + this.rebuildList(true); + } else if (who instanceof EditRoomDialog) { + EditRoomDialog er = (EditRoomDialog)who; + MusicRoom room = er.getMusicRoom(); + this.manager.getRooms().put(room.getRoomName(), room); + this.rebuildList(true); + } else if (who instanceof ConfirmDialog) { + this.done(this.confirmingState); + } + + if (this.lastRoom != null) { + MusicRoom mr = this.manager.getRoom(this.lastRoom); + if (mr != null) { + this.curMusic.setText(mr.getMusicName()); + } + } + } + + this.subDialog = null; + if (showCantChange) { + this.cantChangeMusic(); + } + } +} diff --git a/NET/worlds/scape/MusicRoom.java b/NET/worlds/scape/MusicRoom.java new file mode 100644 index 0000000..1ce3299 --- /dev/null +++ b/NET/worlds/scape/MusicRoom.java @@ -0,0 +1,32 @@ +package NET.worlds.scape; + +class MusicRoom { + private String roomName; + private String musicName; + + public MusicRoom(String roomName, String musicName) { + this.roomName = roomName; + this.musicName = musicName; + } + + public String getRoomName() { + return this.roomName; + } + + public void setRoomName(String roomName) { + this.roomName = roomName; + } + + public String getMusicName() { + return this.musicName; + } + + public void setMusicName(String musicName) { + this.musicName = musicName; + } + + @Override + public String toString() { + return this.roomName; + } +} diff --git a/NET/worlds/scape/MusicTrack.java b/NET/worlds/scape/MusicTrack.java new file mode 100644 index 0000000..9872a20 --- /dev/null +++ b/NET/worlds/scape/MusicTrack.java @@ -0,0 +1,52 @@ +package NET.worlds.scape; + +class MusicTrack { + private String name; + private int vTrack; + private String midi; + private boolean loop; + + public MusicTrack(String name, int vTrack, String midi, boolean loop) { + this.name = name; + this.vTrack = vTrack; + this.midi = midi.equals("-") ? "" : midi; + this.loop = loop; + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + public int getVirtTrackNumber() { + return this.vTrack; + } + + public void setVirtTrackNumber(int vTrack) { + this.vTrack = vTrack; + } + + public String getMIDIFileName() { + return this.midi; + } + + public void setMIDIFileName(String midi) { + this.midi = midi; + } + + public boolean getLooping() { + return this.loop; + } + + public void setLooping(boolean loop) { + this.loop = loop; + } + + @Override + public String toString() { + return this.name; + } +} diff --git a/NET/worlds/scape/MutedDrone.java b/NET/worlds/scape/MutedDrone.java new file mode 100644 index 0000000..cccc363 --- /dev/null +++ b/NET/worlds/scape/MutedDrone.java @@ -0,0 +1,46 @@ +package NET.worlds.scape; + +import NET.worlds.network.ObjID; +import NET.worlds.network.URL; +import NET.worlds.network.WorldServer; +import java.io.IOException; + +public class MutedDrone extends Drone { + private static Object classCookie = new Object(); + + public MutedDrone(ObjID objID, WorldServer serv, URL url) { + super(objID, serv); + this.setSourceURL(url); + } + + public MutedDrone() { + } + + @Override + public Drone setAvatarNow(URL url) { + if (this.shouldBeMuted()) { + this.setSourceURL(url); + return this; + } else { + return super.setAvatarNow(url); + } + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + super.saveState(s); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + int vers = r.restoreVersion(classCookie); + switch (vers) { + case 1: + super.restoreState(r); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/MyButton.java b/NET/worlds/scape/MyButton.java new file mode 100644 index 0000000..8c5a077 --- /dev/null +++ b/NET/worlds/scape/MyButton.java @@ -0,0 +1,14 @@ +package NET.worlds.scape; + +import java.awt.Button; + +class MyButton extends Button { + int numParamsXYZ; + int numParamsN; + + MyButton(String text, int numParamsXYZ, int numParamsN) { + super(text); + this.numParamsXYZ = numParamsXYZ; + this.numParamsN = numParamsN; + } +} diff --git a/NET/worlds/scape/NamedPortal.java b/NET/worlds/scape/NamedPortal.java new file mode 100644 index 0000000..a90fbd4 --- /dev/null +++ b/NET/worlds/scape/NamedPortal.java @@ -0,0 +1,33 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class NamedPortal implements Persister { + private static Object classCookie = new Object(); + + @Override + public void saveState(Saver s) throws IOException { + assert false; + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + r.setOldFlag(); + Portal p = new Portal(); + r.replace(this, p); + p.restoreState(r); + String name = r.restoreString(); + p.setName(name); + return; + default: + throw new TooNewException(); + } + } + + @Override + public void postRestore(int version) { + assert false; + } +} diff --git a/NET/worlds/scape/NametagDrone.java b/NET/worlds/scape/NametagDrone.java new file mode 100644 index 0000000..61bf382 --- /dev/null +++ b/NET/worlds/scape/NametagDrone.java @@ -0,0 +1,50 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import java.awt.Color; +import java.io.IOException; + +public class NametagDrone extends Drone { + private static Object classCookie = new Object(); + + @Override + public void loadInit() { + } + + @Override + public void setName(String v) { + super.setName(v); + SuperRoot nametag = SuperRoot.nameSearch(this.getContents(), "nametag"); + if (nametag != null && nametag instanceof Hologram) { + Hologram oldtag = (Hologram)nametag; + String name = this.getLongID(); + Texture[] tagText = new Texture[]{new StringTexture(name, Console.message("TextureFont"), 48, Color.black, Color.white)}; + oldtag.detach(); + Hologram newtag = new Hologram(tagText); + newtag.post(oldtag); + newtag.setScale(name.length() * 10, 1.0F, 10.0F); + newtag.setVisible(true); + newtag.setBumpable(false); + newtag.setLocalShadowed(false); + newtag.setShadowedLocally(true); + this.add(newtag); + } + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/NoSuchPropertyException.java b/NET/worlds/scape/NoSuchPropertyException.java new file mode 100644 index 0000000..d25078d --- /dev/null +++ b/NET/worlds/scape/NoSuchPropertyException.java @@ -0,0 +1,4 @@ +package NET.worlds.scape; + +public class NoSuchPropertyException extends Exception { +} diff --git a/NET/worlds/scape/NonPersister.java b/NET/worlds/scape/NonPersister.java new file mode 100644 index 0000000..a21e402 --- /dev/null +++ b/NET/worlds/scape/NonPersister.java @@ -0,0 +1,4 @@ +package NET.worlds.scape; + +public interface NonPersister { +} diff --git a/NET/worlds/scape/NotifyScriptAction.java b/NET/worlds/scape/NotifyScriptAction.java new file mode 100644 index 0000000..31f61e1 --- /dev/null +++ b/NET/worlds/scape/NotifyScriptAction.java @@ -0,0 +1,57 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class NotifyScriptAction extends Action { + private String message = "NotifyScriptAction"; + private static Object classCookie = new Object(); + + public void setMessage(String m) { + this.message = m; + } + + @Override + public Persister trigger(Event e, Persister seqId) { + WorldScriptManager.getInstance().action(this.message); + return null; + } + + @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 = StringPropertyEditor.make(new Property(this, index, "Message")); + } else if (mode == 1) { + ret = new String(this.message); + } else if (mode == 2) { + this.message = (String)value; + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + super.saveState(s); + s.saveString(this.message); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 1: + super.restoreState(r); + this.message = r.restoreString(); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/NumberAttribute.java b/NET/worlds/scape/NumberAttribute.java new file mode 100644 index 0000000..b37cf6b --- /dev/null +++ b/NET/worlds/scape/NumberAttribute.java @@ -0,0 +1,81 @@ +package NET.worlds.scape; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class NumberAttribute extends Attribute { + float value = 0.0F; + private static Object classCookie = new Object(); + + public NumberAttribute(int attrID) { + super(attrID); + } + + public NumberAttribute() { + } + + public void set(float x) { + this.value = x; + this.noteChange(); + } + + public float get() { + return this.value; + } + + @Override + public void generateNetData(DataOutputStream s) throws IOException { + s.writeFloat(this.value); + } + + @Override + public void setFromNetData(DataInputStream ds, int len) throws IOException { + this.value = ds.readFloat(); + } + + @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 = FloatPropertyEditor.make(new Property(this, index, "value")); + } else if (mode == 1) { + ret = new Float(this.get()); + } else if (mode == 2) { + this.set((Float)value); + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + s.saveFloat(this.value); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this.value = r.restoreFloat(); + this.set(this.value); + return; + default: + throw new TooNewException(); + } + } + + @Override + public String toString() { + return super.toString() + "[" + this.get() + "]"; + } +} diff --git a/NET/worlds/scape/ObjEditorDialog.java b/NET/worlds/scape/ObjEditorDialog.java new file mode 100644 index 0000000..a304dba --- /dev/null +++ b/NET/worlds/scape/ObjEditorDialog.java @@ -0,0 +1,12 @@ +package NET.worlds.scape; + +class ObjEditorDialog extends ObjectSelectorDialog { + ObjEditorDialog(EditTile parent, String title, Property property, SuperRoot r, Class clas) { + super(parent, title, property, r, clas); + } + + @Override + protected void addIt(Property p, Object obj) { + this.parent.addUndoableSet(p, obj); + } +} diff --git a/NET/worlds/scape/ObjPropertyEditor.java b/NET/worlds/scape/ObjPropertyEditor.java new file mode 100644 index 0000000..73f0eb4 --- /dev/null +++ b/NET/worlds/scape/ObjPropertyEditor.java @@ -0,0 +1,37 @@ +package NET.worlds.scape; + +import NET.worlds.console.PolledDialog; + +public class ObjPropertyEditor extends PropEditor { + SuperRoot root; + Class clas; + + private ObjPropertyEditor(Property property, SuperRoot r, Class clas) { + super(property); + this.root = r; + this.clas = clas; + } + + @Override + public PolledDialog edit(EditTile parent, String title) { + return new ObjEditorDialog(parent, title, this.property, this.root, this.clas); + } + + public static Property make(Property property, SuperRoot r, Class clas) { + return property.setEditor(new ObjPropertyEditor(property, r, clas)); + } + + public static Property make(Property property, SuperRoot r, String clas) { + Class c = null; + + try { + c = Class.forName(clas); + } catch (ClassNotFoundException var5) { + System.out.println("Couldn't find " + clas); + + assert false; + } + + return property.setEditor(new ObjPropertyEditor(property, r, c)); + } +} diff --git a/NET/worlds/scape/ObjectAdderDialog.java b/NET/worlds/scape/ObjectAdderDialog.java new file mode 100644 index 0000000..2b21bd0 --- /dev/null +++ b/NET/worlds/scape/ObjectAdderDialog.java @@ -0,0 +1,12 @@ +package NET.worlds.scape; + +class ObjectAdderDialog extends ObjectSelectorDialog { + ObjectAdderDialog(EditTile parent, String title, VectorProperty property, SuperRoot r, Class clas) { + super(parent, title, property, r, clas); + } + + @Override + protected void addIt(Property p, Object obj) { + this.parent.addUndoableAdd((VectorProperty)p, obj, false); + } +} diff --git a/NET/worlds/scape/ObjectPropertyAdder.java b/NET/worlds/scape/ObjectPropertyAdder.java new file mode 100644 index 0000000..3d9c13a --- /dev/null +++ b/NET/worlds/scape/ObjectPropertyAdder.java @@ -0,0 +1,42 @@ +package NET.worlds.scape; + +import NET.worlds.console.PolledDialog; + +public class ObjectPropertyAdder extends PropAdder { + SuperRoot root; + Class clas; + + private ObjectPropertyAdder(VectorProperty property, SuperRoot r, Class clas) { + super(property); + this.root = r; + this.clas = clas; + } + + @Override + public boolean hasAddDialog() { + return true; + } + + @Override + public PolledDialog add(EditTile parent, String title) { + return new ObjectAdderDialog(parent, title, this.property, this.root, this.clas); + } + + public static VectorProperty make(VectorProperty property, SuperRoot r, Class clas) { + return property.setAdder(new ObjectPropertyAdder(property, r, clas)); + } + + public static VectorProperty make(VectorProperty property, SuperRoot r, String clas) { + Class c = null; + + try { + c = Class.forName(clas); + } catch (ClassNotFoundException var5) { + System.out.println("Couldn't find " + clas); + + assert false; + } + + return property.setAdder(new ObjectPropertyAdder(property, r, c)); + } +} diff --git a/NET/worlds/scape/ObjectSelectorDialog.java b/NET/worlds/scape/ObjectSelectorDialog.java new file mode 100644 index 0000000..f02a89e --- /dev/null +++ b/NET/worlds/scape/ObjectSelectorDialog.java @@ -0,0 +1,91 @@ +package NET.worlds.scape; + +import NET.worlds.core.Std; +import java.util.Enumeration; +import java.util.Vector; + +abstract class ObjectSelectorDialog extends ListAdderDialog { + private Property property; + private Vector objectVector = null; + SuperRoot root = null; + Class clas = null; + + ObjectSelectorDialog(EditTile parent, String title, Property property, SuperRoot r, Class clas) { + super(parent, title); + this.property = property; + this.root = r; + this.clas = clas; + this.ready(); + } + + private void quicksort(String[] objectList, int l, int r) { + if (r > l) { + String v = objectList[r]; + int i = l - 1; + int j = r; + + String tstr; + Object tobj; + do { + while (objectList[++i].compareTo(v) < 0) { + } + + do { + j--; + } while (j > l && objectList[j].compareTo(v) > 0); + + tstr = objectList[i]; + objectList[i] = objectList[j]; + objectList[j] = tstr; + tobj = this.objectVector.elementAt(i); + this.objectVector.setElementAt(this.objectVector.elementAt(j), i); + this.objectVector.setElementAt(tobj, j); + } while (j > i); + + objectList[j] = objectList[i]; + objectList[i] = objectList[r]; + objectList[r] = tstr; + this.objectVector.setElementAt(this.objectVector.elementAt(i), j); + this.objectVector.setElementAt(this.objectVector.elementAt(r), i); + this.objectVector.setElementAt(tobj, r); + this.quicksort(objectList, l, i - 1); + this.quicksort(objectList, i + 1, r); + } + } + + @Override + protected void build() { + this.objectVector = new Vector(); + if (this.root != null) { + Enumeration e = this.root.getDeepOwned(); + + while (e.hasMoreElements()) { + Object obj = e.nextElement(); + if (Std.instanceOf(obj, this.clas)) { + this.objectVector.addElement(obj); + } + } + + String[] objectList = new String[this.objectVector.size()]; + + for (int i = 0; i < objectList.length; i++) { + objectList[i] = this.objectVector.elementAt(i).toString(); + } + + this.quicksort(objectList, 0, objectList.length - 1); + this.setListContents(objectList); + } + + super.build(); + } + + protected abstract void addIt(Property var1, Object var2); + + @Override + protected void add(int option) { + Object obj = this.objectVector.elementAt(option); + if (obj != null) { + this.addIt(this.property, obj); + } + } +} diff --git a/NET/worlds/scape/OpenURLAction.java b/NET/worlds/scape/OpenURLAction.java new file mode 100644 index 0000000..16449f0 --- /dev/null +++ b/NET/worlds/scape/OpenURLAction.java @@ -0,0 +1,124 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.DefaultConsole; +import NET.worlds.console.NoWebControlException; +import NET.worlds.console.WebControl; +import java.io.IOException; + +public class OpenURLAction extends Action { + String targetURL = "http://www.worlds.com"; + int xPercent = 100; + int yPercent = 100; + boolean hasToolbar = true; + boolean isFixed = false; + private static Object classCookie = new Object(); + + @Override + public Persister trigger(Event e, Persister seqID) { + if (seqID != null) { + return seqID; + } else { + Console c = Console.getActive(); + if (c != null && c instanceof DefaultConsole) { + System.out.println("Opening up a URL now."); + DefaultConsole dc = (DefaultConsole)c; + + try { + WebControl wc = new WebControl(dc.getRender(), this.xPercent, this.yPercent, this.hasToolbar, this.isFixed, false); + wc.activate(); + wc.setURL(this.targetURL); + } catch (NoWebControlException var6) { + } + + new SuperRoot(); + return this; + } else { + return null; + } + } + } + + @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 = StringPropertyEditor.make(new Property(this, index, "Target URL")); + } else if (mode == 1) { + ret = this.targetURL; + } else if (mode == 2) { + this.targetURL = (String)value; + } + break; + case 1: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "X Overlay % or Width"), 0, 1024); + } else if (mode == 1) { + ret = new Integer(this.xPercent); + } else if (mode == 2) { + this.xPercent = (Integer)value; + } + break; + case 2: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Y Overlay % or Height"), 0, 1024); + } else if (mode == 1) { + ret = new Integer(this.yPercent); + } else if (mode == 2) { + this.yPercent = (Integer)value; + } + break; + case 3: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Has Toolbar"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.hasToolbar); + } else if (mode == 2) { + this.hasToolbar = (Boolean)value; + } + break; + case 4: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Fixed size"), "No - Percentage specified", "Yes - Pixels specified"); + } else if (mode == 1) { + ret = new Boolean(this.isFixed); + } else if (mode == 2) { + this.isFixed = (Boolean)value; + } + break; + default: + ret = super.properties(index, offset + 4, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + s.saveString(this.targetURL); + s.saveInt(this.xPercent); + s.saveInt(this.yPercent); + s.saveBoolean(this.hasToolbar); + s.saveBoolean(this.isFixed); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this.targetURL = r.restoreString(); + this.xPercent = r.restoreInt(); + this.yPercent = r.restoreInt(); + this.hasToolbar = r.restoreBoolean(); + this.isFixed = r.restoreBoolean(); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/ParallelAction.java b/NET/worlds/scape/ParallelAction.java new file mode 100644 index 0000000..f2ece12 --- /dev/null +++ b/NET/worlds/scape/ParallelAction.java @@ -0,0 +1,140 @@ +package NET.worlds.scape; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.Vector; + +public class ParallelAction extends Action implements RunningActionCallback { + protected static final int NONE = 0; + protected static final int FIRST = 1; + protected static final int ALL = -1; + protected Vector actions = new Vector(); + protected int waitState = -1; + protected int waitingFor = 0; + protected Object currentRun = null; + private static Object classCookie = new Object(); + + @Override + public Persister trigger(Event evt, Persister seqID) { + if (seqID == null) { + if (this.waitingFor == 0) { + this.currentRun = new Object(); + if (this.waitState == -1) { + this.waitingFor = this.actions.size(); + seqID = this; + } else if (this.waitState == 1) { + this.waitingFor = 1; + seqID = this; + } else { + this.waitingFor = 0; + seqID = null; + } + + RunningActionHandler.trigger(this.actions, this.getWorld(), evt, this, this.currentRun); + } + } else if (this.waitingFor == 0) { + seqID = null; + } + + return seqID; + } + + @Override + public void actionDone(Action a, Event e, Object o) { + if (this.waitingFor > 0 && o == this.currentRun) { + this.waitingFor--; + } + } + + public void setWaitForAll() { + this.waitState = -1; + } + + public void setWaitForFirst() { + this.waitState = 1; + } + + public void setWaitForNone() { + this.waitState = 0; + } + + public void addComponent(Action act) { + assert act != null; + + this.actions.addElement(act); + } + + public void insertComponent(Action act, int index) { + assert act != null; + + this.actions.insertElementAt(act, index); + } + + public boolean removeComponent(Action act) { + assert act != null; + + return this.actions.removeElement(act); + } + + public Enumeration getComponents() { + return this.actions.elements(); + } + + @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 = ObjectPropertyAdder.make(new VectorProperty(this, index, "Components"), this.getRoot(), "NET.worlds.scape.Action"); + } else if (mode == 1) { + ret = this.actions.clone(); + } else if (mode == 4) { + this.actions.removeElement(value); + } else if (mode == 3) { + this.actions.addElement((Action)value); + } + break; + case 1: + if (mode == 0) { + String[] names = new String[]{"None", "First", "All"}; + int[] values = new int[]{0, 1, -1}; + ret = EnumPropertyEditor.make(new Property(this, index, "Wait for"), names, values); + } else if (mode == 1) { + ret = new Integer(this.waitState); + } else if (mode == 2) { + this.waitState = (Integer)value; + } + break; + default: + ret = super.properties(index, offset + 2, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(2, classCookie); + super.saveState(s); + s.saveVector(this.actions); + s.saveInt(this.waitState); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 1: + super.restoreState(r); + this.actions = r.restoreVector(); + break; + case 2: + super.restoreState(r); + this.actions = r.restoreVector(); + this.waitState = r.restoreInt(); + break; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/PassthroughBumpCalc.java b/NET/worlds/scape/PassthroughBumpCalc.java new file mode 100644 index 0000000..9490684 --- /dev/null +++ b/NET/worlds/scape/PassthroughBumpCalc.java @@ -0,0 +1,33 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class PassthroughBumpCalc extends BumpCalc { + private static Object classCookie = new Object(); + + @Override + public void detectBump(BumpEventTemp b, WObject owner) { + Transform xfrm = owner.getObjectToWorldMatrix(); + Point3Temp start = xfrm.getPosition(); + Point3Temp d = owner.getPlaneExtent().vectorTimes(xfrm); + xfrm.recycle(); + b.hitPlane(owner, start, d); + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/PasteWidget.java b/NET/worlds/scape/PasteWidget.java new file mode 100644 index 0000000..a1b89b8 --- /dev/null +++ b/NET/worlds/scape/PasteWidget.java @@ -0,0 +1,14 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; + +class PasteWidget extends ClickWidget { + public PasteWidget(ToolBar toolbar) { + super(toolbar, "paste.gif", Console.message("Paste")); + } + + @Override + public void perform() { + Console.getFrame().getEditTile().paste(); + } +} diff --git a/NET/worlds/scape/PathMoveAction.java b/NET/worlds/scape/PathMoveAction.java new file mode 100644 index 0000000..39645e2 --- /dev/null +++ b/NET/worlds/scape/PathMoveAction.java @@ -0,0 +1,24 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class PathMoveAction extends Action { + private static Object classCookie = new Object(); + + @Override + public Persister trigger(Event e, Persister seqID) { + return null; + } + + @Override + public void saveState(Saver s) throws IOException { + assert false; + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + MoveAction a = new MoveAction(); + r.replace(this, a); + a.restoreStateMoveActionHelper(r, classCookie); + } +} diff --git a/NET/worlds/scape/PendingCacheDrone.java b/NET/worlds/scape/PendingCacheDrone.java new file mode 100644 index 0000000..550b8ef --- /dev/null +++ b/NET/worlds/scape/PendingCacheDrone.java @@ -0,0 +1,66 @@ +package NET.worlds.scape; + +import NET.worlds.core.IniFile; +import NET.worlds.network.Cache; +import NET.worlds.network.CacheFile; +import NET.worlds.network.NetUpdate; +import NET.worlds.network.URL; + +public class PendingCacheDrone extends PendingDrone { + static String upgradeDir = IniFile.gamma().getIniString("avatarDir", "avatar/"); + + static { + if (!upgradeDir.endsWith("/")) { + upgradeDir = upgradeDir + "/"; + } + + nativeInit(); + } + + public PendingCacheDrone(PosableDrone _drone, URL _url) { + super(_drone, _url); + } + + @Override + public synchronized void download(URL avURL) { + } + + public static native void nativeInit(); + + public static native void nativeDestroy(); + + public static synchronized native void notifySeqLoaded(int var0, String var1); + + public static void downloadSeqFile(String seqFileName, boolean force, int nativeNotifyObject) { + seqFileName = seqFileName.toLowerCase(); + if (!PosableDroneLoader.usingCache()) { + notifySeqLoaded(nativeNotifyObject, ".\\avatars\\" + seqFileName); + } else { + String path = NetUpdate.getUpgradeServerURL() + upgradeDir + seqFileName; + if (force) { + CacheFile cf = Cache.getFile(URL.make(path)); + cf.waitUntilLoaded(); + if (cf.error()) { + return; + } + + notifySeqLoaded(nativeNotifyObject, cf.getLocalName()); + } else { + new SeqFile(nativeNotifyObject, URL.make(path)); + } + } + } + + public static String getAvatarDatPath() { + if (!PosableDroneLoader.usingCache()) { + return ".\\avatars\\avatars.dat"; + } else if (IniFile.gamma().getIniInt("localavatarsdat", 0) == 1) { + return ".\\avatars\\avatars.dat"; + } else { + String datURL = NetUpdate.getUpgradeServerURL() + upgradeDir + "avatars.dat"; + CacheFile cf = Cache.getFile(URL.make(datURL)); + cf.waitUntilLoaded(); + return cf.error() ? null : cf.getLocalName(); + } + } +} diff --git a/NET/worlds/scape/PendingDrone.java b/NET/worlds/scape/PendingDrone.java new file mode 100644 index 0000000..105851f --- /dev/null +++ b/NET/worlds/scape/PendingDrone.java @@ -0,0 +1,303 @@ +package NET.worlds.scape; + +import NET.worlds.core.Archive; +import NET.worlds.core.IniFile; +import NET.worlds.network.Cache; +import NET.worlds.network.CacheFile; +import NET.worlds.network.NetUpdate; +import NET.worlds.network.URL; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.util.Enumeration; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; + +public class PendingDrone { + static boolean doAvatarUpdates = true; + protected PosableDrone drone; + protected URL url; + protected boolean loaded; + static final boolean debug = false; + + static { + doAvatarUpdates = IniFile.gamma().getIniInt("noAvUpdates", 0) == 0; + } + + PendingDrone(PosableDrone _drone, URL _url) { + this.drone = _drone; + this.url = _url; + this.loaded = false; + } + + public PosableDrone getDrone() { + return this.drone; + } + + public URL getUrl() { + return this.url; + } + + public boolean getLoaded() { + return this.loaded; + } + + public void setLoaded() { + this.loaded = true; + } + + public synchronized void download(URL avURL) { + if (doAvatarUpdates) { + if (avURL != null) { + try { + if (PosableDroneLoader.avatarExistsLocally(avURL)) { + return; + } + } catch (MalformedURLException var5) { + return; + } + + String s = PosableDroneLoader.getAvatarBaseName(avURL); + + assert s != null; + + s = s.toLowerCase(); + URL realFile = URL.make(NetUpdate.getUpgradeServerURL() + "AvatarUpgrades/" + s + ".zip"); + CacheFile cf = Cache.getFile(realFile); + cf.waitUntilLoaded(); + if (!cf.error()) { + this.finishDownload(cf.getLocalName()); + cf.close(); + } + } + } + } + + public synchronized boolean finishDownload(String localName) { + ZipFile patchArchive; + try { + patchArchive = new ZipFile(localName); + } catch (IOException var11) { + this.notify(); + return false; + } + + Enumeration enums = patchArchive.entries(); + + while (enums.hasMoreElements()) { + ZipEntry ze = (ZipEntry)enums.nextElement(); + String filename = ze.getName(); + String avatarFile = URL.homeUnalias("avatars/" + filename); + String[] validExtensions = new String[]{".bod", ".seq", ".dat", ".cmp", ".mov"}; + boolean validFile = false; + + for (int idx = 0; idx < validExtensions.length; idx++) { + if (avatarFile.toString().endsWith(validExtensions[idx])) { + validFile = true; + break; + } + } + + if (validFile) { + if (avatarFile.toString().endsWith("avatars.dat")) { + avatarFile = URL.homeUnalias("avatars/avatars.tmp"); + this.CopyAvatarFile(patchArchive, ze, avatarFile); + this.AppendAvatarsDat(); + } else { + this.CopyAvatarFile(patchArchive, ze, avatarFile); + } + } + } + + try { + patchArchive.close(); + } catch (IOException var10) { + } + + this.notify(); + return false; + } + + public Room getBackgroundLoadRoom() { + return this.drone != null && this.drone.getOwner() != null ? this.drone.getOwner().getRoom() : null; + } + + private void AppendAvatarsDat() { + String contentZip = URL.homeUnalias("avatars/content.zip"); + Archive.flushAll(); + + ZipFile contentZipArchive; + try { + contentZipArchive = new ZipFile(contentZip); + } catch (IOException var12) { + contentZipArchive = null; + } + + if (contentZipArchive != null) { + ZipEntry origAvatarDat = contentZipArchive.getEntry("avatars.dat"); + if (origAvatarDat != null) { + this.CopyAvatarFile(contentZipArchive, origAvatarDat, URL.homeUnalias("avatars/avatars.dat")); + this.StripAvatarDat(contentZipArchive); + } else { + try { + contentZipArchive.close(); + } catch (IOException var11) { + } + } + } + + FileOutputStream avDat; + try { + avDat = new FileOutputStream(URL.homeUnalias("avatars/avatars.dat"), true); + } catch (IOException var10) { + System.out.println(var10); + return; + } + + FileInputStream avTmp; + try { + avTmp = new FileInputStream(URL.homeUnalias("avatars/avatars.tmp")); + } catch (FileNotFoundException var9) { + try { + avDat.close(); + } catch (IOException var7) { + } + + return; + } + + byte[] buf = new byte[1024]; + + while (true) { + try { + int bytesRead = avTmp.read(buf); + if (bytesRead == -1) { + break; + } + + avDat.write(buf, 0, bytesRead); + } catch (IOException var13) { + break; + } + } + + try { + avDat.close(); + avTmp.close(); + } catch (IOException var8) { + } + + File avTmpFile = new File(URL.homeUnalias("avatars/avatars.tmp")); + avTmpFile.delete(); + DroneAnimator.loadconfig(URL.make("home:avatars/avatars.dat").unalias()); + } + + private void StripAvatarDat(ZipFile contentZipArchive) { + FileOutputStream os; + try { + os = new FileOutputStream(URL.homeUnalias("avatars/content.tmp")); + } catch (IOException var13) { + return; + } + + ZipOutputStream zs = new ZipOutputStream(os); + Enumeration enums = contentZipArchive.entries(); + + while (enums.hasMoreElements()) { + ZipEntry ze = (ZipEntry)enums.nextElement(); + String filename = ze.getName(); + if (!filename.equals("avatars.dat")) { + try { + InputStream is = contentZipArchive.getInputStream(ze); + ZipEntry ze2 = new ZipEntry(ze.getName()); + zs.putNextEntry(ze2); + byte[] buffer = new byte[1024]; + + while (true) { + try { + int bytesRead = is.read(buffer); + if (bytesRead != -1) { + zs.write(buffer, 0, bytesRead); + continue; + } + } catch (IOException var14) { + System.out.println("IOException " + ze.getName() + " " + var14.getMessage()); + } + + zs.closeEntry(); + is.close(); + break; + } + } catch (IOException var15) { + System.out.println("IOException 2 " + var15.getMessage()); + } + } + } + + try { + contentZipArchive.close(); + zs.close(); + } catch (IOException var12) { + System.out.println("Error closing zip files " + var12); + } + + File origFile = new File(URL.homeUnalias("avatars/content.zip")); + File newFile = new File(URL.homeUnalias("avatars/content.tmp")); + File oldFile = new File(URL.homeUnalias("avatars/content.old")); + Archive.flushAll(); + + try { + boolean b = origFile.renameTo(oldFile); + b = newFile.renameTo(origFile); + } catch (Exception var11) { + System.out.println(var11); + } + } + + private void CopyAvatarFile(ZipFile patchArchive, ZipEntry ze, String avatarFile) { + InputStream is; + try { + is = patchArchive.getInputStream(ze); + } catch (IOException var11) { + return; + } + + FileOutputStream os; + try { + os = new FileOutputStream(avatarFile); + } catch (IOException var10) { + try { + is.close(); + } catch (IOException var8) { + } + + return; + } + + byte[] buffer = new byte[1024]; + + while (true) { + try { + int bytesRead = is.read(buffer); + if (bytesRead == -1) { + break; + } + + os.write(buffer, 0, bytesRead); + } catch (IOException var12) { + break; + } + } + + try { + is.close(); + os.close(); + } catch (IOException var9) { + } + } +} diff --git a/NET/worlds/scape/PeriodicTimeSensor.java b/NET/worlds/scape/PeriodicTimeSensor.java new file mode 100644 index 0000000..d76e431 --- /dev/null +++ b/NET/worlds/scape/PeriodicTimeSensor.java @@ -0,0 +1,80 @@ +package NET.worlds.scape; + +import NET.worlds.core.Std; +import java.io.IOException; + +public class PeriodicTimeSensor extends Sensor implements FrameHandler { + private float timeInterval = 1.0F; + private long lastTrigger; + private static Object classCookie = new Object(); + + public PeriodicTimeSensor(Action act) { + if (act != null) { + this.addAction(act); + } + } + + public PeriodicTimeSensor() { + } + + @Override + public boolean handle(FrameEvent e) { + long now = 0L; + if (e == null) { + now = Std.getFastTime(); + } else { + now = e.time; + } + + if (now - this.lastTrigger > (long)(1000.0F * this.timeInterval)) { + this.lastTrigger = now; + this.trigger(e); + } + + return true; + } + + @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 = FloatPropertyEditor.make(new Property(this, index, "Time Interval (s)")); + } else if (mode == 1) { + ret = new Float(this.timeInterval); + } else if (mode == 2) { + this.timeInterval = (Float)value; + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + super.saveState(s); + s.saveFloat(this.timeInterval); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 1: + super.restoreState(r); + this.timeInterval = r.restoreFloat(); + return; + default: + throw new TooNewException(); + } + } + + @Override + public String toString() { + return "*every " + this.timeInterval + " s"; + } +} diff --git a/NET/worlds/scape/Persister.java b/NET/worlds/scape/Persister.java new file mode 100644 index 0000000..31a45c4 --- /dev/null +++ b/NET/worlds/scape/Persister.java @@ -0,0 +1,11 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public interface Persister { + void saveState(Saver var1) throws IOException; + + void restoreState(Restorer var1) throws IOException, TooNewException; + + void postRestore(int var1); +} diff --git a/NET/worlds/scape/PickEvent.java b/NET/worlds/scape/PickEvent.java new file mode 100644 index 0000000..342879b --- /dev/null +++ b/NET/worlds/scape/PickEvent.java @@ -0,0 +1,19 @@ +package NET.worlds.scape; + +public class PickEvent extends UserEvent { + public float x; + public float y; + public float z; + + public PickEvent(int time, WObject target, float _x, float _y, float _z) { + super(time, null, target); + this.x = _x; + this.y = _y; + this.z = _z; + } + + @Override + public boolean deliver(Object o) { + return o instanceof PickHandler && ((PickHandler)o).handle(this) ? true : super.deliver(o); + } +} diff --git a/NET/worlds/scape/PickHandler.java b/NET/worlds/scape/PickHandler.java new file mode 100644 index 0000000..14a97b0 --- /dev/null +++ b/NET/worlds/scape/PickHandler.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface PickHandler { + boolean handle(PickEvent var1); +} diff --git a/NET/worlds/scape/PickUpAction.java b/NET/worlds/scape/PickUpAction.java new file mode 100644 index 0000000..bd4b5cb --- /dev/null +++ b/NET/worlds/scape/PickUpAction.java @@ -0,0 +1,33 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class PickUpAction extends Action { + private static Object classCookie = new Object(); + + @Override + public Persister trigger(Event arg, Persister seqID) { + WObject w = (WObject)this.getOwner(); + w.detach(); + w.raise(-Pilot.getActive().getZ()); + Pilot.getActive().add(w); + return null; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/Pilot.java b/NET/worlds/scape/Pilot.java new file mode 100644 index 0000000..6e60dc7 --- /dev/null +++ b/NET/worlds/scape/Pilot.java @@ -0,0 +1,853 @@ +package NET.worlds.scape; + +import NET.worlds.console.AdPart; +import NET.worlds.console.BBAnimateDroneCommand; +import NET.worlds.console.BBMoveDroneCommand; +import NET.worlds.console.BBTeleportCommand; +import NET.worlds.console.BlackBox; +import NET.worlds.console.Console; +import NET.worlds.console.FramePart; +import NET.worlds.console.RenderCanvas; +import NET.worlds.core.Std; +import NET.worlds.network.Galaxy; +import NET.worlds.network.InfiniteWaitException; +import NET.worlds.network.NetworkObject; +import NET.worlds.network.OldPropertyList; +import NET.worlds.network.PacketTooLargeException; +import NET.worlds.network.PropertyList; +import NET.worlds.network.PropertySetCmd; +import NET.worlds.network.URL; +import NET.worlds.network.WorldServer; +import NET.worlds.network.longLocCmd; +import NET.worlds.network.net2Property; +import NET.worlds.network.netPacket; +import NET.worlds.network.roomChangeCmd; +import NET.worlds.network.teleportCmd; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Vector; + +public abstract class Pilot extends WObject implements NetworkObject, BumpHandler { + static Vector<Room> visibleRooms = new Vector<Room>(); + static Vector<RoomSubscribeInfo> visibleRoomInfo = new Vector<RoomSubscribeInfo>(); + int lastUpdateTime; + private static Vector<Room> nextVisibleRooms = new Vector<Room>(); + private static Vector<RoomSubscribeInfo> nextVisibleRoomInfo = new Vector<RoomSubscribeInfo>(); + int positionSentTime; + short lastx; + short lasty; + short lastz; + short lastdir; + Room lastroom; + Room lastFrameRoom; + private static Vector<Room> subscribers = new Vector<Room>(); + private static int lastWarning; + private static Pilot active; + protected int cameraMode = 0; + protected int cameraSpeed = 0; + private static World lastWorld = null; + private Camera lastCam; + protected Console console; + private static Object classCookie = new Object(); + + static { + nativeInit(); + } + + public static native void nativeInit(); + + public float animate(String action) { + action = action.toLowerCase(); + BlackBox.getInstance().submitEvent(new BBAnimateDroneCommand("@Pilot", action)); + if (action.equals("sleep") || action.equals("s")) { + Console console = Console.getActive(); + if (console != null) { + console.goToSleep(); + } + } else if (this == getActive()) { + sendText("&|+action>" + action); + } + + return 0.0F; + } + + public Vector<String> getAnimationList() { + Vector<String> v = new Vector<String>(); + v.addElement("sleep"); + return v; + } + + public void setSleepMode(String mode) { + } + + public static void load(URL url, WobLoaded callback) { + if (!url.endsWith(".mov") && !url.endsWith(".rwx") && !url.endsWith(".rwg")) { + String s = url.getInternal(); + if (s.endsWith(".drone")) { + s = s.substring(0, s.length() - 6) + ".pilot"; + } else if (!s.endsWith(".pilot")) { + s = s + ".pilot"; + } + + new WobLoader(URL.make(s), callback); + } else { + callback.wobLoaded(null, new HoloPilot(url)); + } + } + + public void addInventory(WObject child) throws ClassCastException { + assert child.isDynamic(); + + this.add(child); + } + + public void addInSlot(WObject child, int slot) { + assert child.isDynamic(); + + Sharer s = this.getSharer(); + if (s.getAttribute(slot) != null) { + System.out.println("Attempting to add a second object (" + child.getName() + ") to slot number " + slot); + } else { + s.moveToSlot(child, slot); + } + } + + @Override + public void add(WObject w) { + super.add(w); + } + + public float distToVisibleObject(WObject w) { + return this.distToVisiblePoint(w.getRoom(), w.getWorldPosition()); + } + + public void aboutToDraw() { + } + + public float distToVisiblePoint(Room r, Point3Temp pos) { + if (r == null) { + return 0.0F; + } else { + int i = visibleRooms.indexOf(r); + if (i == -1) { + return 0.0F; + } else { + RoomSubscribeInfo rsi = visibleRoomInfo.elementAt(i); + return rsi.d == 0.0F ? pos.minus(this.getWorldPosition()).length() : pos.minus(Point3Temp.make(rsi.x, rsi.y, rsi.z)).length() + rsi.d; + } + } + } + + public static void addVisibleRoom(Room r, float x, float y, float z, float d) { + r.noteRef(); + int i = nextVisibleRooms.indexOf(r); + if (i == -1) { + nextVisibleRooms.addElement(r); + nextVisibleRoomInfo.addElement(new RoomSubscribeInfo(x, y, z, d)); + } else { + RoomSubscribeInfo info = nextVisibleRoomInfo.elementAt(i); + if (d < info.d) { + info.x = x; + info.y = y; + info.z = z; + info.d = d; + } + } + } + + public void generateFrameEvents(FrameEvent f) { + Room currentRoom = this.getRoom(); + if (currentRoom != null) { + addVisibleRoom(currentRoom, 0.0F, 0.0F, 0.0F, 0.0F); + } + + synchronized (visibleRooms) { + Vector<RoomSubscribeInfo> t = visibleRoomInfo; + visibleRoomInfo = nextVisibleRoomInfo; + nextVisibleRoomInfo = t; + Vector<Room> j = nextVisibleRooms; + nextVisibleRooms = visibleRooms; + visibleRooms = j; + } + + Vector<Room> prevVisibleRooms = nextVisibleRooms; + Object oldEventSource = f.source; + f.source = this; + int i = visibleRooms.size(); + + while (--i >= 0) { + Room r = visibleRooms.elementAt(i); + r.generateFrameEvents(f); + prevVisibleRooms.removeElement(r); + } + + i = prevVisibleRooms.size(); + + while (--i >= 0) { + prevVisibleRooms.elementAt(i).generateFrameEvents(f); + } + + nextVisibleRooms.removeAllElements(); + nextVisibleRoomInfo.removeAllElements(); + i = f.time - this.lastUpdateTime; + if (i > 500) { + this.subscribeRooms(); + boolean hasMoved = this.pilotUpdate(f.time); + this.subscriptionUpdate(hasMoved); + this.updateUnsubscribes(); + this.lastUpdateTime = f.time; + } + + this.touchSubscribers(); + f.source = oldEventSource; + } + + public static void sendText(String msg) { + sendText(null, msg); + } + + public static boolean containsWord(String word, String msg) { + int i = -1; + + while ((i = msg.indexOf(word, i + 1)) >= 0) { + if (i == 0 || !Character.isLetter(msg.charAt(i - 1))) { + int end = i + word.length(); + if (end >= msg.length() || !Character.isLetter(msg.charAt(end))) { + return true; + } + } + } + + return false; + } + + public static void sendText(String who, String msg) { + WorldServer server = active.getServer(); + if (server != null) { + if (msg.contains("&|+action>")) { + PropertyList propList = new PropertyList(); + String strUrl = getActive().getSourceURL().getAbsolute(); + strUrl = strUrl + "#" + msg.substring(msg.indexOf(">") + 1, msg.length()); + propList.addProperty(new net2Property(5, 64, 1, strUrl)); + + try { + server.sendNetworkMsg(new PropertySetCmd(propList)); + } catch (PacketTooLargeException var7) { + } catch (InfiniteWaitException var8) { + } + } + + server.sendText(who, msg); + if ((containsWord("brb", msg) || containsWord("ggp", msg)) && Console.getActive() != null) { + Console.getActive().goToSleep(); + } + + int i = msg.indexOf(42); + + int next; + while (i >= 0 && (next = msg.indexOf(42, i + 1)) > i) { + int space = msg.indexOf(32, i); + if (next > i + 1 && (space == -1 || space > next)) { + String act = msg.substring(i + 1, next).toLowerCase(); + if (who == null && active != null) { + active.animate(act); + } else { + sendText(who, "&|+action>" + act); + } + } + + i = next; + } + } else if (!msg.startsWith("&|+")) { + Console.println(Console.message("No-server-connect")); + } + } + + private static float round(float x, float mul) { + return mul * Math.round(x / mul); + } + + public String getWorldRoomChannel(Room room) { + if (room == null) { + return null; + } else { + World world = room.getWorld(); + if (world == null) { + return null; + } else { + URL url = world.getSourceURL(); + if (url == null) { + return null; + } else { + String newURL = url.getAbsolute(); + Galaxy g = room.getGalaxy(); + String channelPart = g.getChannel(); + return newURL + "#" + room.getName() + "<" + channelPart + ">"; + } + } + } + } + + public String getURL() { + Room room = this.getRoom(); + String newURL = this.getWorldRoomChannel(room); + if (newURL == null) { + return null; + } else { + Point3Temp pos = this.getPosition(); + float val = round(pos.x, 1.0F); + newURL = newURL + "@" + val; + val = round(pos.y, 1.0F); + newURL = newURL + "," + val; + val = round(pos.z, 1.0F); + newURL = newURL + "," + val; + Point3Temp camAxis = Point3Temp.make(); + val = round(this.getSpin(camAxis), 1.0F); + newURL = newURL + "," + val; + val = round(camAxis.x, 0.001F); + newURL = newURL + "," + val; + val = round(camAxis.y, 0.001F); + newURL = newURL + "," + val; + val = round(camAxis.z, 0.001F); + return newURL + "," + val; + } + } + + public String getTeleportURL() { + Camera tester = new Camera(); + Room room = this.getRoom(); + if (room == null) { + return null; + } else { + room.add(tester); + tester.yaw(220.0F); + tester.post(this); + boolean pBumpable = this.getBumpable(); + this.setBumpable(false); + Transform t = tester.getObjectToWorldMatrix(); + tester.moveThrough(Point3Temp.make(0.0F, -170.0F, 0.0F).times(t).minus(t.getPosition())); + t.recycle(); + this.setBumpable(pBumpable); + room = tester.getRoom(); + tester.detach(); + String wrc = this.getWorldRoomChannel(room); + if (wrc == null) { + return null; + } else { + Point3Temp pos = tester.getPosition(); + return wrc + "@" + (int)pos.x + "," + (int)pos.y + "," + (int)pos.z + "," + (int)tester.getYaw(); + } + } + } + + public Room getLastServedRoom() { + return this.lastroom; + } + + public float getFootHeight() { + return 0.0F; + } + + private static void sendToRoom(Room r, netPacket msg) { + if (r != null) { + synchronized (r) { + WorldServer s = r.getServer(); + if (s != null) { + try { + s.sendNetworkMsg(msg); + } catch (InfiniteWaitException var5) { + } catch (PacketTooLargeException var6) { + } + } + } + } + } + + private boolean validRoom(Room r) { + return r == null || r.getNetworkRoom().getRoomID() != 0; + } + + public boolean pilotUpdate(int t) { + Point3Temp pos = this.getPosition(); + short x = (short)pos.x; + short y = (short)pos.y; + short z = (short)this.getFootHeight(); + short dir = (short)(-this.getYaw() + 90.0F); + dir = (short)(dir % 360); + + while (dir < 0) { + dir = (short)(dir + 360); + } + + Room room = this.getRoom(); + if (room != this.lastFrameRoom) { + BlackBox.getInstance().submitEvent(new BBTeleportCommand(this.getURL())); + this.lastFrameRoom = this.getRoom(); + } + + if (room != null && !room.getNetworkRoom().isServed()) { + room = null; + } + + if (this.lastroom != null && !this.lastroom.getNetworkRoom().isServed()) { + this.lastroom = null; + } + + int diffTime = t - this.positionSentTime; + if (x == this.lastx && y == this.lasty && z == this.lastz && dir == this.lastdir && diffTime <= 40000 && room == this.lastroom) { + return false; + } else { + BlackBox.getInstance().submitEvent(new BBMoveDroneCommand("@Pilot", x, y, z, dir)); + if (room != this.lastroom && this.validRoom(room) && this.validRoom(this.lastroom)) { + Galaxy lrGalaxy = null; + Galaxy rGalaxy = null; + if (room != null) { + rGalaxy = room.getGalaxy(); + } + + if (this.lastroom != null) { + lrGalaxy = this.lastroom.getGalaxy(); + } + + if (rGalaxy != lrGalaxy) { + if (room != null) { + sendToRoom(room, new teleportCmd(room, (byte)0, (byte)1, x, y, z, dir)); + BlackBox.getInstance().submitEvent(new BBTeleportCommand(this.getURL())); + } + + if (this.lastroom != null) { + sendToRoom(this.lastroom, new teleportCmd(null, (byte)1, (byte)0, x, y, z, dir)); + } + + BlackBox.getInstance().submitEvent(new BBTeleportCommand(this.getURL())); + } else if (room.getServer() != this.lastroom.getServer()) { + if (room != null) { + sendToRoom(room, new teleportCmd(room, (byte)0, (byte)1, x, y, z, dir)); + BlackBox.getInstance().submitEvent(new BBTeleportCommand(this.getURL())); + } + + if (this.lastroom != null) { + sendToRoom(this.lastroom, new teleportCmd(null, (byte)1, (byte)0, x, y, z, dir)); + } + } else { + sendToRoom(this.lastroom, new roomChangeCmd(room, x, y, z, dir)); + BlackBox.getInstance().submitEvent(new BBTeleportCommand(this.getURL())); + } + + this.lastroom = room; + } else if (room != null) { + sendToRoom(room, new longLocCmd(x, y, z, dir)); + } + + this.positionSentTime = t; + this.lastx = x; + this.lasty = y; + this.lastz = z; + this.lastdir = dir; + return true; + } + } + + private void updateUnsubscribes() { + int i = subscribers.size(); + + while (--i >= 0) { + if (!visibleRooms.contains(subscribers.elementAt(i))) { + subscribers.elementAt(i).unsubscribe(); + subscribers.removeElementAt(i); + } + } + } + + public void subscribeRooms() { + int i = visibleRooms.size(); + + while (--i >= 0) { + Room r = visibleRooms.elementAt(i); + if (!subscribers.contains(r)) { + RoomSubscribeInfo newInfo = visibleRoomInfo.elementAt(i); + r.subscribe(newInfo); + } + } + } + + public boolean removeSubscribedRoom(Room suspect) { + int i = subscribers.size(); + + while (--i >= 0) { + if (subscribers.elementAt(i) == suspect) { + subscribers.removeElementAt(i); + return true; + } + } + + return false; + } + + public void touchSubscribers() { + int i = subscribers.size(); + + while (--i >= 0) { + subscribers.elementAt(i).noteRef(); + } + } + + private void subscriptionUpdate(boolean hasMoved) { + Room camRoom = this.getRoom(); + int i = visibleRooms.size(); + + while (--i >= 0) { + Room r = visibleRooms.elementAt(i); + + assert r.getNetworkRoom() != null; + + RoomSubscribeInfo newInfo = visibleRoomInfo.elementAt(i); + if (!subscribers.contains(r)) { + subscribers.addElement(r); + } else if (hasMoved && r.getNetworkRoom().isServed() && r != camRoom) { + r.subscribeDist(newInfo); + } + } + } + + @Override + public void property(OldPropertyList propList) { + } + + @Override + public void propertyUpdate(PropertyList propList) { + } + + @Override + public void register() { + } + + @Override + public void galaxyDisconnected() { + } + + @Override + public void reacquireServer(WorldServer oldServ) { + } + + @Override + public void changeChannel(Galaxy g, String oldChannel, String newChannel) { + sendToRoom(this.lastroom, new teleportCmd(null, (byte)1, (byte)0, this.lastx, this.lasty, this.lastz, this.lastdir)); + BlackBox.getInstance().submitEvent(new BBTeleportCommand(this.getURL())); + this.lastroom = null; + } + + @Override + public WorldServer getServer() { + Room r = this.getLastServedRoom(); + if (r != null) { + return r.getServer(); + } else { + return this.console == null ? null : this.console.getServerNew(); + } + } + + @Override + public String getLongID() { + return this.console != null ? this.console.getGalaxy().getChatname() : null; + } + + @Override + public WObject changeRoom(Room newRoom, Transform invPos) { + assert this == active; + + if (newRoom.getVIPOnly() && !newRoom.getWorld().getConsole().getVIP()) { + int now = Std.getFastTime(); + if (now > lastWarning + 3000) { + lastWarning = now; + Console.println(Console.message("Only-VIPs-here")); + } + + return null; + } else { + Room oldRoom = getActiveRoom(); + if (oldRoom != null) { + oldRoom.removePostrenderHandler(BlackBox.getInstance()); + oldRoom.removeFrameHandler(BlackBox.getInstance(), null); + } + + WObject p = changeActiveRoom(newRoom); + p.makeIdentity(); + p.pre(invPos); + if (oldRoom != null) { + oldRoom.move(oldRoom, newRoom); + } + + if (newRoom != null) { + newRoom.move(oldRoom, newRoom); + } + + return p; + } + } + + public static Pilot getActive() { + return active; + } + + public void setOutsideCameraMode(int camMode, int camSpeed) { + this.cameraMode = camMode; + this.cameraSpeed = camSpeed; + if (this.getMainCamera() != null) { + this.getMainCamera().lookAround.makeIdentity(); + } + } + + public int getOutsideCameraMode() { + return this.cameraMode; + } + + public int getOutsideCameraSpeed() { + return this.cameraSpeed; + } + + public static Room getActiveRoom() { + return active == null ? null : active.getRoom(); + } + + public static World getActiveWorld() { + return active == null ? null : active.getWorld(); + } + + public abstract void resetAvatarNow(); + + public static Pilot changeActiveRoom(Room newRoom) { + BackgroundLoader.activeRoomChanged(newRoom); + Console oldc = Console.getActive(); + Console newc = oldc; + if (newRoom != null) { + newc = newRoom.getWorld().getConsole(); + } + + Pilot p = newc.getPilot(); + if (p != active) { + p.transferFrom(active); + if (newRoom != null && active != null && newRoom == active.getRoom()) { + p.makeIdentity().post(active); + } + } + + if (oldc != newc) { + newc.forPilotOnlyActivate(); + } + + if (oldc != null) { + active.detach(); + } + + active = p; + p.setUpCameras(newc); + if (newRoom != null) { + newRoom.add(p); + } + + active.resetAvatarNow(); + newc.checkCourtesyVIP(); + if (active.getWorld() != lastWorld) { + lastWorld = active.getWorld(); + newc.displayAds(); + WorldScriptManager.getInstance().worldEntered(lastWorld.toString()); + } + + WorldScriptManager.getInstance().roomEntered(newRoom.toString()); + newRoom.addPostrenderHandler(BlackBox.getInstance()); + newRoom.addFrameHandler(BlackBox.getInstance(), null); + return active; + } + + public void changeChannel(String newChannel) { + Galaxy g = this.console.getGalaxy(); + g.changeChannel(newChannel); + } + + private void setUpCameras(Console c) { + Enumeration<Camera> camList = (Enumeration<Camera>)this.getContents(); + Enumeration<FramePart> e = c.getParts(); + + while (e.hasMoreElements()) { + Object o = e.nextElement(); + if (o instanceof RenderCanvas && !(o instanceof AdPart)) { + ((RenderCanvas)o).setCamera(getNextCamera(camList)); + } + } + } + + public Camera getMainCamera() { + if (this.lastCam != null) { + SuperRoot o = this.lastCam.getOwner(); + if (o == this || o != null && o.getOwner() == this) { + return this.lastCam; + } + } + + return this.lastCam = getNextCamera(new DeepEnumeration<Camera>((Enumeration<Camera>)this.getContents())); + } + + private static Camera getNextCamera(Enumeration<Camera> list) { + while (list.hasMoreElements()) { + Object o = list.nextElement(); + if (o instanceof Camera) { + return (Camera)o; + } + } + + return null; + } + + protected void transferFrom(Pilot old) { + if (old != null) { + this.lastx = old.lastx; + this.lasty = old.lasty; + this.lastz = old.lastz; + this.lastdir = old.lastdir; + this.lastroom = old.lastroom; + this.positionSentTime = old.positionSentTime; + Enumeration<Object> ehs = this.getHandlers(); + + while (ehs.hasMoreElements()) { + Object eh = ehs.nextElement(); + if (eh instanceof MomentumBehavior) { + ((MomentumBehavior)eh).transferFrom(old.getHandlers()); + } + } + + this.getMainCamera().transferFrom(old.getMainCamera()); + } + } + + @Override + public boolean handle(BumpEventTemp b) { + this.slideBumpHandler(b); + return true; + } + + public void slideBumpHandler(BumpEventTemp b) { + if (b.receiver == b.source) { + Point3Temp bumpNormal = Point3Temp.make(b.bumpNormal).normalize(); + b.postBumpPath.minus(Point3Temp.make(bumpNormal).times(b.postBumpPath.dot(bumpNormal))); + b.postBumpPath.plus(Point3Temp.make(b.bumpNormal).times(1.0E-6F)); + } + } + + @Override + public void makeShadow() { + } + + public void setConsole(Console c) { + assert this.console == null; + + this.console = c; + copySoul(c.getPilotSoulTemplate(), this); + } + + private static void saveEnum(Saver s, Enumeration<?> e) throws IOException { + while (e.hasMoreElements()) { + Object o = e.nextElement(); + if (o instanceof Persister && !(o instanceof NonPersister)) { + s.saveMaybeNull((Persister)o); + } + } + + s.saveMaybeNull(null); + } + + public static void copySoul(WObject source, WObject target) { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + + try { + Saver saver = new Saver(new DataOutputStream(buffer)); + saveEnum(saver, source.getContents()); + saveEnum(saver, source.getHandlers()); + saveEnum(saver, source.getActions()); + saveEnum(saver, source.getAttributes()); + saver.done(); + } catch (Exception var5) { + var5.printStackTrace(System.out); + throw new Error(var5.toString()); + } + + try { + Restorer r = new Restorer(new DataInputStream(new ByteArrayInputStream(buffer.toByteArray()))); + + Persister p; + while ((p = r.restoreMaybeNull()) != null) { + target.add((Transform)p); + } + + while ((p = r.restoreMaybeNull()) != null) { + target.addHandler((SuperRoot)p); + } + + while ((p = r.restoreMaybeNull()) != null) { + target.addAction((Action)p); + } + + while ((p = r.restoreMaybeNull()) != null) { + target.addAttribute((Attribute)p); + } + + r.done(); + } catch (Exception var6) { + var6.printStackTrace(System.out); + throw new Error(var6.toString()); + } + } + + @Override + protected void noteUnadding(SuperRoot child) { + if (child instanceof WObject) { + WObject w = (WObject)child; + w.isDynamic(); + } + + super.noteUnadding(child); + } + + @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 = new Property(this, index, "Console"); + } else if (mode == 1) { + ret = this.console; + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + if (this.console != null) { + System.out.println("Warning: saving pilot " + this.getName() + " with soul, which won't restore correctly!"); + } + + s.saveVersion(0, classCookie); + super.saveState(s); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/PitchDriver.java b/NET/worlds/scape/PitchDriver.java new file mode 100644 index 0000000..8d2210c --- /dev/null +++ b/NET/worlds/scape/PitchDriver.java @@ -0,0 +1,196 @@ +package NET.worlds.scape; + +import java.io.IOException; +import java.util.Enumeration; + +public class PitchDriver extends SwitchableBehavior implements KeyUpHandler, KeyDownHandler, FrameHandler, Persister, MomentumBehavior { + protected float pitch_force; + protected float pitch_vel; + protected int lastTime; + protected float maxdvpitch = 166.0F; + protected float pitch_damp = -5.0F; + protected float minpitch_vel = 3.0F; + protected float pitch_key = 500.0F; + private static Object cookie = new Object(); + + public void applyFrameForce(Event e) { + if (e.receiver instanceof Pilot) { + Camera cam = ((Pilot)e.receiver).getMainCamera(); + int now = e.time; + float dt = (now - this.lastTime) / 1000.0F; + if (!(dt <= 0.0F)) { + this.lastTime = now; + float dTheta = this.pitch_vel * dt; + float dv = 0.0F; + if (this.pitch_force != 0.0F) { + dv += this.pitch_force * dt; + dv = this.maxdvpitch * (float)Math.atan(dv / this.maxdvpitch); + this.pitch_vel += dv; + dTheta += dv * dt; + } + + if (dTheta != 0.0F) { + Point3Temp axis = Point3Temp.make(); + float angle = cam.lookAround.getSpin(axis); + if (axis.x < 0.0F) { + angle = -angle; + } + + if (angle + dTheta > 90.0F) { + dTheta = 90.0F - angle; + } else if (angle + dTheta < -90.0F) { + dTheta = -90.0F - angle; + } + + cam.lookAround.spin(1.0F, 0.0F, 0.0F, dTheta); + } + + this.pitch_vel = (float)(this.pitch_vel * Math.exp(this.pitch_damp * dt)); + if (Math.abs(this.pitch_vel) < this.minpitch_vel) { + this.pitch_vel = 0.0F; + } + } + } + } + + @Override + public boolean handle(FrameEvent e) { + this.applyFrameForce(e); + return true; + } + + public void resetPitch(Event e) { + Camera cam = ((Pilot)e.receiver).getMainCamera(); + cam.lookAround.makeIdentity(); + } + + @Override + public boolean handle(KeyDownEvent e) { + float pitch; + if (e.getKey() == '\ue321') { + pitch = this.pitch_key; + } else { + if (e.getKey() != '\ue322') { + if (e.getKey() == '\ue324') { + this.resetPitch(e); + } + + return true; + } + + pitch = -this.pitch_key; + } + + this.applyFrameForce(e); + this.pitch_force = pitch; + return true; + } + + @Override + public boolean handle(KeyUpEvent e) { + if (e.getKey() == '\ue321' || e.getKey() == '\ue322') { + this.applyFrameForce(e); + this.pitch_force = 0.0F; + } + + return true; + } + + @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 = FloatPropertyEditor.make(new Property(this, index, "Pitch max acceleration")); + } else if (mode == 1) { + ret = new Float(this.maxdvpitch); + } else if (mode == 2) { + this.maxdvpitch = ((Float)value).intValue(); + } + break; + case 1: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Pitch rate damping")); + } else if (mode == 1) { + ret = new Float(this.pitch_damp); + } else if (mode == 2) { + this.pitch_damp = ((Float)value).intValue(); + } + break; + case 2: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Pitch min rate")); + } else if (mode == 1) { + ret = new Float(this.minpitch_vel); + } else if (mode == 2) { + this.minpitch_vel = ((Float)value).intValue(); + } + break; + case 3: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Pitch rate increment for up/down arrow keys")); + } else if (mode == 1) { + ret = new Float(this.pitch_key); + } else if (mode == 2) { + this.pitch_key = ((Float)value).intValue(); + } + break; + default: + ret = super.properties(index, offset + 12, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, cookie); + super.saveState(s); + s.saveFloat(this.pitch_vel); + s.saveFloat(this.maxdvpitch); + s.saveFloat(this.pitch_damp); + s.saveFloat(this.minpitch_vel); + s.saveFloat(this.pitch_key); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(cookie)) { + case 0: + r.setOldFlag(); + super.restoreState(r); + r.restoreFloat(); + this.pitch_vel = r.restoreFloat(); + this.maxdvpitch = r.restoreFloat(); + this.pitch_damp = r.restoreFloat(); + this.minpitch_vel = r.restoreFloat(); + this.pitch_key = r.restoreFloat(); + break; + case 1: + super.restoreState(r); + this.pitch_vel = r.restoreFloat(); + this.maxdvpitch = r.restoreFloat(); + this.pitch_damp = r.restoreFloat(); + this.minpitch_vel = r.restoreFloat(); + this.pitch_key = r.restoreFloat(); + break; + default: + throw new TooNewException(); + } + } + + @Override + public void transferFrom(Enumeration oldMBs) { + while (oldMBs.hasMoreElements()) { + SuperRoot sr = (SuperRoot)oldMBs.nextElement(); + if (sr instanceof PitchDriver) { + PitchDriver pd = (PitchDriver)sr; + this.pitch_vel = pd.pitch_vel; + this.pitch_force = pd.pitch_force; + this.lastTime = pd.lastTime; + break; + } + } + } +} diff --git a/NET/worlds/scape/PitchWidget.java b/NET/worlds/scape/PitchWidget.java new file mode 100644 index 0000000..c6e741a --- /dev/null +++ b/NET/worlds/scape/PitchWidget.java @@ -0,0 +1,19 @@ +package NET.worlds.scape; + +class PitchWidget extends WidgetButton { + public PitchWidget(ToolBar toolbar) { + super(toolbar, "pitch.gif", "Pitch"); + } + + @Override + public String drag(boolean initialDrag, float deltax, float deltay) { + if (Math.abs(deltax) > Math.abs(deltay)) { + deltay = 0.0F; + } + + Transform t = Transform.make(); + this.applyWorldTransform(initialDrag, t.spin(this.getWorldAxis(1, 0, 0), -deltay)); + t.recycle(); + return "Pitch"; + } +} diff --git a/NET/worlds/scape/PlaneBumpCalc.java b/NET/worlds/scape/PlaneBumpCalc.java new file mode 100644 index 0000000..83fed14 --- /dev/null +++ b/NET/worlds/scape/PlaneBumpCalc.java @@ -0,0 +1,65 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class PlaneBumpCalc extends BumpCalc { + private static Object classCookie = new Object(); + + @Override + public void detectBump(BumpEventTemp b, WObject owner) { + WObject source = (WObject)b.source; + Point3Temp sourceStart = source.getWorldPosition(); + Transform xfrm = owner.getObjectToWorldMatrix(); + Point3Temp start = xfrm.getPosition(); + Point3Temp right = owner.getPlaneExtent().times(xfrm); + Point3Temp d = Point3Temp.make(right).minus(start); + xfrm.recycle(); + BoundBoxTemp sourceBox = source.getBoundBox(); + Point2 corner; + if (d.x > 0.0F) { + if (d.y > 0.0F) { + corner = new Point2(sourceBox.lo.x, sourceBox.hi.y); + } else { + corner = new Point2(sourceBox.hi.x, sourceBox.hi.y); + } + } else if (d.y > 0.0F) { + corner = new Point2(sourceBox.lo.x, sourceBox.lo.y); + } else { + corner = new Point2(sourceBox.hi.x, sourceBox.lo.y); + } + + Point2 dn = new Point2(-d.y, d.x).normalize(); + corner.x = corner.x - sourceStart.x; + corner.y = corner.y - sourceStart.y; + float dist = corner.dot(dn); + Point3Temp extent = Point3Temp.make(dn.x * dist, dn.y * dist, 0.0F); + if (!b.hitRegion(owner, Point3Temp.make(start).minus(extent), d, extent)) { + Point3Temp ccwNormal = Point3Temp.make(extent.y, -extent.x, 0.0F); + d = Point3Temp.make(ccwNormal).minus(extent); + Point3Temp extentL = Point3Temp.make(-d.y, d.x, 0.0F).normalize().times(dist / 1.5F); + Point3Temp startL = Point3Temp.make(start).minus(ccwNormal); + if (!b.hitRegion(owner, startL, d, extentL)) { + if (!b.hitRegion(owner, Point3Temp.make(right).minus(extent), Point3Temp.make(-d.y, d.x, 0.0F), Point3Temp.make(-extentL.y, extentL.x, 0.0F))) { + ; + } + } + } + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/PlaybackRecordingAction.java b/NET/worlds/scape/PlaybackRecordingAction.java new file mode 100644 index 0000000..3b9e7d8 --- /dev/null +++ b/NET/worlds/scape/PlaybackRecordingAction.java @@ -0,0 +1,59 @@ +package NET.worlds.scape; + +import NET.worlds.console.BlackBox; +import NET.worlds.network.URL; +import java.io.IOException; + +public class PlaybackRecordingAction extends Action { + private String filename = "home:record.rec"; + private static Object classCookie = new Object(); + + public void setFilename(String m) { + this.filename = m; + } + + @Override + public Persister trigger(Event e, Persister seqId) { + BlackBox.getInstance().play(URL.make(this.filename)); + return null; + } + + @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 = StringPropertyEditor.make(new Property(this, index, "Filename")); + } else if (mode == 1) { + ret = new String(this.filename); + } else if (mode == 2) { + this.filename = (String)value; + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + super.saveState(s); + s.saveString(this.filename); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 1: + super.restoreState(r); + this.filename = r.restoreString(); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/Point2.java b/NET/worlds/scape/Point2.java new file mode 100644 index 0000000..3b471b7 --- /dev/null +++ b/NET/worlds/scape/Point2.java @@ -0,0 +1,129 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class Point2 implements Persister { + public float x; + public float y; + private static Object classCookie = new Object(); + + public Point2() { + } + + public Point2(float _x, float _y) { + this.set(_x, _y); + } + + public Point2(Point2 p) { + this.x = p.x; + this.y = p.y; + } + + public Point2 copy(Point2 b) { + this.x = b.x; + this.y = b.y; + return this; + } + + public void set(float _x, float _y) { + this.x = _x; + this.y = _y; + } + + public float length() { + return (float)Math.sqrt(this.x * this.x + this.y * this.y); + } + + public Point2 normalize() { + float len = this.length(); + if (len > 0.0F) { + this.dividedBy(len); + } + + return this; + } + + public Point2 negate() { + this.x = -this.x; + this.y = -this.y; + return this; + } + + public Point2 plus(Point2 p) { + this.x = this.x + p.x; + this.y = this.y + p.y; + return this; + } + + public Point2 plus(float v) { + this.x += v; + this.y += v; + return this; + } + + public Point2 minus(float v) { + return this.plus(-v); + } + + public Point2 minus(Point2 p) { + this.x = this.x - p.x; + this.y = this.y - p.y; + return this; + } + + public Point2 times(float v) { + this.x *= v; + this.y *= v; + return this; + } + + public Point2 times(Point2 p) { + this.x = this.x * p.x; + this.y = this.y * p.y; + return this; + } + + public Point2 dividedBy(float v) { + this.x /= v; + this.y /= v; + return this; + } + + public Point2 dividedBy(Point2 p) { + this.x = this.x / p.x; + this.y = this.y / p.y; + return this; + } + + public float dot(Point2 p) { + return p.x * this.x + p.y * this.y; + } + + @Override + public String toString() { + return this.x + "," + this.y; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + s.saveFloat(this.x); + s.saveFloat(this.y); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + this.x = r.restoreFloat(); + this.y = r.restoreFloat(); + return; + default: + throw new TooNewException(); + } + } + + @Override + public void postRestore(int version) { + } +} diff --git a/NET/worlds/scape/Point2EditorDialog.java b/NET/worlds/scape/Point2EditorDialog.java new file mode 100644 index 0000000..61f62e6 --- /dev/null +++ b/NET/worlds/scape/Point2EditorDialog.java @@ -0,0 +1,66 @@ +package NET.worlds.scape; + +import java.util.StringTokenizer; + +class Point2EditorDialog extends ListEditorDialog { + protected Property property; + protected Point2 p; + + Point2EditorDialog(EditTile parent, String title, Property property) { + super(parent, title); + this.property = property; + this.ready(); + } + + @Override + protected void build() { + this.p = (Point2)this.property.get(); + super.build(); + } + + @Override + protected int getElementCount() { + return 2; + } + + @Override + protected String getElement(int index) { + switch (index) { + case 0: + return "" + this.p.x; + default: + return "" + this.p.y; + } + } + + @Override + protected boolean setElements(StringTokenizer e) { + Point2 p = new Point2(); + int count = 0; + + while (e.hasMoreTokens()) { + try { + float tmp = Float.valueOf(e.nextToken()); + switch (count++) { + case 0: + p.x = tmp; + break; + case 1: + p.y = tmp; + break; + default: + return false; + } + } catch (Exception var5) { + return false; + } + } + + if (count != 2) { + return false; + } else { + this.parent.addUndoableSet(this.property, p); + return true; + } + } +} diff --git a/NET/worlds/scape/Point2PropertyEditor.java b/NET/worlds/scape/Point2PropertyEditor.java new file mode 100644 index 0000000..58ea863 --- /dev/null +++ b/NET/worlds/scape/Point2PropertyEditor.java @@ -0,0 +1,19 @@ +package NET.worlds.scape; + +import NET.worlds.console.PolledDialog; + +public class Point2PropertyEditor extends PropEditor { + private Point2PropertyEditor(Property property) { + super(property); + } + + @Override + public PolledDialog edit(EditTile parent, String title) { + return new Point2EditorDialog(parent, title, this.property); + } + + public static Property make(Property property) { + property.setPropertyType(7); + return property.setEditor(new Point2PropertyEditor(property)); + } +} diff --git a/NET/worlds/scape/Point3.java b/NET/worlds/scape/Point3.java new file mode 100644 index 0000000..b4c4921 --- /dev/null +++ b/NET/worlds/scape/Point3.java @@ -0,0 +1,47 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class Point3 extends Point3Temp implements Persister { + private static Object classCookie = new Object(); + + public Point3() { + super(0); + } + + public Point3(float x, float y, float z) { + super(0); + this.x = x; + this.y = y; + this.z = z; + } + + public Point3(Point3Temp p) { + this(p.x, p.y, p.z); + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + s.saveFloat(this.x); + s.saveFloat(this.y); + s.saveFloat(this.z); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + this.x = r.restoreFloat(); + this.y = r.restoreFloat(); + this.z = r.restoreFloat(); + return; + default: + throw new TooNewException(); + } + } + + @Override + public void postRestore(int version) { + } +} diff --git a/NET/worlds/scape/Point3EditorDialog.java b/NET/worlds/scape/Point3EditorDialog.java new file mode 100644 index 0000000..02134cb --- /dev/null +++ b/NET/worlds/scape/Point3EditorDialog.java @@ -0,0 +1,71 @@ +package NET.worlds.scape; + +import java.util.StringTokenizer; + +class Point3EditorDialog extends ListEditorDialog { + protected Property property; + protected Point3 p; + + Point3EditorDialog(EditTile parent, String title, Property property) { + super(parent, title); + this.property = property; + this.ready(); + } + + @Override + protected void build() { + this.p = (Point3)this.property.get(); + super.build(); + } + + @Override + protected int getElementCount() { + return 3; + } + + @Override + protected String getElement(int index) { + switch (index) { + case 0: + return "" + this.p.x; + case 1: + return "" + this.p.y; + default: + return "" + this.p.z; + } + } + + @Override + protected boolean setElements(StringTokenizer e) { + Point3 p = new Point3(); + int count = 0; + + while (e.hasMoreTokens()) { + try { + float tmp = Float.valueOf(e.nextToken()); + switch (count++) { + case 0: + p.x = tmp; + break; + case 1: + p.y = tmp; + break; + case 2: + p.z = tmp; + break; + default: + return false; + } + } catch (Exception var5) { + return false; + } + } + + if (count != 3) { + return false; + } else { + this.parent.addUndoableSet(this.property, p); + return true; + } + } +} diff --git a/NET/worlds/scape/Point3PropertyEditor.java b/NET/worlds/scape/Point3PropertyEditor.java new file mode 100644 index 0000000..6f0c01c --- /dev/null +++ b/NET/worlds/scape/Point3PropertyEditor.java @@ -0,0 +1,19 @@ +package NET.worlds.scape; + +import NET.worlds.console.PolledDialog; + +public class Point3PropertyEditor extends PropEditor { + private Point3PropertyEditor(Property property) { + super(property); + } + + @Override + public PolledDialog edit(EditTile parent, String title) { + return new Point3EditorDialog(parent, title, this.property); + } + + public static Property make(Property property) { + property.setPropertyType(8); + return property.setEditor(new Point3PropertyEditor(property)); + } +} diff --git a/NET/worlds/scape/Point3Temp.java b/NET/worlds/scape/Point3Temp.java new file mode 100644 index 0000000..361b578 --- /dev/null +++ b/NET/worlds/scape/Point3Temp.java @@ -0,0 +1,168 @@ +package NET.worlds.scape; + +public class Point3Temp { + public float x; + public float y; + public float z; + private static Recycler recycler = new Recycler(); + + static { + nativeInit(); + } + + public static native void nativeInit(); + + public static Point3Temp make(float x, float y, float z) { + Point3Temp p = (Point3Temp)recycler.alloc(); + if (p == null) { + recycler.recycle(new Point3Temp(0)); + p = (Point3Temp)recycler.alloc(); + } + + p.x = x; + p.y = y; + p.z = z; + return p; + } + + public static Point3Temp make() { + return make(0.0F, 0.0F, 0.0F); + } + + public static Point3Temp make(Point3Temp p) { + return make(p.x, p.y, p.z); + } + + protected Point3Temp(int dummy) { + } + + public Point3Temp copy(Point3Temp b) { + this.set(b.x, b.y, b.z); + return this; + } + + public void set(float _x, float _y, float _z) { + this.x = _x; + this.y = _y; + this.z = _z; + } + + public float length() { + return (float)Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z); + } + + public float squaredLength() { + return this.x * this.x + this.y * this.y + this.z * this.z; + } + + public native Point3Temp times(Transform var1); + + public native Point3Temp vectorTimes(Transform var1); + + public Point3Temp normalize() { + float len = this.length(); + if (len > 0.0F) { + this.dividedBy(len); + } + + return this; + } + + public Point3Temp negate() { + this.x = -this.x; + this.y = -this.y; + this.z = -this.z; + return this; + } + + public Point3Temp abs() { + this.x = Math.abs(this.x); + this.y = Math.abs(this.y); + this.z = Math.abs(this.z); + return this; + } + + public static Point3Temp getDirVector(float amount, float angle) { + angle = (float)(angle * (Math.PI / 180.0)); + return make(-amount * (float)Math.sin(angle), amount * (float)Math.cos(angle), 0.0F); + } + + public Point3Temp plus(Point3Temp p) { + this.x = this.x + p.x; + this.y = this.y + p.y; + this.z = this.z + p.z; + return this; + } + + public Point3Temp cross(Point3Temp p) { + float xNew = this.y * p.z - this.z * p.y; + float yNew = this.z * p.x - this.x * p.z; + this.z = this.x * p.y - this.y * p.x; + this.x = xNew; + this.y = yNew; + return this; + } + + public Point3Temp plus(float v) { + this.x += v; + this.y += v; + this.z += v; + return this; + } + + public Point3Temp minus(float v) { + return this.plus(-v); + } + + public Point3Temp minus(Point3Temp p) { + this.x = this.x - p.x; + this.y = this.y - p.y; + this.z = this.z - p.z; + return this; + } + + public Point3Temp times(float v) { + this.x *= v; + this.y *= v; + this.z *= v; + return this; + } + + public Point3Temp times(Point3Temp p) { + this.x = this.x * p.x; + this.y = this.y * p.y; + this.z = this.z * p.z; + return this; + } + + public Point3Temp dividedBy(float v) { + this.x /= v; + this.y /= v; + this.z /= v; + return this; + } + + public Point3Temp dividedBy(Point3Temp p) { + this.x = this.x / p.x; + this.y = this.y / p.y; + this.z = this.z / p.z; + return this; + } + + public float dot(Point3Temp p) { + return p.x * this.x + p.y * this.y + p.z * this.z; + } + + public float det(Point3Temp a, Point3Temp b) { + return this.x * a.y * b.z + a.x * b.y * this.z + b.x * this.y * a.z - this.z * a.y * b.x - a.z * b.y * this.x - b.z * this.y * a.x; + } + + public boolean sameValue(Point3Temp p) { + return p == null ? false : this.x == p.x && this.y == p.y && this.z == p.z; + } + + @Override + public String toString() { + return this.x + "," + this.y + "," + this.z; + } +} diff --git a/NET/worlds/scape/Polygon.java b/NET/worlds/scape/Polygon.java new file mode 100644 index 0000000..7305c86 --- /dev/null +++ b/NET/worlds/scape/Polygon.java @@ -0,0 +1,75 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class Polygon extends Surface { + protected float[] vertices; + private static Object classCookie = new Object(); + + public Polygon(int numVertices, Material material) { + this(new float[5 * numVertices], material); + } + + public Polygon(float[] vertices, Material material) { + super(material); + + assert vertices.length % 5 == 0; + + this.vertices = vertices; + } + + public Polygon() { + } + + public void setVertex(int i, float x, float y, float z, float u, float v) { + i *= 5; + this.vertices[i] = x; + this.vertices[i + 1] = y; + this.vertices[i + 2] = z; + this.vertices[i + 3] = u; + this.vertices[i + 4] = v; + this.nativeSetVertex(i, x, y, z, u, v); + } + + public native void nativeSetVertex(int var1, float var2, float var3, float var4, float var5, float var6); + + @Override + protected void addRwChildren(WObject parent) { + this.addNewRwChild(parent); + + for (int i = 0; i < this.vertices.length; i += 5) { + this.addVertex(this.vertices[i], this.vertices[i + 1], this.vertices[i + 2], this.vertices[i + 3], this.vertices[i + 4]); + } + + this.doneWithEditing(); + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + s.saveInt(this.vertices.length); + + for (int i = 0; i < this.vertices.length; i++) { + s.saveFloat(this.vertices[i]); + } + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + int length = r.restoreInt(); + this.vertices = new float[length]; + + for (int i = 0; i < length; i++) { + this.vertices[i] = r.restoreFloat(); + } + + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/Portal.java b/NET/worlds/scape/Portal.java new file mode 100644 index 0000000..e2f05b6 --- /dev/null +++ b/NET/worlds/scape/Portal.java @@ -0,0 +1,831 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.Main; +import NET.worlds.console.MainCallback; +import NET.worlds.network.NetUpdate; +import NET.worlds.network.URL; +import java.awt.Color; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.Vector; + +public class Portal extends Rect implements BumpHandler, Prerenderable, Postrenderable, Properties, Persister, LoadedURLSelf { + static final int UNCONNECTED = -1; + static final int INITIAL = 0; + static final int DOWNLOADING = 1; + static final int DONE = 2; + private int _state = -1; + private Portal _farSidePortal = null; + String _farSidePortalName = null; + private boolean _farSideIsPortal = true; + private boolean _allowDownload = true; + String _farSideRoomName = null; + private URL _farSideWorld = null; + private Room _farSideRoom = null; + private float _farx; + private float _fary; + private float _farz; + private float _fartheta; + private float _userFarx; + private float _userFary; + private float _userFarz; + private float _userFartheta; + private boolean frozeFrameEvents; + private Transform _p2pxform = null; + private int _changeNum = 0; + private int _farChangeNum = -1; + static BumpCalc standardPassthroughBumpCalc = new PassthroughBumpCalc(); + private static Object classCookie = new Object(); + + static { + nativeInit(); + standardPassthroughBumpCalc.setName("defaultPassthroughBumpCalc"); + } + + protected Room getFarSideRoom() { + return this._farSideRoom; + } + + public Portal(float w, float h) { + super(w, h, null); + } + + public Portal(float llx, float lly, float llz, float urx, float ury, float urz) { + super(llx, lly, llz, urx, ury, urz, null); + } + + public Portal() { + } + + public void setFarSideInfo(URL world, String room, String portal) { + this._farSideWorld = world; + this._farSideRoomName = room; + this._farSidePortalName = portal; + } + + public Portal(Point3Temp llc, Point3Temp urc) { + super(llc, urc, null); + } + + public static Portal findByName(Room r, String portalName) { + SuperRoot sr = SuperRoot.nameSearch(r.getDeepOwned(), portalName); + return sr != null && sr instanceof Portal ? (Portal)sr : null; + } + + public Portal connectTo(Portal far) { + assert this._state == -1; + + this._farSideIsPortal = true; + this._farSidePortal = far; + this.newFarSide(); + return this; + } + + public Portal connectTo(URL farworld, String farroom, Point3Temp llc, Point3Temp urc) { + return this.connectTo(farworld, farroom, llc.x, llc.y, llc.z, urc.x, urc.y, urc.z); + } + + public Portal connectTo(Room r, Point3Temp llc, Point3Temp urc) { + System.out.println("Warning! Old style Portal.connectTo called!"); + Thread.dumpStack(); + + assert this._state == -1; + + this._farSideWorld = r.getWorld().getSourceURL(); + this._farSideRoomName = r.getName(); + this.setFarSideRoom(r); + this._farx = this._userFarx = urc.x; + this._fary = this._userFary = urc.y; + this._farz = this._userFarz = llc.z; + this._userFartheta = (float)(Math.atan2(llc.y - urc.y, llc.x - urc.x) * 180.0 / Math.PI); + this._fartheta = this._userFartheta; + this._state = 2; + this._farSideIsPortal = false; + this.setTransform(); + this.updateVisible(); + return this; + } + + public Portal connectTo(URL farworld, String farroom, float llx, float lly, float llz, float urx, float ury, float urz) { + float theta = (float)(Math.atan2(lly - ury, llx - urx) * 180.0 / Math.PI); + return this.connectTo(farworld, farroom, urx, ury, llz, theta); + } + + public Portal connectTo(URL farworld, String farroom, float x, float y, float z, float theta) { + assert this._state == -1; + + this._farSideWorld = farworld; + this._farSideRoomName = farroom; + this._farx = this._userFarx = x; + this._fary = this._userFary = y; + this._farz = this._userFarz = z; + this._fartheta = this._userFartheta = theta; + this._farSideIsPortal = false; + this.reset(); + return this; + } + + public Portal remotify() { + RPAction rpa = new RPAction(); + this.addAction(rpa); + this.addHandler(new SameRoomSensor(rpa)); + return this; + } + + private void findFarSidePortal(boolean showmessage) { + if (this._farSideIsPortal) { + if (this._farSidePortalName == null) { + this._state = -1; + } else { + this._farSidePortal = null; + Vector portals = this._farSideRoom.getOutgoingPortals(); + int len = portals.size(); + + for (int i = 0; i < len; i++) { + Portal p = (Portal)portals.elementAt(i); + if (p.getName().equals(this._farSidePortalName)) { + this._farSidePortal = p; + break; + } + } + + if (this._farSidePortal == null) { + if (showmessage) { + Object[] arguments = new Object[]{ + new String(this.getName()), new String("" + this._farSideWorld), new String(this._farSideRoomName), new String(this._farSidePortalName) + }; + Console.println(MessageFormat.format(Console.message("Portal-doesnt"), arguments)); + } + + this._state = -1; + } + } + + if (this._farSidePortal != null) { + this.newFarSide(); + } + } else { + this._farSidePortal = null; + this._farx = this._userFarx; + this._fary = this._userFary; + this._farz = this._userFarz; + this._fartheta = this._userFartheta; + this._p2pxform = null; + } + } + + public void reset() { + this.reset(true); + } + + public void reset(boolean showmessage) { + this.setFarSideRoom(null); + if (this._farSideRoomName == null || (this.flags & 262144) != 0) { + this._state = -1; + } else if (this._farSideWorld == null) { + Room r = this.getRoom(); + if (r != null) { + World w = r.getWorld(); + if (w != null) { + this.setFarSideRoom(w.getRoom(this._farSideRoomName)); + } + } + + if (this._farSideRoom != null) { + this.findFarSidePortal(showmessage); + } else { + this._state = -1; + this._farSidePortal = null; + if (showmessage) { + Object[] arguments = new Object[]{ + new String(this.getName()), new String("" + this.getRoom()), new String(this._farSideRoomName), new String(this._farSidePortalName) + }; + Console.println(MessageFormat.format(Console.message("Room-doesnt"), arguments)); + } + } + } else { + if (this._farSidePortalName == null) { + this._farSidePortal = null; + } + + this._state = 0; + } + + this.setTransform(); + this.updateVisible(); + } + + @Override + public void discard() { + Portal far = this._farSidePortal; + this.setFarSideRoom(null); + this._state = 0; + super.discard(); + if (far != null && far.getRoom() != null && this._farSideWorld != null) { + far.reset(); + } + } + + private void recomputeFarPosition() { + this.setFarSideRoom(this._farSidePortal.getRoom()); + if (this._farSideRoom != null) { + this._farSideRoomName = this._farSideRoom.getName(); + } + + this._farSidePortalName = this._farSidePortal.getName(); + Point3Temp farext = Point3Temp.make(1.0F, 0.0F, 1.0F).vectorTimes(this._farSidePortal); + Point3Temp farlrc = this._farSidePortal.getPosition(); + if ((this.flags & 4) == 0) { + farlrc.x = farlrc.x + farext.x; + farlrc.y = farlrc.y + farext.y; + } + + this._farx = farlrc.x; + this._fary = farlrc.y; + this._farz = farlrc.z; + this._fartheta = (-this._farSidePortal.getYaw() + 180.0F) % 360.0F; + this._farChangeNum = this._farSidePortal._changeNum; + this._p2pxform = null; + } + + public Portal biconnect(Portal far) { + this.connectTo(far); + far.connectTo(this); + return this; + } + + public void disconnect() { + this._farSideWorld = null; + this._farSideRoomName = null; + this.setFarSideRoom(null); + this._farSidePortal = null; + this._farSideIsPortal = true; + this._farSidePortalName = null; + this._state = -1; + this.updateVisible(); + this.discardTransform(); + } + + public void bidisconnect() { + this._farSidePortal.disconnect(); + this.disconnect(); + } + + public boolean connected() { + return this._farSidePortal != null || this._farSideRoomName != null && !this._farSideIsPortal; + } + + public boolean active() { + return this._state == 2; + } + + public boolean unconnected() { + return this._state == -1; + } + + public boolean remote() { + return this._farSideWorld != null; + } + + public Portal farSide() { + return this._farSideIsPortal ? this._farSidePortal : null; + } + + public Room farSideRoom() { + return this._farSideRoom; + } + + private void setFarSideRoom(Room far) { + this._farSideRoom = far; + } + + @Override + protected void noteAddingTo(SuperRoot s) { + this.addToRoom(s); + super.noteAddingTo(s); + } + + private void addToRoom(SuperRoot s) { + if (s instanceof WObject) { + Room r = ((WObject)s).getRoom(); + if (r != null) { + r.addOutgoingPortal(this); + } + } + } + + @Override + public void detach() { + Room r = this.getRoom(); + if (r != null) { + r.removeOutgoingPortal(this); + } + + super.detach(); + } + + public String farRoom() { + return this._farSideRoomName; + } + + public URL farWorld() { + return this._farSideWorld; + } + + public Transform p2pXform() { + return this._p2pxform; + } + + @Override + protected void addRwChildren(WObject parent) { + if (this._farSidePortal != null && this._farSidePortal instanceof TwoWayPortal && !this._farSidePortal.isActive()) { + Main.register(new MainCallback() { + @Override + public void mainCallback() { + Portal.this.detach(); + Main.unregister(this); + } + }); + } + + super.addRwChildren(parent); + this.updateVisible(); + this.setTransform(); + this.getRoom().prependPrerenderHandler(this); + this.getRoom().prependPostrenderHandler(this); + } + + @Override + protected void markVoid() { + this.getRoom().removePrerenderHandler(this); + this.getRoom().removePostrenderHandler(this); + super.markVoid(); + } + + @Override + protected void noteTransformChange() { + this._changeNum++; + super.noteTransformChange(); + this.discardTransform(); + } + + public static native void nativeInit(); + + @Override + protected native void updateVisible(); + + native void setTransform(); + + public void discardTransform() { + if (this._p2pxform != null) { + this._p2pxform = null; + if (this._farSidePortal != null) { + this._farSidePortal.discardTransform(); + } + } + } + + @Override + public native void prerender(Camera var1); + + @Override + public native void postrender(Camera var1); + + @Override + public BumpCalc getBumpCalc(BumpEventTemp b) { + if (this._farSidePortal == null + || !(b.source instanceof Camera) + || (this.flags & 4) == 0 && this._farSidePortal.active() && this._farSidePortal._p2pxform != null && this._farSidePortal.getVisible()) { + if (this.bumpCalc != null) { + return this.bumpCalc; + } else if (this._farSideRoomName == null) { + return standardPassthroughBumpCalc; + } else { + if (this.connected() && (this.flags & 262144) == 0) { + if (this._farSideRoom == null && this._farSideIsPortal && this._farSidePortal != null) { + this.setFarSideRoom(this._farSidePortal.getRoom()); + } + + if (this._farSideRoom != null && this._farSideRoom.isActive()) { + return standardPassthroughBumpCalc; + } + } + + return super.getBumpCalc(b); + } + } else { + return super.getBumpCalc(b); + } + } + + @Override + public boolean handle(BumpEventTemp b) { + if (this._farSidePortal == null + || !(b.source instanceof Camera) + || (this.flags & 4) == 0 && this._farSidePortal.active() && this._farSidePortal._p2pxform != null && this._farSidePortal.getVisible()) { + this.portalBumpHandler(b); + return true; + } else { + return true; + } + } + + public void portalBumpHandler(BumpEventTemp b) { + if (b.target == this && this._state == 2) { + if (this._farSideRoom == null && this._farSideIsPortal && this._farSidePortal != null) { + this.setFarSideRoom(this._farSidePortal.getRoom()); + } + + if (this._farSideRoom != null && this._farSideRoom.isActive()) { + if (this._p2pxform == null) { + this.setTransform(); + if (this._p2pxform == null) { + return; + } + } + + b.postBumpRoom = this._farSideRoom; + Transform t = ((WObject)b.source).getObjectToWorldMatrix(); + b.postBumpPosition.setTransform(t); + t.recycle(); + b.postBumpPosition.moveBy(b.path).post(this._p2pxform); + b.postBumpPath = new Point3(b.fullPath).times(1.0F - b.fraction).vectorTimes(this._p2pxform); + } + } else { + if (this._state == 1 && this._farSideWorld != null && !this._farSideWorld.isRemote() && !this.frozeFrameEvents) { + this.frozeFrameEvents = true; + Console.setFreezeFrameEvents(true); + } + } + } + + @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 = URLPropertyEditor.make(new Property(this, index, "Destination World URL (null means this world)").allowSetNull(), "world"); + } else if (mode == 1) { + ret = this._farSideWorld; + } else if (mode == 2) { + this._farSideWorld = (URL)value; + this.reset(); + this.triggerLoad(); + } + break; + case 1: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Destination Room Name").allowSetNull()); + } else if (mode == 1) { + ret = this._farSideRoomName == null ? "" : this._farSideRoomName; + } else if (mode == 2) { + this._farSideRoomName = (String)value; + if ("".equals(this._farSideRoomName)) { + this._farSideRoomName = null; + } + + this.reset(); + this.triggerLoad(); + } + break; + case 2: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Connect to a portal"), "Use location and orientation", "Use portal"); + } else if (mode == 1) { + ret = new Boolean(this._farSideIsPortal); + } else if (mode == 2) { + boolean tmp = (Boolean)value; + this._farSideIsPortal = tmp; + this.reset(); + this.triggerLoad(); + } + break; + case 3: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Download if world not present"), "Never download", "Allow download"); + } else if (mode == 1) { + ret = new Boolean(this._allowDownload); + } else if (mode == 2) { + boolean tmp = (Boolean)value; + this._allowDownload = tmp; + } + break; + case 4: + if (mode == 0) { + ret = new Property(this, index, "Destination Portal Name"); + if (this._farSideIsPortal) { + ret = StringPropertyEditor.make((Property)ret); + } + } else if (mode == 1) { + ret = this._farSidePortalName == null ? "" : this._farSidePortalName; + } else if (mode == 2) { + this._farSidePortalName = (String)value; + if ("".equals(this._farSidePortalName)) { + this._farSidePortalName = null; + } + + this.reset(); + this.triggerLoad(); + } + break; + case 5: + if (mode == 0) { + ret = new Property(this, index, "Destination position"); + if (!this._farSideIsPortal) { + ret = Point3PropertyEditor.make((Property)ret); + } + } else if (mode == 1) { + ret = new Point3(this._userFarx, this._userFary, this._userFarz); + } else if (mode == 2) { + Point3 p = (Point3)value; + this._farx = this._userFarx = p.x; + this._fary = this._userFary = p.y; + this._farz = this._userFarz = p.z; + this.reset(); + this.triggerLoad(); + } + break; + case 6: + if (mode == 0) { + ret = new Property(this, index, "Destination orientation (degrees, clockwise from North)"); + if (!this._farSideIsPortal) { + ret = FloatPropertyEditor.make((Property)ret, 0.0F, 360.0F); + } + } else if (mode == 1) { + ret = new Float(this._userFartheta); + } else if (mode == 2) { + this._fartheta = this._userFartheta = (Float)value; + this.reset(); + this.triggerLoad(); + } + break; + case 7: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Mirrored"), "Normal", "Mirrored"); + } else if (mode == 1) { + ret = new Boolean((this.flags & 4) != 0); + } else if (mode == 2) { + if ((Boolean)value) { + this.flags |= 4; + } else { + this.flags &= -5; + } + + this.reset(); + this.triggerLoad(); + } + break; + default: + ret = super.properties(index, offset + 8, mode, value); + } + + return ret; + } + + private void newFarSide() { + this._farSidePortalName = this._farSidePortal.getName(); + if (this._state == -1 && (this.flags & 262144) == 0) { + this._state = 2; + } + + this.recomputeFarPosition(); + this.setTransform(); + this.updateVisible(); + } + + @Override + public void saveState(Saver s) throws IOException { + Portal tmp = null; + if (this._farSideWorld != null || this._farSidePortal != null && (!this._farSidePortal.isActive() || this._farSidePortal instanceof NonPersister)) { + tmp = this._farSidePortal; + this._farSidePortal = null; + } + + s.saveVersion(9, classCookie); + super.saveState(s); + s.saveBoolean(this._farSideIsPortal); + s.saveBoolean(this._allowDownload); + s.saveString(this._farSidePortalName); + s.saveMaybeNull(this._farSidePortal); + URL.save(s, this._farSideWorld); + s.saveString(this._farSideRoomName); + s.saveFloat(this._userFarx); + s.saveFloat(this._userFary); + s.saveFloat(this._userFarz); + s.saveFloat(this._userFartheta); + if (tmp != null) { + this._farSidePortal = tmp; + } + } + + public void superRestoreState(Restorer r) throws IOException, TooNewException { + this.restoreWObjectState(r); + this.setMaterial(new Material(Color.black)); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + float x = 0.0F; + float y = 0.0F; + float z = 0.0F; + int vers = r.restoreVersion(classCookie); + switch (vers) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + r.setOldFlag(); + this.superRestoreState(r); + if (vers < 6) { + if (vers == 0) { + r.restoreInt(); + } + + x = r.restoreFloat(); + y = r.restoreFloat(); + z = r.restoreFloat(); + this.scale(x, 1.0F, z); + } + + if (r.restoreBoolean()) { + this.flags |= 4; + } + + if (vers >= 4) { + this._farSidePortalName = r.restoreString(); + } + + this._farSidePortal = (Portal)r.restoreMaybeNull(); + if (vers == 1) { + String n = r.restoreString(); + if (!"".equals(n)) { + this.setName(n); + } + } else if (vers >= 3) { + if (vers >= 7) { + this._farSideWorld = URL.restore(r); + } else { + this._farSideWorld = URL.restore(r, ".world"); + } + + this._farSideRoomName = r.restoreString(); + this._farx = r.restoreFloat(); + this._fary = r.restoreFloat(); + this._farz = r.restoreFloat(); + this._fartheta = r.restoreFloat(); + Material initialCover = Material.restore(r); + Material downloadCover = Material.restore(r); + if (initialCover != null) { + this.setMaterial(initialCover); + if (downloadCover != null && (initialCover.textureName == null || !initialCover.textureName.equals(downloadCover.textureName))) { + System.out + .println( + "Both initial and download covers, " + + initialCover.textureName + + " and " + + downloadCover.textureName + + ", in " + + this.getName() + + " -- using initial." + ); + } + } else { + this.setMaterial(downloadCover); + } + + if (vers >= 5) { + this._farSideIsPortal = r.restoreBoolean(); + } + } + break; + case 8: + case 9: + super.restoreState(r); + this._farSideIsPortal = r.restoreBoolean(); + if (vers >= 9) { + this._allowDownload = r.restoreBoolean(); + } + + this._farSidePortalName = r.restoreString(); + this._farSidePortal = (Portal)r.restoreMaybeNull(); + this._farSideWorld = URL.restore(r); + this._farSideRoomName = r.restoreString(); + this._farx = r.restoreFloat(); + this._fary = r.restoreFloat(); + this._farz = r.restoreFloat(); + this._fartheta = r.restoreFloat(); + break; + default: + throw new TooNewException(); + } + + if (vers <= 4 && this._farSideRoomName != null && this._farSidePortal == null && this._farSidePortalName == null) { + this._farSideIsPortal = false; + } + + this._userFarx = this._farx; + this._userFary = this._fary; + this._userFarz = this._farz; + this._userFartheta = this._fartheta; + } + + @Override + public void postRestore(int version) { + super.postRestore(version); + if (this.getOwner() != null) { + this.addToRoom(this.getOwner()); + Room r = this.getOwner().getRoom(); + if (this._farSidePortal == null) { + this.reset(); + } else { + this.newFarSide(); + } + } + } + + @Override + public String toString() { + String to; + if (this._state == -1) { + to = "(not connected)"; + } else { + if (this._farSideWorld != null) { + to = this._farSideWorld.toString(); + } else { + to = ""; + } + + if (this._farSideRoom != null) { + to = to + "#" + this._farSideRoomName; + } + + if (this._farSidePortalName != null) { + to = to + "#" + this._farSidePortalName; + } + } + + return super.toString() + "[Connected To " + to + "]"; + } + + public Portal triggerLoad() { + if (this._farSideWorld != null && this._farSideRoomName != null) { + if (this._farSidePortal != null && !this._farSidePortal.isActive()) { + this.reset(); + } + + if (this._state == 0) { + this._state = 1; + World.load(this._farSideWorld, this); + } + } + + return this; + } + + @Override + public void loadedURLSelf(URLSelf o, URL url, String err) { + if (this.frozeFrameEvents) { + this.frozeFrameEvents = false; + Console.setFreezeFrameEvents(false); + } + + if (this._state == 1) { + if (err == null && o instanceof World) { + World w = (World)o; + this.setFarSideRoom(w.getRoom(this._farSideRoomName)); + if (this._farSideRoom != null) { + this._state = 2; + this.findFarSidePortal(true); + } else { + Object[] arguments = new Object[]{new String(this._farSideRoomName), new String("" + this._farSideWorld)}; + Console.println(MessageFormat.format(Console.message("Cant-find-remote"), arguments)); + this._state = -1; + } + } else { + if (err == null) { + err = "doesn't contain a World"; + o.decRef(); + } + + String readable = TeleportAction.getReadableNameOfWorld(url); + this._state = -1; + if (this._allowDownload && !World.isProscribed(url, false)) { + Object[] arguments = new Object[]{new String(readable)}; + Console.println(MessageFormat.format(Console.message("Dont-have-world"), arguments)); + String packageName = TeleportAction.getPackageNameOfWorld(url); + if (packageName != null) { + NetUpdate.loadWorld(packageName, false); + } + } + } + + this.updateVisible(); + } + } +} diff --git a/NET/worlds/scape/PosableAction.java b/NET/worlds/scape/PosableAction.java new file mode 100644 index 0000000..cab8508 --- /dev/null +++ b/NET/worlds/scape/PosableAction.java @@ -0,0 +1,74 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class PosableAction extends Action { + private String action = "wave"; + private static Object classCookie = new Object(); + + public PosableAction() { + } + + public PosableAction(String action) { + this.action = action; + this.rightMenuLabel = action; + } + + @Override + public Persister trigger(Event e, Persister seqID) { + SuperRoot o = this.getOwner(); + if (o instanceof PosableShape) { + ((PosableShape)o).animate(this.action); + } else if (o instanceof Drone) { + ((Drone)o).animate(this.action); + } else if (o instanceof Pilot) { + ((Pilot)o).animate(this.action); + } + + return null; + } + + @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 = StringPropertyEditor.make(new Property(this, index, "Action Name")); + } else if (mode == 1) { + ret = new String(this.action); + } else if (mode == 2) { + this.action = (String)value; + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public String toString() { + return super.toString() + "[action " + this.action + "]"; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + s.saveString(this.action); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this.action = r.restoreString(); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/PosableDrone.java b/NET/worlds/scape/PosableDrone.java new file mode 100644 index 0000000..d6b6ec3 --- /dev/null +++ b/NET/worlds/scape/PosableDrone.java @@ -0,0 +1,197 @@ +package NET.worlds.scape; + +import NET.worlds.console.BBAnimateDroneCommand; +import NET.worlds.console.BlackBox; +import NET.worlds.console.Console; +import NET.worlds.core.IniFile; +import NET.worlds.network.ObjID; +import NET.worlds.network.URL; +import NET.worlds.network.WorldServer; +import java.io.IOException; +import java.net.MalformedURLException; +import java.util.Enumeration; +import java.util.Vector; + +public class PosableDrone extends Drone implements FrameHandler { + static PosableDroneLoader droneLoader = new PosableDroneLoader(); + public static boolean threadDroneLoads = IniFile.gamma().getIniInt("ThreadDroneLoading", 0) == 1; + static boolean droneLoaderStarted = false; + private PosableShape pendingShape = null; + private static Object classCookie = new Object(); + + public void SetPendingShape(PosableShape ps) { + this.pendingShape = ps; + } + + @Override + public boolean handle(FrameEvent evt) { + if (this.pendingShape != null) { + PosableShape ps = this.getInternalPosableShape(); + if (ps != null) { + ps.detach(); + } + + this.add(this.pendingShape); + this.pendingShape = null; + } + + return super.handle(evt); + } + + public PosableDrone(ObjID objID, WorldServer serv, URL url) { + super(objID, serv); + this.makeFigure(url); + } + + public PosableDrone(ObjID objID, WorldServer serv) { + super(objID, serv); + this.loadInit(); + } + + public PosableDrone() { + } + + @Override + public void loadInit() { + this.makeFigure(PosableShape.getDefaultURL()); + } + + public synchronized URL getPosableShapeURL() { + PosableShape ps = this.getInternalPosableShape(); + return ps == null ? null : ps.getURL(); + } + + @Override + public Drone setAvatarNow(URL url) { + if (!this.shouldBeMuted() && (url.endsWith(".rwx") || url.endsWith(".rwg"))) { + if (this.shouldBeForcedHuman()) { + url = PosableShape.getHuman(url); + } + + url = PosableShape.getPermitted(url, this.getWorld()); + PosableShape ps = this.getInternalPosableShape(); + if (ps != null) { + if (url.equals(ps.getURL())) { + return this; + } + + ps.detach(); + } + + this.makeFigure(url); + return this; + } else { + return super.setAvatarNow(url); + } + } + + public void makeFigure(URL url) { + boolean isPilot = false; + if (Console.getActive() != null && Console.getActive().getPilot() != null && Console.getActive().getPilot().hasContents()) { + isPilot = Console.getActive().getPilot().contentsContain(this); + } + + if (!isPilot) { + isPilot = this.isPilotDrone(url); + } + + boolean loadAsynchronously = false; + + try { + if (!PosableDroneLoader.avatarExistsLocally(url)) { + loadAsynchronously = true; + } else { + loadAsynchronously = !isPilot && !url.toString().equals(PosableShape.getDefaultURL().toString()); + } + } catch (MalformedURLException var5) { + loadAsynchronously = false; + } + + if (loadAsynchronously && threadDroneLoads) { + if (!droneLoaderStarted) { + droneLoaderStarted = true; + Thread t = new Thread(droneLoader, "DroneLoaderDaemon"); + t.setDaemon(true); + t.setPriority(1); + t.start(); + } + + droneLoader.load(this, url); + } else { + PosableShape ps; + if (VehicleShape.isVehicle(url)) { + ps = new VehicleShape(url); + } else { + ps = new PosableShape(url); + } + + ps.setVisible(true); + ps.setBumpable(false); + if (!this.isPilotDrone(url)) { + ps.enableLOD(true); + } + + this.add(ps); + } + } + + public PosableShape getInternalPosableShape() { + Enumeration e = this.getContents(); + + while (e.hasMoreElements()) { + Object o = e.nextElement(); + if (o instanceof PosableShape) { + return (PosableShape)o; + } + } + + return null; + } + + public boolean isPilotDrone(URL url) { + return Console.getActive() != null && Console.getActive().pendingPilot.equals(url.toString()); + } + + @Override + public float animate(String action) { + super.animate(action); + BlackBox.getInstance().submitEvent(new BBAnimateDroneCommand(this.getName(), action)); + PosableShape ps = this.getInternalPosableShape(); + return ps != null ? ps.animate(action) : 0.0F; + } + + @Override + public Vector getAnimationList() { + PosableShape ps = this.getInternalPosableShape(); + return ps != null ? ps.getAnimationList() : super.getAnimationList(); + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(2, classCookie); + super.saveState(s); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + int vers = r.restoreVersion(classCookie); + switch (vers) { + case 0: + case 1: + if (vers == 0) { + this.restoreStateDrone(r); + } else { + super.restoreState(r); + } + + r.setOldFlag(); + this.makeFigure(URL.make("avatar:" + r.restoreString() + ".rwx")); + break; + case 2: + super.restoreState(r); + break; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/PosableDroneLoader.java b/NET/worlds/scape/PosableDroneLoader.java new file mode 100644 index 0000000..191ef6d --- /dev/null +++ b/NET/worlds/scape/PosableDroneLoader.java @@ -0,0 +1,84 @@ +package NET.worlds.scape; + +import NET.worlds.core.Archive; +import NET.worlds.network.URL; +import java.net.MalformedURLException; +import java.util.Enumeration; +import java.util.Vector; + +public class PosableDroneLoader implements Runnable { + static final boolean debug = false; + DroneLoader loader; + private static boolean useCachedFiles = URL.usingCachedAvatars(); + private Vector droneList = new Vector(); + + PosableDroneLoader() { + } + + public static boolean usingCache() { + return useCachedFiles; + } + + public static PendingDrone makePendingDrone(PosableDrone _drone, URL _url) { + return (PendingDrone)(useCachedFiles ? new PendingCacheDrone(_drone, _url) : new PendingDrone(_drone, _url)); + } + + public void load(PosableDrone _drone, URL _url) { + PendingDrone pd = makePendingDrone(_drone, _url); + this.droneList.addElement(pd); + if (this.loader != null) { + this.loader.wakeUp(); + } + } + + public boolean isPending(PosableDrone _drone, URL _url) { + Vector listCopy = (Vector)this.droneList.clone(); + Enumeration enums = listCopy.elements(); + + while (enums.hasMoreElements()) { + PendingDrone pd = (PendingDrone)enums.nextElement(); + if (pd.getUrl().toString().equals(_url.toString()) && pd.getDrone().toString().equals(_drone.toString())) { + return true; + } + } + + return false; + } + + @Override + public void run() { + this.loader = new DroneLoader(); + + while (true) { + this.loader.load(this.droneList); + } + } + + public static String getAvatarBaseName(URL pUrl) { + String s = null; + int dot = pUrl.getAbsolute().indexOf(46); + if (dot != -1) { + s = pUrl.getAbsolute().substring(7, dot); + } + + return s; + } + + public static boolean avatarExistsLocally(URL pUrl) throws MalformedURLException { + if (useCachedFiles) { + return false; + } else if (pUrl.toString().equals(PosableShape.getDefaultURL().toString())) { + return true; + } else if (!pUrl.getAbsolute().substring(0, 7).equals("avatar:")) { + throw new MalformedURLException("Not an avatar URL"); + } else { + String s = getAvatarBaseName(pUrl); + if (s == null) { + throw new MalformedURLException("No file extension"); + } else { + URL realFile = URL.make(pUrl, s + ".bod"); + return Archive.exists(realFile.unalias()); + } + } + } +} diff --git a/NET/worlds/scape/PosableShape.java b/NET/worlds/scape/PosableShape.java new file mode 100644 index 0000000..7ed5610 --- /dev/null +++ b/NET/worlds/scape/PosableShape.java @@ -0,0 +1,1331 @@ +package NET.worlds.scape; + +import NET.worlds.console.AvMenu; +import NET.worlds.console.Console; +import NET.worlds.console.DefaultConsole; +import NET.worlds.core.IniFile; +import NET.worlds.core.ServerTableManager; +import NET.worlds.core.Std; +import NET.worlds.core.Timer; +import NET.worlds.core.TimerCallback; +import NET.worlds.network.Cache; +import NET.worlds.network.CacheFile; +import NET.worlds.network.NetUpdate; +import NET.worlds.network.URL; +import NET.worlds.network.WorldServer; +import java.awt.Color; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.net.MalformedURLException; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.StringTokenizer; +import java.util.Vector; + +public class PosableShape extends Shape implements FrameHandler, Prerenderable, MouseDownHandler, ShapeLoaderListener, TimerCallback { + protected int figureType = -1; + private float closestView = 10000.0F; + private int farViewCount; + private Vector<String> animationList; + private boolean COG; + private boolean setPrepFigure = true; + private boolean runPrepFigure = this.setPrepFigure; + private static URL defaultURL = URL.make("avatar:aura.0PG.rwg"); + protected DroneAnimator animator = null; + private boolean recomputeHeight = false; + private boolean firstURL = true; + private Shape subparts; + public static Color[] colorTable = new Color[]{ + new Color(0, 0, 0), + new Color(51, 102, 204), + new Color(234, 162, 115), + new Color(255, 102, 51), + new Color(255, 153, 204), + new Color(139, 232, 0), + new Color(43, 131, 0), + new Color(51, 51, 153), + new Color(145, 51, 204), + new Color(153, 204, 255), + new Color(204, 51, 102), + new Color(0, 204, 102), + new Color(255, 204, 102), + new Color(102, 102, 102), + new Color(254, 123, 26), + new Color(255, 51, 153), + new Color(188, 51, 204), + new Color(204, 0, 38), + new Color(118, 0, 0), + new Color(153, 102, 51), + new Color(196, 196, 196), + new Color(204, 153, 255), + new Color(255, 255, 255), + new Color(255, 179, 2), + new Color(247, 227, 2), + new Color(255, 255, 153) + }; + private Hashtable<Object, Vector<Object>> actions; + private int scanPos; + private static Material origMat = new Material(null); + public static String base64 = "-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+"; + private static String[] permittedList = ServerTableManager.instance().getTable("permittedList"); + private static String[] faceList = ServerTableManager.instance().getTable("faceList"); + private static String[] humanList = ServerTableManager.instance().getTable("humanList"); + private static String[] secretList = ServerTableManager.instance().getTable("secretList"); + private static Hashtable<String, String> permittedHash = new Hashtable<String, String>(); + private static Vector<String> permittedNames = new Vector<String>(); + private static Vector<String> faceNames = new Vector<String>(); + private static Hashtable<String, String> humanHash = new Hashtable<String, String>(); + private static Hashtable<String, Vector<String>> worldHash = new Hashtable<String, Vector<String>>(); + private static Hashtable<String, String> secretNames = new Hashtable<String, String>(); + private static Hashtable<String, String> faceTextures = new Hashtable<String, String>(); + static boolean gotServerAvatarList; + static boolean serverAvatarListError; + private Enumeration<String> animations; + private boolean doLOD = false; + protected int expressionStart; + protected int nextChange; + protected Vector<PosableShape.TimedMatChange> expressionChanges; + private static Object classCookie; + + static { + if (!NetUpdate.isInternalVersion()) { + for (int i = 0; i < secretList.length; i++) { + secretNames.put(secretList[i], secretList[i]); + } + } + + for (int i = 0; i < permittedList.length; i += 2) { + if (secretNames.get(permittedList[i]) == null) { + permittedNames.addElement(permittedList[i]); + if (permittedList[i + 1].indexOf("DgT") >= 0) { + faceNames.addElement(permittedList[i]); + } + } + + if (permittedList[i + 1] != null) { + permittedHash.put(permittedList[i], permittedList[i + 1]); + } + } + + for (int i = 1; i < humanList.length; i += 2) { + humanHash.put(humanList[i - 1], humanList[i]); + } + + for (int i = 0; i < faceList.length; i += 2) { + faceTextures.put(faceList[i], faceList[i + 1]); + } + + gotServerAvatarList = false; + serverAvatarListError = false; + classCookie = new Object(); + } + + public static URL getDefaultURL() { + return defaultURL; + } + + public PosableShape(URL url) { + this.setURL(url); + } + + public PosableShape(URL url, boolean isAW) { + this.setPrepFigure = isAW; + this.runPrepFigure = this.setPrepFigure; + this.setURL(url); + } + + public PosableShape() { + } + + @Override + public void loadInit() { + this.setURL(defaultURL); + } + + @Override + public void markVoid() throws ClassCastException { + if (this.animator != null) { + this.animator.endanimations(); + if (this.figureType != -1) { + this.animator.delayedDeltype(this.figureType); + } + } + + this.animator = null; + this.getRoom().removePrerenderHandler(this); + super.markVoid(); + } + + @Override + public synchronized void recursiveAddRwChildren(WObject parent) { + if (!this.hasClump()) { + super.recursiveAddRwChildren(parent); + this.getRoom().addPrerenderHandler(this); + if (this.isFullyLoaded() && this.figureType != -1) { + DroneAnimator.addtype(this.figureType); + if (this.runPrepFigure) { + DroneAnimator.prepFigure(this, this.COG); + } + + this.animator = new DroneAnimator(); + } + } + } + + @Override + public void notifyShapeLoaded(Shape s) { + this.recomputeHeight = true; + } + + @Override + public Transform getObjectToWorldMatrix() { + return this.clumpID != 0 ? this.getJointedObjectToWorldMatrix(Transform.make()) : super.getObjectToWorldMatrix(); + } + + public static int getFigureType(URL url) { + String bodyType = getBodyType(url); + return bodyType == null ? -1 : DroneAnimator.getnameindex(bodyType); + } + + public static int getFigureType(String bodyType) { + bodyType = getBodyType(bodyType); + return bodyType == null ? -1 : DroneAnimator.getnameindex(bodyType); + } + + protected void download(URL pUrl) { + PendingDrone pd = PosableDroneLoader.makePendingDrone(null, pUrl); + Enumeration<String> e = getComponentAvatars(pd.getUrl()); + if (e != null) { + while (e.hasMoreElements()) { + String avURL = e.nextElement(); + pd.download(URL.make(avURL)); + } + } + } + + @Override + public synchronized void setURL(URL newName) { + if (newName != this.url && (newName == null || !newName.equals(this.url))) { + if (newName == null || !newName.toString().startsWith("avatar:lod")) { + if (newName != null) { + this.download(newName); + int newType = getFigureType(newName); + if (newType != this.figureType) { + if (this.animator != null) { + this.animator.endanimations(); + if (this.figureType != -1) { + this.animator.delayedDeltype(this.figureType); + } + } + + this.animator = null; + this.figureType = newType; + this.animationList = null; + } + } + + this.setBaseLODURL(newName); + if (forceLODLevel != -1 && this.numDetailLevels > 0 && this.doLOD) { + this.setLOD(0.0F); + return; + } + } + + this.removeSubparts(); + if (newName != null && newName.getAbsolute().startsWith("avatar:")) { + try { + this.createSubparts(newName); + } catch (MalformedURLException var3) { + System.out.println("Received bogus PosableShape URL: " + newName); + return; + } + } + + super.setURL(newName); + } + } + + private String scanName(String s) { + int start = this.scanPos; + + char c; + while ((c = s.charAt(this.scanPos)) >= 'a' && c <= 'z' || c == '_') { + this.scanPos++; + } + + return s.substring(start, this.scanPos); + } + + public static String readName(String s, int pos) { + int start = pos; + + char c; + try { + while ((c = s.charAt(pos)) >= 'a' && c <= 'z' || c == '_') { + pos++; + } + } catch (StringIndexOutOfBoundsException var4) { + } + + return s.substring(start, pos); + } + + private int scanInt(String s) { + int start = this.scanPos; + + int val; + char c; + for (val = 0; (c = s.charAt(this.scanPos)) >= '0' && c <= '9'; this.scanPos++) { + val = 10 * val + (c - '0'); + } + + return val; + } + + private static Material scanTexture(String name, int frame) { + if (frame <= 0) { + name = "avatar:" + name + ".cmp"; + } else { + name = "avatar:" + name + frame + "s*.mov"; + } + + Material m = new Material(0.32F, 0.55F, 0.0F, colorTable[3], null, 1.0F, true, false); + m.loadTexture(URL.make(name)); + return m; + } + + public static Material readTexture(String s, int p) { + int frame = 0; + + char c; + while ((c = s.charAt(p)) >= '0' && c <= '9') { + frame = 10 * frame + (c - '0'); + p++; + } + + return scanTexture(readName(s, p), frame); + } + + public static boolean isValidTexture(String s) { + int len = s.length(); + int i = 0; + + char c; + while (i < len && (c = s.charAt(i)) >= '0' && c <= '9') { + i++; + } + + while (i < len) { + if (((c = s.charAt(i)) < 'a' || c > 'z') && c != '_') { + return false; + } + + i++; + } + + return true; + } + + private static int scanBase64(char c) { + int i = base64.indexOf(c); + return i < 0 ? 0 : i; + } + + public static Material readColor(String s, int p) { + char c = s.charAt(p++); + Material m = null; + if (c == '_') { + int color = s.charAt(p++) - 'A'; + if (color >= 0 && color < colorTable.length) { + m = new Material(0.32F, 0.55F, 0.0F, colorTable[color], null, 1.0F, true, false); + } else { + m = origMat; + } + } else { + int r = 4 * scanBase64(c); + int g = 4 * scanBase64(s.charAt(p++)); + int b = 4 * scanBase64(s.charAt(p++)); + m = new Material(0.32F, 0.55F, 0.0F, new Color(r, g, b), null, 1.0F, true, false); + } + + return m; + } + + private Material scanColor(String s) { + Material m = readColor(s, this.scanPos); + if (s.charAt(this.scanPos) == '_') { + this.scanPos += 2; + } else { + this.scanPos += 3; + } + + return m; + } + + private float getScale(char c) { + if (c >= 'a' && c <= 'z') { + return 1.0F - (c - 'a' + 1) * 0.025615385F; + } else { + return c >= 'A' && c <= 'Z' ? 1.0F / (1.0F - (c - 'A' + 1) * 0.025615385F) : 1.0F; + } + } + + private Material getMat(char c, Vector<Material> mats) { + int matNum = c - 'a'; + if (matNum < mats.size()) { + Material m = mats.elementAt(matNum); + return m == origMat ? origMat : (Material)m.clone(); + } else { + return null; + } + } + + private Shape getLimb(String s, String bodyType, int pos, int partNum, Shape parent, Vector<Material> mats, boolean loadNow) { + int end = s.length() - 4; + if (bodyType == null) { + if (parent instanceof PosableShape) { + bodyType = ""; + } else { + bodyType = Shape.getBodBase(parent.getURL()); + if (parent.getURL().toString().indexOf("lod/") != -1) { + bodyType = "lod/" + bodyType; + } + } + } + + Shape shape = new Shape(); + Shape subshape = shape; + shape.setURL(URL.make("avatar:" + bodyType + partNum / 10 + partNum % 10 + ".bod")); + int clumpsUsed = 0; + Material lastMat = null; + int delay = 0; + int lastTime = 0; + String actName = null; + boolean haveAddedChange = false; + if (pos > 0) { + this.scanPos = pos + 1; + + while (true) { + char c = s.charAt(this.scanPos++); + if (c >= 'A' && c <= 'Z') { + if (c == 'G') { + int num = this.scanInt(s); + if (num <= 0 || num > 99) { + num = partNum; + } + + bodyType = this.scanName(s); + if (bodyType.equals("")) { + break; + } + + subshape.setURL(URL.make("avatar:" + bodyType + num / 10 + num % 10 + ".bod")); + } else if (c == 'S') { + char xScale = s.charAt(this.scanPos++); + char yScale = s.charAt(this.scanPos++); + char zScale = s.charAt(this.scanPos++); + if (xScale == 'Z' && yScale == 'Z' && zScale == 'Z') { + this.runPrepFigure = false; + } + + subshape.scale(this.getScale(xScale), this.getScale(yScale), this.getScale(zScale)); + } else if (c != 'Q') { + if (c == 'C') { + assert false; + } else if (c == 'D') { + delay += (int)(1000.0 * (Math.pow(1.0932, scanBase64(s.charAt(this.scanPos++))) - 0.9F)); + } else if (c == 'A') { + actName = this.scanName(s); + this.animationList = null; + } else { + if (c != 'T' && c != 'C') { + this.scanPos--; + break; + } + + System.out.println("Illegal av " + this.url); + } + } + } else if (c >= 'a') { + Material m = this.getMat(c, mats); + if (m != null) { + if (delay == 0) { + delay = 50; + } + + lastTime += delay; + if (lastMat != null) { + if (!haveAddedChange) { + haveAddedChange = true; + this.addChange(lastTime - delay, lastMat, subshape); + } + + this.addChange(lastTime, m, subshape); + } + + if (m != origMat) { + subshape.setMaterial(m); + } + + lastMat = m; + delay = 0; + } + } else { + if (c < '0' || c > '9') { + break; + } + + this.scanPos--; + int clumpNum = this.scanInt(s) - clumpsUsed; + clumpsUsed++; + subshape = new SubclumpShape(); + subshape.setURL(URL.make("system:subclump" + clumpNum)); + shape.add(subshape); + lastMat = null; + haveAddedChange = false; + lastTime = 0; + delay = 0; + } + + if (this.scanPos > end) { + this.scanPos = end; + return parent; + } + } + } + + if (bodyType.equals("")) { + return parent; + } else { + shape.addLoadListener(this); + if (ProgressiveAdder.get().enabled() && !loadNow) { + ProgressiveAdder.get().scheduleForAdd(parent, shape); + } else { + parent.add(shape); + } + + if (this.subparts == null) { + this.subparts = shape; + } + + return shape; + } + } + + private void addChange(int when, Material mat, Shape s) { + PosableShape.TimedMatChange t = new PosableShape.TimedMatChange(); + t.when = when; + t.mat = mat; + t.limb = s; + mat.setKeepLoaded(true); + int i = 0; + if (this.expressionChanges == null) { + this.expressionChanges = new Vector<PosableShape.TimedMatChange>(); + this.expressionStart = Std.getRealTime(); + this.nextChange = 0; + } else { + for (i = this.expressionChanges.size(); i > 0; i--) { + PosableShape.TimedMatChange o = this.expressionChanges.elementAt(i - 1); + if (when >= o.when) { + break; + } + } + } + + this.expressionChanges.insertElementAt(t, i); + } + + public static Enumeration<String> getComponentAvatars(URL pUrl) { + if (pUrl == null) { + return null; + } else { + Vector<String> v = new Vector<String>(); + String urlString = pUrl.getAbsolute(); + if (urlString.startsWith("avatar:") && urlString.endsWith(".rwg")) { + String baseAv = urlString.substring(7, urlString.indexOf(46)); + v.addElement("avatar:" + baseAv + ".rwg"); + int pos = urlString.indexOf(46); + int len = urlString.length() - 4; + + label82: + while (pos < len) { + char c = urlString.charAt(pos++); + if (c >= 'A' && c <= 'Z') { + switch (c) { + case 'A': + case 'Q': + case 'T': + default: + break; + case 'C': + c = urlString.charAt(pos++); + if (c == '_') { + pos++; + } else { + pos += 2; + } + break; + case 'D': + pos++; + break; + case 'G': + while (pos < len) { + c = urlString.charAt(pos); + if (c < '0' || c > '9') { + break; + } + + pos++; + } + + String bodyType = ""; + + while (true) { + if (pos < len) { + c = urlString.charAt(pos); + if ((c < '0' || c > '9') && c >= 'a' && c <= 'z') { + bodyType = bodyType + c; + pos++; + continue; + } + } + + if (bodyType != "" && bodyType.length() > 1) { + v.addElement("avatar:" + bodyType + ".rwg"); + } + continue label82; + } + case 'S': + pos += 3; + } + } + } + + return v.elements(); + } else { + return null; + } + } + } + + public static int skipLimb(String s, int pos) { + int len = s.length() - 4; + + while (pos < len) { + char c = s.charAt(pos++); + if (c >= 'A' && c <= 'Z') { + switch (c) { + case 'A': + case 'G': + case 'Q': + case 'T': + break; + case 'C': + c = s.charAt(pos++); + if (c == '_') { + pos++; + } else { + pos += 2; + } + break; + case 'D': + pos++; + break; + case 'S': + pos += 3; + break; + default: + return pos - 1; + } + } else if ((c < 'a' || c > 'z') && (c < '0' || c > '9')) { + break; + } + } + + return -1; + } + + private String findStarts(String s, int end, int[] offs, String bodyType, Vector<Material> mats) { + String lastTextureName = bodyType; + + while (this.scanPos < end) { + char section = s.charAt(this.scanPos); + if (section < 'A' || section > 'Z') { + return s; + } + + offs[section - 'A'] = this.scanPos++; + + while (this.scanPos < end) { + char c = s.charAt(this.scanPos++); + if (c < 'A' || c > 'Z') { + if ((c < '0' || c > '9') && (c < 'a' || c > 'z')) { + return s.substring(0, this.scanPos - 1) + ".rwg"; + } + } else if (c == 'G') { + this.scanInt(s); + this.scanName(s); + } else if (c == 'S') { + this.scanPos += 3; + } else if (c != 'Q') { + if (c == 'C' || c == 'T') { + int start = this.scanPos - 1; + char letter = (char)(97 + mats.size()); + Material mat; + if (c == 'C') { + mat = this.scanColor(s); + } else { + int num = this.scanInt(s); + String name = this.scanName(s); + if (name.equals("")) { + name = lastTextureName; + } else { + lastTextureName = name; + } + + mat = scanTexture(name, num); + } + + mats.addElement(mat); + s = s.substring(0, start) + 'Q' + letter + s.substring(this.scanPos); + int cutLen = this.scanPos - start - 2; + this.scanPos -= cutLen; + end -= cutLen; + } else if (c == 'D') { + this.scanPos++; + } else { + if (c != 'A') { + this.scanPos--; + break; + } + + this.scanName(s); + } + } + } + } + + return s; + } + + public static Vector<String> getPermittedNames() { + return permittedNames; + } + + public static String[] getPermittedList() { + return permittedList; + } + + public static void downloadPermittedNames() { + if (!gotServerAvatarList) { + serverAvatarListError = false; + WorldServer w = Pilot.getActive().getServer(); + if (w != null && w.getGalaxy() != null) { + String avatarList = Console.getActive().getScriptServer() + "getavlist.pl?u=" + w.getGalaxy().getChatname(); + if (w.getGalaxy().getSerialNum() != null) { + avatarList = avatarList + "&s=" + w.getGalaxy().getSerialNum(); + } + + URL avatarListURL = URL.make(avatarList); + CacheFile cf = Cache.getFile(avatarListURL, true); + cf.waitUntilLoaded(); + if (!cf.error()) { + permittedNames.removeAllElements(); + humanHash.clear(); + worldHash.clear(); + + try { + RandomAccessFile f = new RandomAccessFile(cf.getLocalName(), "r"); + + while (f.getFilePointer() < f.length()) { + String line = f.readLine(); + if (!line.startsWith("//")) { + StringTokenizer st = new StringTokenizer(line); + if (st.countTokens() > 2) { + String name = st.nextToken(); + permittedNames.addElement(name); + String gender = st.nextToken(); + if (gender.equals("m") || gender.equals("f")) { + humanHash.put(name, gender); + } + + Vector<String> worldList = new Vector<String>(); + + while (st.hasMoreTokens()) { + worldList.addElement(st.nextToken()); + } + + worldHash.put(name, worldList); + } + } + } + + f.close(); + } catch (Exception var10) { + System.out.println("Error parsing avatar list: " + var10.toString()); + serverAvatarListError = true; + return; + } + + gotServerAvatarList = true; + Console c = Console.getActive(); + if (c instanceof DefaultConsole) { + DefaultConsole dc = (DefaultConsole)c; + dc.getAvatarMenu().rebuildVIPMenu(); + } + + if (c.getPilot() != null) { + c.getPilot().resetAvatarNow(); + } + + AvMenu.rebuildHeadList(); + } else { + serverAvatarListError = true; + } + } + } + } + + public static URL getPermitted(URL in, World world) { + if (in.endsWith(".mov")) { + return in; + } else if (NetUpdate.isInternalVersion()) { + return in; + } else if (!gotServerAvatarList && !serverAvatarListError) { + return in; + } else if (serverAvatarListError) { + return validateAvatar(in.getAbsolute()) ? in : getDefAv(); + } else { + Enumeration<String> e = getComponentAvatars(in); + + while (e != null && e.hasMoreElements()) { + String baseAv = e.nextElement(); + String s = getBodyType(URL.make(baseAv)); + if (s == null) { + return getDefAv(); + } + + Vector<String> allowedWorlds = worldHash.get(s); + if (allowedWorlds == null) { + return getDefAv(); + } + + boolean worldOK = false; + Enumeration<String> we = allowedWorlds.elements(); + + while (true) { + if (we.hasMoreElements()) { + String thisWorld = we.nextElement(); + if (thisWorld == null) { + return getDefAv(); + } + + if (thisWorld.equals("all")) { + worldOK = true; + } else { + thisWorld = thisWorld.replace('_', ' ').toLowerCase().trim(); + if (world == null) { + worldOK = true; + continue; + } + + if (!thisWorld.equals(world.toString().toLowerCase().trim())) { + continue; + } + + worldOK = true; + } + } + + if (!worldOK) { + return getDefAv(); + } + break; + } + } + + return in; + } + } + + public static Vector<String> getFaceNames() { + return faceNames; + } + + public static URL getAvURL(String bodyType) { + Object newName = permittedHash.get(bodyType); + return newName instanceof String ? URL.make("avatar:" + (String)newName) : null; + } + + public static boolean validateAvatar(String av) { + System.out.println("Validating " + av); + String baseAv = getBodyType(URL.make(av)); + return baseAv == null ? false : permittedHash.get(baseAv) != null; + } + + public static String convertLODToParent(String bodyType) { + String result = bodyType; + if (bodyType.startsWith("lod/")) { + result = bodyType.substring(4, bodyType.length() - 1); + } + + return result; + } + + public static String getBodyType(URL url) { + if (url == null) { + return null; + } else { + String str = url.getAbsolute(); + if (str.startsWith("avatar:") && (str.endsWith(".rwg") || str.endsWith(".RWG")) && str.charAt(7) != '.') { + int pos = str.indexOf(".", 7); + String bodyType = str.substring(7, pos).toLowerCase(); + bodyType = convertLODToParent(bodyType); + if (str.charAt(pos + 1) != '0') { + bodyType = getBodyType(bodyType); + } + + return bodyType; + } else { + return null; + } + } + } + + static URL getDefAv() { + return URL.make(IniFile.override().getIniString("DefaultArticAv", "avatar:willy.rwg")); + } + + public static URL getHuman(URL url) { + if (url.endsWith(".mov")) { + return HoloDrone.getHuman(url); + } else { + String s = getBodyType(url); + if (s == null) { + return getDefAv(); + } else { + String gender = humanHash.get(s); + if (gender == null) { + return getDefAv(); + } else { + URL def = URL.make("avatar:" + s + ".rwg"); + String str = url.getAbsolute(); + int pos = str.indexOf(".0EC_"); + if (pos >= 0 && str.length() >= pos + 7 && "_AC".indexOf(str.charAt(pos + 5)) >= 0) { + if (!gender.equals("m") + || str.indexOf("yank") < 0 + || str.regionMatches(pos + 6, "TyankshirtC_", 0, 12) && str.regionMatches(pos + 19, "C-2bTyankstripe", 0, 15)) { + pos = str.lastIndexOf("HDgT2"); + if (pos >= 0 && str.length() >= pos + 7) { + String faceGender = humanHash.get(readName(str, pos + 5)); + if (faceGender != null && faceGender.equals(gender)) { + pos = str.lastIndexOf("NS"); + if (pos >= 0 && str.length() >= pos + 3 && "0abcdABCD".indexOf(str.charAt(pos + 2)) >= 0) { + pos += 5; + if (str.length() < pos + 2) { + return def; + } else { + if (str.charAt(pos) == 'G') { + String headGender = humanHash.get(readName(str, pos + 1)); + if (headGender == null || !headGender.equals(gender)) { + return def; + } + } + + return url; + } + } else { + return def; + } + } else { + return def; + } + } else { + return def; + } + } else { + return def; + } + } else { + return def; + } + } + } + } + } + + public URL getHuman() { + return getHuman(this.getURL()); + } + + public static String getBodyType(String basename) { + String str = permittedHash.get(basename); + if (str != null) { + basename = str.substring(0, str.indexOf(".")); + } + + return basename; + } + + public static int getMatPosition(String str, char type) { + int index = "abcdef".indexOf(type); + if (index >= 0) { + int p = str.indexOf(".0E"); + if (p >= 0) { + p += 3; + + for (int i = 0; i < index; i++) { + p = skipMat(str, p); + } + } + + return p; + } else { + int p = str.indexOf(".0E"); + if (p >= 0) { + for (p += 2; p >= 0; p = skipLimb(str, p)) { + if (str.charAt(p++) == type) { + return p; + } + } + } + + return p; + } + } + + public static String getCurrentAvCustomizable() { + URL av = Pilot.getActive().getSourceURL(); + String str = av.getAbsolute(); + if (str.startsWith("avatar:") && (str.endsWith(".rwg") || str.endsWith(".RWG")) && str.charAt(7) != '.') { + int pos = str.indexOf(".", 7); + if (!str.regionMatches(pos, ".0E", 0, 3)) { + av = getAvURL(str.substring(7, pos).toLowerCase()); + if (av == null) { + if (!str.substring(pos).equalsIgnoreCase(".rwg")) { + Console.println(Console.message("cant-cust-av")); + return null; + } + + str = "avatar:" + str.substring(7, pos) + ".0EC__C__C__C__C__C__" + "PeBbLcMcOaRcUcVaWeXeYIeJeK" + "NS000QaHDgT2tonyT3T2T1Q0f.rwg"; + } else { + str = av.getAbsolute(); + } + } + + return str; + } else { + Console.println(Console.message("non-cust-av")); + return null; + } + } + + public static int skipMat(String s, int i) { + char c = s.charAt(i); + int matEnd = i; + if (c == 'C') { + c = s.charAt(i + 1); + if (c == '_') { + matEnd = i + 3; + } else { + matEnd = i + 4; + } + } else if (c == 'T') { + matEnd = i + 1; + + while ((c = s.charAt(matEnd)) >= '0' && c <= '9') { + matEnd++; + } + + while ((c = s.charAt(matEnd)) >= 'a' && c <= 'z') { + matEnd++; + } + } else if (c >= 'a' && c <= 'z') { + matEnd = i + 1; + } + + return matEnd; + } + + public static String getFace(String bodyType) { + Object face = faceTextures.get(bodyType); + return face != null ? (String)face : "1" + bodyType; + } + + private void createSubparts(URL url) throws MalformedURLException { + String str = url.getAbsolute(); + int len = str.length(); + String bodyType = null; + this.runPrepFigure = this.setPrepFigure; + if (str.startsWith("avatar:") && (str.endsWith(".rwg") || str.endsWith(".RWG")) && str.charAt(7) != '.') { + this.scanPos = str.indexOf(".", 7); + bodyType = str.substring(7, this.scanPos).toLowerCase(); + if (str.charAt(this.scanPos + 1) != '0') { + this.scanPos = len - 4; + Object newName = permittedHash.get(bodyType); + if (newName != null) { + str = (String)newName; + this.scanPos = 0; + bodyType = this.scanName(str); + if (str.charAt(this.scanPos) != '.') { + throw new MalformedURLException(); + } + + if (str.charAt(this.scanPos + 1) != '0') { + throw new MalformedURLException(); + } + + this.scanPos += 2; + } + } else { + this.scanPos += 2; + } + } else { + this.scanPos = 0; + str = ".rwg"; + bodyType = "aura"; + } + + Vector<Material> mats = new Vector<Material>(); + int[] offsets = new int[26]; + str = this.findStarts(str, str.length() - 4, offsets, bodyType, mats); + if (this.subparts != null) { + throw new MalformedURLException(); + } else { + Shape groi = this.getLimb(str, bodyType, offsets[15], 1, this, mats, true); + Shape back = this.getLimb(str, null, offsets[1], 2, groi, mats, false); + Shape neck = this.getLimb(str, null, offsets[13], 3, back, mats, false); + Shape head = this.getLimb(str, null, offsets[7], 4, neck, mats, false); + Shape lupa = this.getLimb(str, null, offsets[11], 11, back, mats, false); + Shape lfor = this.getLimb(str, null, offsets[12], 12, lupa, mats, false); + Shape lhan = this.getLimb(str, null, offsets[14], 13, lfor, mats, false); + Shape rupa = this.getLimb(str, null, offsets[17], 6, back, mats, false); + Shape rfor = this.getLimb(str, null, offsets[20], 7, rupa, mats, false); + Shape rhan = this.getLimb(str, null, offsets[21], 8, rfor, mats, false); + Shape lthi = this.getLimb(str, null, offsets[8], 19, groi, mats, false); + Shape lcal = this.getLimb(str, null, offsets[9], 20, lthi, mats, false); + Shape lfoo = this.getLimb(str, null, offsets[10], 21, lcal, mats, false); + Shape rthi = this.getLimb(str, null, offsets[22], 15, groi, mats, false); + Shape rcal = this.getLimb(str, null, offsets[23], 16, rthi, mats, false); + Shape rfoo = this.getLimb(str, null, offsets[24], 17, rcal, mats, false); + Shape tail = this.getLimb(str, null, offsets[25], 24, groi, mats, false); + } + } + + protected void removeSubparts() { + if (this.subparts != null) { + this.subparts.discard(); + this.subparts = null; + this.actions = null; + } + } + + @Override + public void prerender(Camera cam) { + if (this.getVisible()) { + Point3Temp p = this.inCamSpace(cam); + boolean v = p != null && p.z > 1.0F && p.x < p.z && -p.x < p.z; + if (v) { + if (this.closestView > p.z) { + this.closestView = p.z; + } + + if (p.z > 700.0F && ++this.farViewCount > 10) { + if (this.closestView > 400.0F) { + this.closestView = 400.0F; + } + + this.farViewCount = 0; + } + } + } + } + + public float animate(String action) { + if (this.animator == null) { + return 0.0F; + } else { + if (action.length() == 1) { + char lower = action.toLowerCase().charAt(0); + char upper = action.toUpperCase().charAt(0); + Vector<String> al = this.getAnimationList(); + int len = al.size(); + + for (int i = 0; i < len; i++) { + String[] actionAliases = ServerTableManager.instance().getTable("actionAliases"); + String displayName = al.elementAt(i); + if (actionAliases != null) { + for (int j = 0; j < actionAliases.length; j += 2) { + if (displayName.toLowerCase().equals(actionAliases[j].toLowerCase())) { + displayName = actionAliases[j + 1]; + break; + } + } + } + + char c = displayName.charAt(0); + if (c == lower || c == upper) { + action = al.elementAt(i); + break; + } + } + } + + return this.performAnimationSequence(action); + } + } + + @Override + public void timerDone() { + if (this.animations.hasMoreElements()) { + String nextAnim = this.animations.nextElement(); + float time = this.animator.getAnimationTime(this.figureType, nextAnim); + this.animator.animate(this.figureType, nextAnim, Std.getRealTime()); + Timer tm = new Timer(time, this); + tm.start(); + } + } + + private float performAnimationSequence(String action) { + float totalTime = 0.0F; + Vector<String> vanimations = new Vector<String>(); + StringTokenizer tok = new StringTokenizer(action, "&\t\n\r"); + + while (tok.hasMoreTokens()) { + String subAction = tok.nextToken(); + totalTime += this.animator.getAnimationTime(this.figureType, subAction); + vanimations.addElement(subAction); + } + + this.animations = vanimations.elements(); + this.timerDone(); + return totalTime; + } + + public Vector<String> getAnimationList() { + if (this.animationList != null) { + return this.animationList; + } else { + this.animationList = DroneAnimator.getActionList(this.figureType); + return this.animationList; + } + } + + public void enableLOD(boolean flag) { + this.doLOD = flag; + } + + @Override + public boolean handle(MouseDownEvent e) { + return false; + } + + @Override + public boolean handle(FrameEvent fe) { + float dist = this.closestView; + this.closestView = 10000.0F; + if (this.animator != null && !(dist > 900.0F) && this.hasClump()) { + if (this.recomputeHeight) { + if (this.runPrepFigure) { + DroneAnimator.prepFigure(this, this.COG); + } + + this.recomputeHeight = false; + } + + if (this.doLOD && this.setLOD(dist)) { + return true; + } else { + int time = Std.getRealTime(); + Transform t = this.getObjectToWorldMatrix(); + this.animator.moveto(this.figureType, (short)t.getX(), (short)t.getY(), (short)t.getZ(), (short)(-t.getYaw()), time - 1); + this.animator.update(null, this, time, t.getScaleX(), dist > 700.0F); + t.recycle(); + if (this.expressionStart > 0) { + time -= this.expressionStart; + + while (true) { + PosableShape.TimedMatChange tx = this.expressionChanges.elementAt(this.nextChange); + if (time < tx.when) { + break; + } + + if (tx.mat != origMat) { + tx.limb.setMaterial(tx.mat); + } + + if (++this.nextChange >= this.expressionChanges.size()) { + this.nextChange = 0; + this.expressionStart += time; + break; + } + } + } + + return true; + } + } else { + return true; + } + } + + @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 = BooleanPropertyEditor.make(new Property(this, index, "Center of Gravity"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.COG); + } else if (mode == 2) { + this.COG = (Boolean)value; + URL u = this.getURL(); + this.setURL(defaultURL); + this.setURL(u); + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + s.saveBoolean(this.COG); + if (this.subparts != null) { + this.subparts.detach(); + super.saveState(s); + this.add(this.subparts); + } else { + super.saveState(s); + } + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 1: + this.COG = r.restoreBoolean(); + case 0: + super.restoreState(r); + return; + default: + throw new TooNewException(); + } + } + + @Override + public String toString() { + return this.getName(); + } + + class TimedMatChange { + Shape limb; + Material mat; + int when; + } +} diff --git a/NET/worlds/scape/Postrenderable.java b/NET/worlds/scape/Postrenderable.java new file mode 100644 index 0000000..c1f0994 --- /dev/null +++ b/NET/worlds/scape/Postrenderable.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface Postrenderable { + void postrender(Camera var1); +} diff --git a/NET/worlds/scape/PostspinBehavior.java b/NET/worlds/scape/PostspinBehavior.java new file mode 100644 index 0000000..a95efca --- /dev/null +++ b/NET/worlds/scape/PostspinBehavior.java @@ -0,0 +1,130 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class PostspinBehavior extends SpinBehavior implements FrameHandler { + private float xCenter; + private float yCenter; + private float zCenter; + private static Object classCookie = new Object(); + + public PostspinBehavior(float x, float y, float z, float cycleTime) { + this(x, y, z, 0.0F, 0.0F, 1.0F, cycleTime); + } + + public PostspinBehavior(float x, float y, float z, float ax, float ay, float az) { + this(x, y, z, ax, ay, az, 5.0F); + } + + public PostspinBehavior(float x, float y, float z, float ax, float ay, float az, float cycleTime) { + super(cycleTime, ax, ay, az); + this.xCenter = x; + this.yCenter = y; + this.zCenter = z; + } + + public PostspinBehavior() { + } + + public float getXCenter() { + return this.xCenter; + } + + public float getYCenter() { + return this.yCenter; + } + + public float getZCenter() { + return this.zCenter; + } + + public Point3Temp getCenter() { + return Point3Temp.make(this.xCenter, this.yCenter, this.zCenter); + } + + public void setXCenter(float c) { + this.xCenter = c; + } + + public void setYCenter(float c) { + this.yCenter = c; + } + + public void setZCenter(float c) { + this.zCenter = c; + } + + public void setCenter(Point3Temp center) { + this.xCenter = center.x; + this.yCenter = center.y; + this.zCenter = center.z; + } + + @Override + public boolean handle(FrameEvent e) { + if (this.enabled && this.cycleTime > 0.0F) { + e.receiver.moveBy(-this.xCenter, -this.yCenter, -this.zCenter); + e.receiver.postspin(this.ax, this.ay, this.az, 0.36F * e.dt / this.cycleTime); + e.receiver.moveBy(this.xCenter, this.yCenter, this.zCenter); + } + + return true; + } + + @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, "Center")); + } else if (mode == 1) { + ret = new Point3(this.getCenter()); + } else if (mode == 2) { + this.setCenter((Point3)value); + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public String toString() { + return super.toString() + + "[center " + + this.getCenter() + + ", axis " + + this.getAxis() + + ", cycleTime " + + this.cycleTime + + ", enabled " + + this.enabled + + "]"; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + s.saveFloat(this.xCenter); + s.saveFloat(this.yCenter); + s.saveFloat(this.zCenter); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this.xCenter = r.restoreFloat(); + this.yCenter = r.restoreFloat(); + this.zCenter = r.restoreFloat(); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/Prerenderable.java b/NET/worlds/scape/Prerenderable.java new file mode 100644 index 0000000..fac20c9 --- /dev/null +++ b/NET/worlds/scape/Prerenderable.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface Prerenderable { + void prerender(Camera var1); +} diff --git a/NET/worlds/scape/PrintAction.java b/NET/worlds/scape/PrintAction.java new file mode 100644 index 0000000..569079f --- /dev/null +++ b/NET/worlds/scape/PrintAction.java @@ -0,0 +1,71 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import java.io.IOException; + +public class PrintAction extends Action { + String txt = null; + private static Object classCookie = new Object(); + + public PrintAction() { + } + + public PrintAction(String text) { + this.txt = text; + } + + @Override + public Persister trigger(Event arg, Persister seqID) { + String msg = this.txt; + if (msg == null) { + msg = this.getName() + "Has-no-text"; + } + + Console.println(msg); + return null; + } + + @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 = StringPropertyEditor.make(new Property(this, index, "Text Out")); + } else if (mode == 1) { + ret = this.txt; + } else if (mode == 2) { + this.txt = (String)value; + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + s.saveString(this.txt); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this.txt = r.restoreString(); + return; + default: + throw new TooNewException(); + } + } + + @Override + public String toString() { + return super.toString() + "[" + this.txt + "]"; + } +} diff --git a/NET/worlds/scape/ProgressiveAdder.java b/NET/worlds/scape/ProgressiveAdder.java new file mode 100644 index 0000000..29696c2 --- /dev/null +++ b/NET/worlds/scape/ProgressiveAdder.java @@ -0,0 +1,49 @@ +package NET.worlds.scape; + +import NET.worlds.core.IniFile; +import java.util.Vector; + +public class ProgressiveAdder implements FrameHandler { + Vector addList = new Vector(); + static ProgressiveAdder theProgressiveAdder = null; + + public static ProgressiveAdder get() { + if (theProgressiveAdder == null) { + theProgressiveAdder = new ProgressiveAdder(); + } + + return theProgressiveAdder; + } + + ProgressiveAdder() { + } + + public boolean enabled() { + return IniFile.gamma().getIniInt("ProgressiveAvLoading", 0) == 1; + } + + void scheduleForAdd(WObject parent, WObject child) { + synchronized (this.addList) { + WObject[] objs = new WObject[]{parent, child}; + this.addList.addElement(objs); + } + } + + @Override + public boolean handle(FrameEvent fe) { + synchronized (this.addList) { + if (this.addList.size() > 0) { + WObject[] objs = (WObject[])this.addList.elementAt(0); + WObject parent = objs[0]; + WObject child = objs[1]; + if (!parent.discarded && !child.discarded) { + parent.add(child); + } + + this.addList.removeElementAt(0); + } + + return true; + } + } +} diff --git a/NET/worlds/scape/PropAdder.java b/NET/worlds/scape/PropAdder.java new file mode 100644 index 0000000..2ead54d --- /dev/null +++ b/NET/worlds/scape/PropAdder.java @@ -0,0 +1,48 @@ +package NET.worlds.scape; + +import NET.worlds.console.PolledDialog; + +public class PropAdder implements LibraryDrop { + protected VectorProperty property; + + protected PropAdder(VectorProperty property) { + this.property = property; + } + + public static VectorProperty make(VectorProperty property) { + return property.setAdder(new PropAdder(property)); + } + + public PolledDialog add(EditTile parent, String title) { + assert false; + + return null; + } + + public boolean hasAddDialog() { + return false; + } + + protected boolean checkObject(Object obj) { + return this.property.addTest(obj); + } + + @Override + public boolean libraryDrop(EditTile target, Object obj, boolean isPaste, boolean doDrop) { + if (this.checkObject(obj)) { + if (doDrop) { + if (isPaste) { + target.addUndoablePaste(this.property, obj); + } else { + target.addUndoableAdd(this.property, obj, true); + } + + return !(obj instanceof SuperRoot) || ((SuperRoot)obj).getOwner() != null; + } else { + return true; + } + } else { + return false; + } + } +} diff --git a/NET/worlds/scape/PropEditor.java b/NET/worlds/scape/PropEditor.java new file mode 100644 index 0000000..dfe2202 --- /dev/null +++ b/NET/worlds/scape/PropEditor.java @@ -0,0 +1,18 @@ +package NET.worlds.scape; + +import NET.worlds.console.PolledDialog; + +public abstract class PropEditor implements LibraryDrop { + protected Property property; + + protected PropEditor(Property property) { + this.property = property; + } + + public abstract PolledDialog edit(EditTile var1, String var2); + + @Override + public boolean libraryDrop(EditTile target, Object obj, boolean isPaste, boolean doDrop) { + return false; + } +} diff --git a/NET/worlds/scape/PropList.java b/NET/worlds/scape/PropList.java new file mode 100644 index 0000000..2a9d3a4 --- /dev/null +++ b/NET/worlds/scape/PropList.java @@ -0,0 +1,119 @@ +package NET.worlds.scape; + +import NET.worlds.core.IniFile; +import java.awt.List; +import java.util.Enumeration; +import java.util.Vector; + +public class PropList extends List { + private Object obj; + private Vector properties; + private static String[] sortOrder = new String[]{ + "Name", + "Tilesize", + "Transform", + "From", + "To", + "Extent", + "Bumpable", + "Collision Extent", + "Visible", + "Optimizable", + "DrawFirstOnIntersection", + "DrawOrderUnimportant" + }; + + static { + int numUserPreferences = IniFile.gamma().getIniInt("PropertyOrderCount", -1); + if (numUserPreferences >= 0) { + sortOrder = new String[numUserPreferences]; + + for (int i = 0; i < numUserPreferences; i++) { + sortOrder[i] = IniFile.gamma().getIniString("PropertyOrder" + i, ""); + } + } + } + + public static void setPreferences(String[] prefs) { + sortOrder = prefs; + } + + public Object getObject() { + return this.obj; + } + + public void setObject(Object obj) { + int selected = this.getSelectedIndex(); + if (obj != this.obj) { + selected = -1; + } + + this.obj = obj; + int count = this.countItems(); + if (count != 0) { + this.delItems(0, count - 1); + } + + Vector unsorted = new Vector(); + Enumeration e = new EnumProperties(obj); + + for (int var11 = 0; e.hasMoreElements(); var11++) { + Property p = (Property)e.nextElement(); + if (!(p instanceof VectorProperty) && (p.getEditor() != null || !(p.get() instanceof Properties))) { + unsorted.addElement(p); + } + } + + this.properties = new Vector(unsorted.size()); + + for (int sortItem = 0; sortItem < sortOrder.length; sortItem++) { + String s = sortOrder[sortItem]; + int size = unsorted.size(); + + for (int i = 0; i < size; i++) { + Property p = (Property)unsorted.elementAt(i); + if (p.getName().equals(s)) { + this.properties.addElement(p); + unsorted.removeElementAt(i); + break; + } + } + } + + int size = unsorted.size(); + + for (int ix = 0; ix < size; ix++) { + this.properties.addElement(unsorted.elementAt(ix)); + } + + size = this.properties.size(); + + for (int ix = 0; ix < size; ix++) { + Property prop = (Property)this.properties.elementAt(ix); + this.addItem(prop.getName() + " (" + prop.getPropertyType() + ")" + " (" + prop.get() + ")"); + } + + count = this.countItems(); + if (count != 0 && selected != -1) { + if (selected >= count) { + selected = count - 1; + } + + this.select(selected); + } + } + + public Property getSelectedProperty() { + int i = this.getSelectedIndex(); + return i != -1 ? (Property)this.properties.elementAt(i) : null; + } + + @Override + public void addItem(String s) { + if (s.length() > 128) { + s = s.substring(0, 125) + "..."; + } + + super.addItem(s); + } +} diff --git a/NET/worlds/scape/PropPropEditor.java b/NET/worlds/scape/PropPropEditor.java new file mode 100644 index 0000000..7d83be1 --- /dev/null +++ b/NET/worlds/scape/PropPropEditor.java @@ -0,0 +1,27 @@ +package NET.worlds.scape; + +import NET.worlds.console.PolledDialog; + +public class PropPropEditor extends PropEditor { + private boolean _nullHandling; + private SuperRoot _target; + + private PropPropEditor(Property property, SuperRoot target, boolean nullHandling) { + super(property); + this._target = target; + this._nullHandling = nullHandling; + } + + @Override + public PolledDialog edit(EditTile parent, String title) { + return new PropPropEditorDialog(parent, title, this.property, this._target, this._nullHandling); + } + + public static Property make(Property property, SuperRoot target) { + return property.setEditor(new PropPropEditor(property, target, false)); + } + + public static Property make(Property property, SuperRoot target, boolean nullHandling) { + return property.setEditor(new PropPropEditor(property, target, nullHandling)); + } +} diff --git a/NET/worlds/scape/PropPropEditorDialog.java b/NET/worlds/scape/PropPropEditorDialog.java new file mode 100644 index 0000000..4852b5a --- /dev/null +++ b/NET/worlds/scape/PropPropEditorDialog.java @@ -0,0 +1,55 @@ +package NET.worlds.scape; + +class PropPropEditorDialog extends ListChooserDialog { + private SuperRoot _target; + private Property _property; + private boolean _nullHandling; + + PropPropEditorDialog(EditTile parent, String title, Property property, SuperRoot target, boolean nullHandling) { + super(parent, title); + this._target = target; + this._property = property; + this._nullHandling = nullHandling; + this.ready(); + } + + @Override + protected String getEntry(int index) { + Property p = null; + + try { + p = (Property)this._target.properties(index, 0, 0, null); + } catch (NoSuchPropertyException var4) { + } + + return p == null ? null : p.getName(); + } + + @Override + protected int getSelected() { + if (this._property == null) { + return -1; + } else { + Property val = (Property)this._property.get(); + return val == null ? -1 : val.getIndex(); + } + } + + @Override + protected boolean setValue(String text, int index) { + if (index == -1 && !this._nullHandling) { + return false; + } else { + Object val = null; + + try { + val = this._target.properties(index, 0, 0, null); + } catch (NoSuchPropertyException var5) { + assert false; + } + + this._parent.addUndoableSet(this._property, val); + return true; + } + } +} diff --git a/NET/worlds/scape/PropTreeNode.java b/NET/worlds/scape/PropTreeNode.java new file mode 100644 index 0000000..a064dec --- /dev/null +++ b/NET/worlds/scape/PropTreeNode.java @@ -0,0 +1,142 @@ +package NET.worlds.scape; + +import NET.worlds.console.TreeNode; +import java.util.Enumeration; +import java.util.Vector; + +class PropTreeNode extends TreeNode { + private Object obj; + private boolean allowSorting = true; + + public PropTreeNode(Object obj) { + super(null); + this.obj = obj; + + assert obj != null; + } + + public PropTreeNode(Object obj, TreeNode parent) { + super(parent); + this.obj = obj; + + assert obj != null; + } + + @Override + public boolean shouldSort() { + return this.allowSorting; + } + + @Override + public Vector getChildren() { + Vector ret = null; + Object obj = this.obj; + if (obj instanceof VectorProperty) { + VectorProperty vp = (VectorProperty)obj; + this.allowSorting = vp.shouldSort(); + ret = new Vector(); + Vector v = (Vector)vp.get(); + if (v != null) { + int count = v.size(); + + for (int i = 0; i < count; i++) { + Object child = v.elementAt(i); + if (child == null) { + System.out.println("Error: VectorProperty " + vp.getName() + " of " + vp.getOwner() + " was null."); + } else { + ret.addElement(new PropTreeNode(child, this)); + } + } + } + } else { + if (obj instanceof Property) { + obj = ((Property)obj).get(); + } + + if (obj instanceof Properties) { + ret = new Vector(); + Enumeration e = new EnumProperties(obj); + + while (e.hasMoreElements()) { + Property p = (Property)e.nextElement(); + if (p instanceof VectorProperty || p.getEditor() == null && p.get() instanceof Properties) { + ret.addElement(new PropTreeNode(p, this)); + } + } + } + } + + return ret; + } + + @Override + public Object getObject() { + return this.obj; + } + + @Override + public boolean displayAsTitle() { + return this.obj instanceof VectorProperty || this.obj instanceof Property; + } + + public boolean canEdit() { + return false; + } + + public VectorProperty getContainingVectorProperty() { + Object obj = this.obj; + TreeNode e = this.getParent(); + return !(obj instanceof VectorProperty) && (e == null || !((obj = e.getObject()) instanceof VectorProperty)) ? null : (VectorProperty)obj; + } + + public PropAdder getAdder() { + VectorProperty vec = this.getContainingVectorProperty(); + return vec != null ? vec.getAdder() : null; + } + + public String getContainerName() { + return this.getContainingVectorProperty().getName(); + } + + public boolean canAdd() { + PropAdder adder = this.getAdder(); + return adder != null && adder.hasAddDialog(); + } + + public boolean canDelete() { + TreeNode e = this.getParent(); + Object obj; + Object var3; + return e != null + && ( + (obj = e.getObject()) instanceof VectorProperty && ((VectorProperty)obj).getAdder() != null + || (var3 = this.getObject()) instanceof Property && ((Property)var3).canSetNull() && ((Property)var3).get() != null + ); + } + + public Undoable delete(boolean isCut) { + assert this.canDelete(); + + Object o = this.getParent().getObject(); + if (o instanceof VectorProperty) { + VectorProperty owner = (VectorProperty)o; + Vector v = (Vector)owner.get(); + int i = v.indexOf(this.obj); + + assert i != -1; + + return (Undoable)(isCut ? new UndoablCut(owner, i) : new UndoablDelete(owner, i)); + } else { + return new UndoablSet((Property)this.getObject(), null); + } + } + + @Override + public String toString() { + if (this.obj instanceof SuperRoot) { + return ((SuperRoot)this.obj).getName(); + } else { + return this.obj instanceof Property ? ((Property)this.obj).getName() : this.obj.toString(); + } + } +} diff --git a/NET/worlds/scape/Properties.java b/NET/worlds/scape/Properties.java new file mode 100644 index 0000000..f75b5f4 --- /dev/null +++ b/NET/worlds/scape/Properties.java @@ -0,0 +1,14 @@ +package NET.worlds.scape; + +public interface Properties { + int ENUM = 0; + int GET = 1; + int SET = 2; + int ADD = 3; + int DEL = 4; + int ADD_TEST = 5; + + Object properties(int var1, int var2, int var3, Object var4) throws NoSuchPropertyException; + + Object propertyParent(); +} diff --git a/NET/worlds/scape/Property.java b/NET/worlds/scape/Property.java new file mode 100644 index 0000000..31b797a --- /dev/null +++ b/NET/worlds/scape/Property.java @@ -0,0 +1,153 @@ +package NET.worlds.scape; + +import NET.worlds.console.Main; + +public class Property { + protected Properties owner; + public static final int BOOL_TYPE = 0; + public static final int INT_TYPE = 1; + public static final int FLOAT_TYPE = 2; + public static final int STRING_TYPE = 3; + public static final int COLOR_TYPE = 4; + public static final int ENUM_TYPE = 5; + public static final int FLOAT_ARRAY_TYPE = 6; + public static final int POINT2_TYPE = 7; + public static final int POINT3_TYPE = 8; + public static final int TRANSFORM_TYPE = 9; + public static final int URL_TYPE = 10; + protected int index; + protected String name; + protected int propertyType = 3; + protected PropEditor editor; + public boolean helpExists = false; + protected boolean canSetNull = false; + + public Property(Properties owner, int index, String name) { + this.owner = owner; + this.index = index; + this.name = name; + } + + public Property(Properties owner, int index, String name, boolean haveHelp) { + this.owner = owner; + this.index = index; + this.name = name; + this.helpExists = haveHelp; + } + + Property setEditor(PropEditor editor) { + this.editor = editor; + return this; + } + + public PropEditor getEditor() { + return this.editor; + } + + public Property allowSetNull() { + this.canSetNull = true; + return this; + } + + public boolean canSetNull() { + return this.canSetNull; + } + + public String getName() { + return this.name; + } + + public int getIndex() { + return this.index; + } + + public Properties getOwner() { + return this.owner; + } + + public Object get() { + return this.operate(1, null); + } + + public Object set(Object obj) { + return this.operate(2, obj); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof Property && ((Property)obj).owner == this.owner && ((Property)obj).index == this.index; + } + + @Override + public int hashCode() { + return this.owner.hashCode() ^ this.index; + } + + protected Object operate(int func, Object value) { + return Main.isMainThread() ? this.safeOperate(func, value) : new CallbackPropertyOperator(this, func, value).getValue(); + } + + Object safeOperate(int func, Object value) { + try { + Object ret = this.owner.properties(this.index, 0, func, value); + if (func > 1 && func < 5 && this.owner instanceof SuperRoot) { + ((SuperRoot)this.owner).markEdited(); + } + + return ret; + } catch (NoSuchPropertyException var4) { + assert false; + + return null; + } + } + + @Override + public String toString() { + return this.getName(); + } + + public void setPropertyType(int type) { + this.propertyType = type; + } + + public String getPropertyType() { + String retVal; + switch (this.propertyType) { + case 0: + retVal = "Boolean"; + break; + case 1: + retVal = "Integer"; + break; + case 2: + retVal = "Float"; + break; + case 3: + retVal = "String"; + break; + case 4: + retVal = "Color"; + break; + case 5: + retVal = "Enumeration"; + break; + case 6: + retVal = "Float Array"; + break; + case 7: + retVal = "2D Point"; + break; + case 8: + retVal = "3D Point"; + break; + case 9: + retVal = "Transform"; + break; + default: + retVal = "URL"; + } + + return retVal; + } +} diff --git a/NET/worlds/scape/ProximitySensor.java b/NET/worlds/scape/ProximitySensor.java new file mode 100644 index 0000000..4ae5b64 --- /dev/null +++ b/NET/worlds/scape/ProximitySensor.java @@ -0,0 +1,149 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class ProximitySensor extends Sensor implements FrameHandler { + private boolean _wasin = false; + private Point3 _start = new Point3(0.0F, 0.0F, 0.0F); + private Point3 _end = new Point3(1.0F, 1.0F, 1.0F); + private boolean _triggerin = true; + private boolean _triggerout = false; + private boolean _silentTeleport = false; + private Room _lastRoom; + private static Object classCookie = new Object(); + + public ProximitySensor(Action a) { + if (a != null) { + this.addAction(a); + } + } + + public ProximitySensor() { + } + + @Override + public boolean handle(FrameEvent e) { + SuperRoot owner = this.getOwner(); + if (!(owner instanceof WObject)) { + return true; + } else { + WObject wo = (WObject)owner; + Pilot pilot = Pilot.getActive(); + Room room = pilot.getRoom(); + boolean teleport = room != this._lastRoom; + this._lastRoom = room; + Point3Temp pos = pilot.getPosition(); + BoundBoxTemp bbt = BoundBoxTemp.make(Point3Temp.make(this._start).times(wo), Point3Temp.make(this._end).times(wo)); + if (pilot.getRoom() == wo.getRoom() && bbt.contains(pos)) { + if (!this._wasin) { + this._wasin = true; + if (this._triggerin && (!teleport || !this._silentTeleport)) { + this.trigger(e); + } + } + } else if (this._wasin) { + this._wasin = false; + if (this._triggerout && (!teleport || !this._silentTeleport)) { + this.trigger(e); + } + } + + return true; + } + } + + @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, "Start")); + } else if (mode == 1) { + ret = new Point3(this._start); + } else if (mode == 2) { + this._start = (Point3)value; + } + break; + case 1: + if (mode == 0) { + ret = Point3PropertyEditor.make(new Property(this, index, "End")); + } else if (mode == 1) { + ret = new Point3(this._end); + } else if (mode == 2) { + this._end = (Point3)value; + } + break; + case 2: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Trigger on entry"), "Don't trigger when entered", "Trigger when entered"); + } else if (mode == 1) { + ret = new Boolean(this._triggerin); + } else if (mode == 2) { + this._triggerin = (Boolean)value; + } + break; + case 3: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Trigger on exit"), "Don't trigger when exited", "Trigger when exited"); + } else if (mode == 1) { + ret = new Boolean(this._triggerout); + } else if (mode == 2) { + this._triggerout = (Boolean)value; + } + break; + case 4: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Teleport trigger"), "Don't trigger on teleports", "Trigger on teleports"); + } else if (mode == 1) { + ret = new Boolean(!this._silentTeleport); + } else if (mode == 2) { + this._silentTeleport = !(Boolean)value; + } + break; + default: + ret = super.properties(index, offset + 5, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(2, classCookie); + super.saveState(s); + s.saveBoolean(this._triggerin); + s.saveBoolean(this._triggerout); + s.saveBoolean(this._silentTeleport); + s.save(this._start); + s.save(this._end); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 1: + super.restoreState(r); + this._triggerin = r.restoreBoolean(); + this._triggerout = r.restoreBoolean(); + this._start = (Point3)r.restore(); + this._end = (Point3)r.restore(); + break; + case 2: + super.restoreState(r); + this._triggerin = r.restoreBoolean(); + this._triggerout = r.restoreBoolean(); + this._silentTeleport = r.restoreBoolean(); + this._start = (Point3)r.restore(); + this._end = (Point3)r.restore(); + break; + default: + throw new TooNewException(); + } + } + + @Override + public String toString() { + return super.toString() + "[" + (this._triggerin ? "I" : " ") + (this._triggerout ? "O" : " ") + this._start + " to " + this._end + "]"; + } +} diff --git a/NET/worlds/scape/RPAction.java b/NET/worlds/scape/RPAction.java new file mode 100644 index 0000000..2fc9f4a --- /dev/null +++ b/NET/worlds/scape/RPAction.java @@ -0,0 +1,12 @@ +package NET.worlds.scape; + +public class RPAction extends Action { + @Override + public Persister trigger(Event e, Persister seqID) { + if (this.getOwner() instanceof Portal) { + ((Portal)this.getOwner()).triggerLoad(); + } + + return null; + } +} diff --git a/NET/worlds/scape/Rect.java b/NET/worlds/scape/Rect.java new file mode 100644 index 0000000..9613dd3 --- /dev/null +++ b/NET/worlds/scape/Rect.java @@ -0,0 +1,421 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.DefaultConsole; +import java.io.IOException; + +public class Rect extends Surface implements MouseDownHandler, FrameHandler, Prerenderable { + static BumpCalc standardPlaneBumpCalc = new PlaneBumpCalc(); + Billboard _billboardAttribute = null; + VideoTexture _videoAttribute = null; + boolean visible = false; + protected float u = 1.0F; + protected float v = 1.0F; + protected float uOff; + protected float vOff; + private static Object classCookie = new Object(); + + static { + standardPlaneBumpCalc.setName("defaultPlaneBumpCalc"); + } + + public Rect(float w, float h, Material material) { + super(material); + this.scale(w, h, h); + } + + public Rect(float x, float y, float z, Material material) { + super(material); + this.setFarCorner(Point3Temp.make(x, y, z)); + } + + public Rect(float llx, float lly, float llz, float urx, float ury, float urz, Material material) { + super(material); + this.moveBy(llx, lly, llz); + this.setFarCorner(Point3Temp.make(urx, ury, urz)); + } + + public Rect(Point3Temp llc, Point3Temp urc, Material material) { + this(llc.x, llc.y, llc.z, urc.x, urc.y, urc.z, material); + } + + Rect() { + } + + public static boolean setFarCornerHelper(Transform t, Point3Temp newCorner) { + t.scale(1.0F / t.getScaleX(), 1.0F / t.getScaleY(), 1.0F / t.getScaleZ()); + Point3Temp lookRight = Point3Temp.make(1.0F, 0.0F, 0.0F).vectorTimes(t); + Point3Temp lookOut = Point3Temp.make(0.0F, 1.0F, 0.0F).vectorTimes(t); + Point3Temp lookUp = Point3Temp.make(0.0F, 0.0F, 1.0F).vectorTimes(t); + Point3Temp newEndOffset = Point3Temp.make(newCorner).minus(t.getPosition()); + float x = newEndOffset.dot(lookRight); + float y = newEndOffset.dot(lookOut); + float z = newEndOffset.dot(lookUp); + if (!(z >= 0.0F)) { + return false; + } else { + if (x != 0.0F || y != 0.0F) { + t.spin(0.0F, 0.0F, 1.0F, (float)(Math.atan2(y, x) * 180.0 / Math.PI)); + } + + t.scale((float)Math.sqrt(x * x + y * y), z, z); + return true; + } + } + + public boolean setFarCorner(Point3Temp newCorner) { + Transform t = this.getTransform(); + if (setFarCornerHelper(t, newCorner)) { + this.setTransform(t); + t.recycle(); + return true; + } else { + t.recycle(); + Console.println(Console.message("cant-rot-rect")); + return false; + } + } + + public Point3Temp getFarCorner() { + Point3Temp ret = Point3Temp.make(1.0F, 0.0F, 1.0F); + if (this.hasClump()) { + Transform t = this.getObjectToWorldMatrix(); + ret.times(t); + t.recycle(); + } else { + ret.times(this); + } + + return ret; + } + + public Point3Temp getFarCornerLocal() { + Point3Temp ret = Point3Temp.make(1.0F, 0.0F, 1.0F); + if (this.hasClump()) { + Transform t = this.getTransform(); + ret.times(t); + t.recycle(); + } else { + ret.times(this); + } + + return ret; + } + + public void setNearCorner(Point3Temp from) { + Point3Temp oldEnd = this.getFarCornerLocal(); + Point3Temp oldStart = this.getPosition(); + this.moveTo(from); + if (!this.setFarCorner(oldEnd)) { + this.moveTo(oldStart); + } + } + + @Override + public Point3Temp getPlaneExtent() { + return Point3Temp.make(1.0F, 0.0F, 1.0F); + } + + @Override + public BumpCalc getBumpCalc(BumpEventTemp b) { + return this.bumpCalc == null ? standardPlaneBumpCalc : this.bumpCalc; + } + + public Point2 getTileSize() { + return new Point2(this.u != 1.0F ? this.getScaleX() / this.u : 0.0F, this.v != 1.0F ? this.getScaleZ() / this.v : 0.0F); + } + + void setUV(float u, float v) { + this.setTileSize(this.getScaleX() / u, this.getScaleZ() / v); + } + + public Rect setTileSize(float tx, float ty) { + this.u = tx == 0.0F ? 1.0F : this.getScaleX() / tx; + this.v = ty == 0.0F ? 1.0F : this.getScaleZ() / ty; + this.reclump(); + return this; + } + + public void setTileOffset(Point2 p) { + this.uOff = this.getScaleX() == 0.0F ? 0.0F : p.x / this.getScaleX(); + this.vOff = this.getScaleZ() == 0.0F ? 0.0F : p.y / this.getScaleZ(); + this.reclump(); + } + + public Point2 getTileOffset() { + return new Point2(this.uOff * this.getScaleX(), this.vOff * this.getScaleZ()); + } + + public static Rect floor(float x, float y, Material m) { + return (Rect)new Rect(x, y, m).setBumpable(false).postspin(1.0F, 0.0F, 0.0F, -90.0F); + } + + public static Rect floor(float llx, float lly, float z, float urx, float ury, Material m) { + return (Rect)floor(urx - llx, ury - lly, m).moveBy(llx, lly, z); + } + + public static Rect ceiling(float x, float y, Material m) { + return (Rect)new Rect(x, y, m).setBumpable(false).postspin(1.0F, 0.0F, 0.0F, 90.0F).moveBy(0.0F, y, 0.0F); + } + + public static Rect ceiling(float llx, float lly, float z, float urx, float ury, Material m) { + return (Rect)ceiling(urx - llx, ury - lly, m).moveBy(llx, lly, z); + } + + public Rect hang(float pllx, float pllz, float purx, float purz, Material pic) { + Rect r = (Rect)new Rect((purx - pllx) / this.getScaleX(), (purz - pllz) / this.getScaleZ(), pic) + .moveBy(pllx / this.getScaleX(), 0.0F, pllz / this.getScaleZ()) + .post(this); + return (Rect)r.premoveBy(0.0F, -1.0F / r.getScale().length(), 0.0F); + } + + public VideoTexture getVideoAttribute() { + return this._videoAttribute; + } + + public Billboard getBillboardAttribute() { + return this._billboardAttribute; + } + + @Override + public boolean handle(MouseDownEvent event) { + if (this._billboardAttribute != null && (event.key & 1) == 1) { + Point2 pt = this.deproject(); + this._billboardAttribute.billboardClicked(pt); + } + + return false; + } + + @Override + public boolean handle(FrameEvent f) { + if (this._billboardAttribute != null && this.getVisible() && this.visible) { + this._billboardAttribute.billboardFrame(f); + } + + if (this._videoAttribute != null && this.getVisible() && this.visible) { + this._videoAttribute.videoFrame(f); + } + + this.visible = false; + return false; + } + + @Override + public void prerender(Camera cam) { + if (this._billboardAttribute != null || this._videoAttribute != null) { + Point3Temp p = this.inCamSpace(cam); + boolean v = p != null && p.z > 1.0F && p.x < p.z && -p.x < p.z; + if (v) { + this.visible = true; + } + } + } + + protected Point2 deproject() { + Console c = Console.getActive(); + if (c instanceof DefaultConsole) { + DefaultConsole dc = (DefaultConsole)c; + Point3Temp worldClick = dc.getRender().getCamera().lastPickSpot(); + Point3Temp vWorld = Point3Temp.make(worldClick); + vWorld.minus(this.getObjectToWorldMatrix().getPosition()); + Transform inv = this.getObjectToWorldMatrix().invert(); + Point3Temp vObj = Point3Temp.make(vWorld).vectorTimes(inv); + inv.recycle(); + Point2 rectPt = new Point2(); + rectPt.set(vObj.x, vObj.z); + return rectPt; + } else { + return new Point2(-1.0F, -1.0F); + } + } + + @Override + protected void addRwChildren(WObject container) { + this.addNewRwChild(container); + float uo = this.uOff; + if (uo != 0.0F) { + uo *= this.u; + uo = (float)(uo - 2.0 * Math.floor(uo / 2.0F)); + } + + float vo = this.vOff; + if (vo != 0.0F) { + vo *= this.v; + vo = (float)(vo - 2.0 * Math.floor(vo / 2.0F)); + } + + this.addVertex(0.0F, 0.0F, 0.0F, uo, this.v + vo); + this.addVertex(1.0F, 0.0F, 0.0F, this.u + uo, this.v + vo); + this.addVertex(1.0F, 0.0F, 1.0F, this.u + uo, vo); + this.addVertex(0.0F, 0.0F, 1.0F, uo, vo); + this.doneWithEditing(); + if (!(this instanceof Portal)) { + this.getRoom().addPrerenderHandler(this); + } + } + + @Override + protected void markVoid() { + if (!(this instanceof Portal)) { + this.getRoom().removePrerenderHandler(this); + } + + super.markVoid(); + } + + @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 = Point2PropertyEditor.make(new Property(this, index, "Tile Size")); + } else if (mode == 1) { + ret = this.getTileSize(); + } else if (mode == 2) { + Point2 p = (Point2)value; + if (!(p.x < 0.0F) && !(p.y < 0.0F)) { + this.setTileSize(p.x, p.y); + } else { + Console.println(Console.message("Tile-size")); + } + } + break; + case 1: + if (mode == 0) { + ret = Point2PropertyEditor.make(new Property(this, index, "Tile Origin")); + } else if (mode == 1) { + ret = this.getTileOffset(); + } else if (mode == 2) { + this.setTileOffset((Point2)value); + } + break; + case 2: + if (mode == 0) { + ret = Point3PropertyEditor.make(new Property(this, index, "From")); + } else if (mode == 1) { + ret = new Point3(this.getPosition()); + } else if (mode == 2) { + this.setNearCorner((Point3)value); + } + break; + case 3: + if (mode == 0) { + ret = Point3PropertyEditor.make(new Property(this, index, "To")); + } else if (mode == 1) { + ret = new Point3(this.getFarCornerLocal()); + } else if (mode == 2) { + this.setFarCorner((Point3)value); + } + break; + case 4: + if (mode == 0) { + ret = Point2PropertyEditor.make(new Property(this, index, "Extent")); + } else if (mode == 1) { + ret = new Point2(this.getScaleX(), this.getScaleZ()); + } else if (mode == 2) { + float zScale = ((Point2)value).y / this.getScaleZ(); + this.scale(((Point2)value).x / this.getScaleX(), zScale, zScale); + } + break; + case 5: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Flip Alternate U"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.getUFlip()); + } else if (mode == 2) { + this.setUFlip((Boolean)value); + this.reclump(); + } + break; + case 6: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Flip Alternate V"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.getVFlip()); + } else if (mode == 2) { + this.setVFlip((Boolean)value); + this.reclump(); + } + break; + case 7: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Unused"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.getMouseOver()); + } else if (mode == 2) { + this.setMouseOver((Boolean)value); + } + break; + default: + ret = super.properties(index, offset + 8, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(4, classCookie); + super.saveState(s); + s.saveFloat(this.u); + s.saveFloat(this.v); + s.saveFloat(this.uOff); + s.saveFloat(this.vOff); + s.saveBoolean(false); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + int vers = r.restoreVersion(classCookie); + switch (vers) { + case 0: + case 1: + super.restoreState(r); + float x = r.restoreFloat(); + float y = r.restoreFloat(); + float z = r.restoreFloat(); + r.restoreFloat(); + r.restoreFloat(); + r.restoreFloat(); + this.u = r.restoreFloat(); + this.v = r.restoreFloat(); + this.spin(0.0F, 0.0F, 1.0F, (float)(Math.atan2(y, x) * 180.0 / Math.PI)); + this.scale((float)Math.sqrt(x * x + y * y), z, z); + break; + case 2: + super.restoreState(r); + this.u = r.restoreFloat(); + this.v = r.restoreFloat(); + break; + case 3: + super.restoreState(r); + this.u = r.restoreFloat(); + this.v = r.restoreFloat(); + this.uOff = r.restoreFloat(); + this.vOff = r.restoreFloat(); + break; + case 4: + super.restoreState(r); + this.u = r.restoreFloat(); + this.v = r.restoreFloat(); + this.uOff = r.restoreFloat(); + this.vOff = r.restoreFloat(); + r.restoreBoolean(); + break; + default: + throw new TooNewException(); + } + } + + @Override + public String toString() { + return super.toString() + "[" + this.getPosition() + "->" + this.getFarCornerLocal() + "]"; + } + + @Override + public boolean acceptsLeftClicks() { + return this._billboardAttribute != null && this._billboardAttribute.getIsAdBanner() ? true : this.getMouseOver(); + } +} diff --git a/NET/worlds/scape/RectPatch.java b/NET/worlds/scape/RectPatch.java new file mode 100644 index 0000000..6ce3473 --- /dev/null +++ b/NET/worlds/scape/RectPatch.java @@ -0,0 +1,401 @@ +package NET.worlds.scape; + +import java.awt.Color; +import java.io.IOException; + +public class RectPatch extends WObject implements FloorPatch { + public float xDim; + public float yDim; + public float[] z = new float[]{0.0F, 0.0F, 0.0F, 0.0F}; + public Material mat; + public float xTile = 1.0F; + public float xTileOffset = 0.0F; + public float yTile = 1.0F; + public float yTileOffset = 0.0F; + public Polygon[] t = new Polygon[4]; + private static Object classCookie = new Object(); + + public RectPatch(float x, float y) { + this.setVisible(true); + this.setBumpable(false); + this.xDim = x; + this.yDim = y; + this.setMaterial(new Material(Color.gray)); + } + + public RectPatch() { + this.xDim = 1.0F; + this.yDim = 1.0F; + this.setMaterial(new Material(Color.gray)); + } + + @Override + protected void addRwChildren(WObject parent) { + if (this.t[0] == null) { + this.createAppearance(); + } + + super.addRwChildren(parent); + } + + @Override + public void setVisible(boolean v) { + super.setVisible(v); + this.createAppearance(); + } + + public void setMaterial(Material m) { + if (this.mat != null) { + this.mat.detach(); + } + + this.add(m); + this.mat = m; + this.createAppearance(); + } + + public Material getMaterial() { + return this.mat; + } + + @Override + public boolean inPatch(float x, float y) { + Transform inverse = this.getObjectToWorldMatrix().invert(); + Point3Temp p = Point3Temp.make(x, y, 0.0F).times(inverse); + inverse.recycle(); + x = p.x; + y = p.y; + return !(x < 0.0F) && !(x > this.xDim) && !(y < 0.0F) && !(y > this.yDim); + } + + @Override + public float floorHeight(float x, float y) { + Transform inverse = this.getObjectToWorldMatrix().invert(); + Point3Temp p = Point3Temp.make(x, y, 0.0F).times(inverse); + inverse.recycle(); + x = p.x; + y = p.y; + float nx = x / this.xDim; + float ny = y / this.yDim; + float fx = 1.0F - nx; + float fy = 1.0F - ny; + return this.z[0] * fy * fx + this.z[1] * ny * fx + this.z[2] * ny * nx + this.z[3] * fy * nx; + } + + @Override + public Point3 surfaceNormal(float x, float y) { + Point3 A = new Point3(this.xDim, 0.0F, this.z[1] - this.z[0]); + Point3Temp B = Point3Temp.make(0.0F, this.yDim, this.z[3] - this.z[0]); + A.cross(B); + A.normalize(); + A.times(this.getObjectToWorldMatrix()); + return A; + } + + private void removeAppearance() { + for (int i = 0; i < 4; i++) { + if (this.t[i] != null) { + this.t[i].detach(); + this.t[i] = null; + } + } + } + + public void createAppearance() { + this.removeAppearance(); + if (this.getVisible()) { + if (!(this.xDim <= 0.0F) && !(this.yDim <= 0.0F)) { + if (this.xTile <= 0.0F) { + this.xTile = 1.0F; + } + + if (this.xTile > 31.0F) { + this.xTile = 31.0F; + } + + if (this.yTile <= 0.0F) { + this.yTile = 1.0F; + } + + if (this.yTile > 31.0F) { + this.yTile = 31.0F; + } + + if (this.xTileOffset < 0.0F) { + this.xTileOffset = 1.0F - (float)Math.floor(this.xTileOffset) + this.xTileOffset; + } + + if (this.yTileOffset < 0.0F) { + this.yTileOffset = 1.0F - (float)Math.floor(this.yTileOffset) + this.yTileOffset; + } + + float cx = this.xDim / 2.0F; + float cy = this.yDim / 2.0F; + float cz = (this.z[0] + this.z[1] + this.z[2] + this.z[3]) / 4.0F; + float cU = this.xTileOffset + this.xTile / 2.0F; + float cV = this.yTileOffset + this.yTile / 2.0F; + this.t[0] = new Polygon(3, this.mat); + this.t[0].setVertex(0, 0.0F, 0.0F, this.z[0], this.xTileOffset, this.yTileOffset); + this.t[0].setVertex(1, cx, cy, cz, cU, cV); + this.t[0].setVertex(2, 0.0F, this.yDim, this.z[1], this.xTileOffset, this.yTileOffset + this.yTile); + this.add(this.t[0]); + this.t[1] = new Polygon(3, this.mat); + this.t[1].setVertex(0, 0.0F, this.yDim, this.z[1], this.xTileOffset, this.yTileOffset + this.yTile); + this.t[1].setVertex(1, cx, cy, cz, cU, cV); + this.t[1].setVertex(2, this.xDim, this.yDim, this.z[2], this.xTileOffset + this.xTile, this.yTileOffset + this.yTile); + this.add(this.t[1]); + this.t[2] = new Polygon(3, this.mat); + this.t[2].setVertex(0, this.xDim, this.yDim, this.z[2], this.xTileOffset + this.xTile, this.yTileOffset + this.yTile); + this.t[2].setVertex(1, cx, cy, cz, cU, cV); + this.t[2].setVertex(2, this.xDim, 0.0F, this.z[3], this.xTileOffset + this.xTile, this.yTileOffset); + this.add(this.t[2]); + this.t[3] = new Polygon(3, this.mat); + this.t[3].setVertex(0, this.xDim, 0.0F, this.z[3], this.xTileOffset + this.xTile, this.yTileOffset); + this.t[3].setVertex(1, cx, cy, cz, cU, cV); + this.t[3].setVertex(2, 0.0F, 0.0F, this.z[0], this.xTileOffset, this.yTileOffset); + this.add(this.t[3]); + } + } + } + + public void setCornerHeight(int corner, float height) { + this.z[corner] = height; + this.createAppearance(); + } + + public void setWidth(float v) { + this.xDim = v; + this.createAppearance(); + } + + public void setLength(float v) { + this.yDim = v; + this.createAppearance(); + } + + @Override + public Transform spin(float x, float y, float z, float a) { + if (x == 0.0F && y == 0.0F) { + return super.spin(x, y, z, a); + } else { + System.out.println("ERROR: cannot spin floor patch out of horizontal!"); + return this; + } + } + + @Override + public Transform postspin(float x, float y, float z, float a) { + if (x == 0.0F && y == 0.0F) { + return super.spin(x, y, z, a); + } else { + System.out.println("ERROR: cannot spin floor patch out of horizontal!"); + return this; + } + } + + @Override + public Transform worldSpin(float x, float y, float z, float a) { + if (x == 0.0F && y == 0.0F) { + return super.spin(x, y, z, a); + } else { + System.out.println("ERROR: cannot spin floor patch out of horizontal!"); + return this; + } + } + + @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 = FloatPropertyEditor.make(new Property(this, index, "Length (y)")); + } else if (mode == 1) { + ret = new Float(this.yDim); + } else if (mode == 2) { + this.setLength((Float)value); + } + break; + case 1: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Width (x)")); + } else if (mode == 1) { + ret = new Float(this.xDim); + } else if (mode == 2) { + this.setWidth((Float)value); + } + break; + case 2: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "0,0 corner")); + } else if (mode == 1) { + ret = new Float(this.z[0]); + } else if (mode == 2) { + this.setCornerHeight(0, (Float)value); + } + break; + case 3: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "0,y corner")); + } else if (mode == 1) { + ret = new Float(this.z[1]); + } else if (mode == 2) { + this.setCornerHeight(1, (Float)value); + } + break; + case 4: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "x,y corner")); + } else if (mode == 1) { + ret = new Float(this.z[2]); + } else if (mode == 2) { + this.setCornerHeight(2, (Float)value); + } + break; + case 5: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "x,0 corner")); + } else if (mode == 1) { + ret = new Float(this.z[3]); + } else if (mode == 2) { + this.setCornerHeight(3, (Float)value); + } + break; + case 6: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "# Tiles (x)")); + } else if (mode == 1) { + ret = new Float(this.xTile); + } else if (mode == 2) { + this.xTile = (Float)value; + this.createAppearance(); + } + break; + case 7: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "# Tiles (y)")); + } else if (mode == 1) { + ret = new Float(this.yTile); + } else if (mode == 2) { + this.yTile = (Float)value; + this.createAppearance(); + } + break; + case 8: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Tile Offset (x)")); + } else if (mode == 1) { + ret = new Float(this.xTileOffset); + } else if (mode == 2) { + this.xTileOffset = (Float)value; + this.createAppearance(); + } + break; + case 9: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Tile Offset (y)")); + } else if (mode == 1) { + ret = new Float(this.yTileOffset); + } else if (mode == 2) { + this.yTileOffset = (Float)value; + this.createAppearance(); + } + break; + case 10: + if (mode == 0) { + ret = new Property(this, index, "Material"); + } else if (mode == 1) { + ret = this.mat; + } + break; + default: + ret = super.properties(index, offset + 11, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(2, classCookie); + this.removeAppearance(); + super.saveState(s); + s.saveFloat(this.xDim); + s.saveFloat(this.yDim); + + for (int i = 0; i < 4; i++) { + s.saveFloat(this.z[i]); + } + + s.saveFloat(this.xTile); + s.saveFloat(this.xTileOffset); + s.saveFloat(this.yTile); + s.saveFloat(this.yTileOffset); + s.saveMaybeNull(this.mat); + this.createAppearance(); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + this.restoreStateRectPatchHelper(r, classCookie); + } + + public void restoreStateRectPatchHelper(Restorer r, Object cookie) throws IOException, TooNewException { + switch (r.restoreVersion(cookie)) { + case 0: + r.setOldFlag(); + super.restoreState(r); + this.xDim = r.restoreFloat(); + this.yDim = r.restoreFloat(); + + for (int i = 0; i < 4; i++) { + this.z[i] = r.restoreFloat(); + } + + this.setVisible(false); + break; + case 1: + r.setOldFlag(); + super.restoreState(r); + this.xDim = r.restoreFloat(); + this.yDim = r.restoreFloat(); + + for (int i = 0; i < 4; i++) { + this.z[i] = r.restoreFloat(); + } + + this.xTile = r.restoreFloat(); + this.xTileOffset = r.restoreFloat(); + this.yTile = r.restoreFloat(); + this.yTileOffset = r.restoreFloat(); + this.setMaterial(Material.restore(r)); + r.restoreMaybeNull(); + r.restoreMaybeNull(); + r.restoreMaybeNull(); + r.restoreMaybeNull(); + break; + case 2: + super.restoreState(r); + this.xDim = r.restoreFloat(); + this.yDim = r.restoreFloat(); + + for (int i = 0; i < 4; i++) { + this.z[i] = r.restoreFloat(); + } + + this.xTile = r.restoreFloat(); + this.xTileOffset = r.restoreFloat(); + this.yTile = r.restoreFloat(); + this.yTileOffset = r.restoreFloat(); + this.setMaterial(Material.restore(r)); + break; + default: + throw new TooNewException(); + } + } + + @Override + public String toString() { + return super.toString() + "[" + this.xDim + "," + this.yDim + "]"; + } +} diff --git a/NET/worlds/scape/Recycler.java b/NET/worlds/scape/Recycler.java new file mode 100644 index 0000000..cab50e4 --- /dev/null +++ b/NET/worlds/scape/Recycler.java @@ -0,0 +1,75 @@ +package NET.worlds.scape; + +import NET.worlds.console.Main; +import NET.worlds.console.MainCallback; + +public class Recycler implements MainCallback { + private static int minCapacity = 50; + private Object[] list = new Object[minCapacity]; + private int numFilled = 0; + private int numAllocked = 0; + private int maxAllockedRecently = 0; + private int howRecently = 0; + + Recycler() { + Main.register(this); + } + + private void resizeTo(int newCapacity) { + assert newCapacity > this.numAllocked; + + if (newCapacity < minCapacity) { + newCapacity = minCapacity; + } + + if (newCapacity < this.list.length && this.list.length < 2 * newCapacity) { + while (this.numFilled > newCapacity) { + this.list[--this.numFilled] = null; + } + } else { + Object[] newList = new Object[newCapacity]; + + try { + System.arraycopy(this.list, 0, newList, 0, this.numAllocked); + } catch (Exception var4) { + throw new Error(var4.toString()); + } + + this.list = newList; + this.numFilled = this.numAllocked; + } + } + + @Override + public void mainCallback() { + if (this.numAllocked > this.maxAllockedRecently) { + this.maxAllockedRecently = this.numAllocked; + } + + if (++this.howRecently == 1000) { + int newCapacity = this.maxAllockedRecently + minCapacity; + if (newCapacity < this.list.length) { + this.resizeTo(newCapacity); + } + + this.howRecently = 0; + this.maxAllockedRecently = this.numAllocked; + } + + this.numAllocked = 0; + } + + public Object alloc() { + assert Main.isMainThread(); + + return this.numAllocked == this.numFilled ? null : this.list[this.numAllocked++]; + } + + public void recycle(Object o) { + if (this.numFilled == this.list.length) { + this.resizeTo(this.list.length * 2); + } + + this.list[this.numFilled++] = o; + } +} diff --git a/NET/worlds/scape/RelativeMoveAction.java b/NET/worlds/scape/RelativeMoveAction.java new file mode 100644 index 0000000..8d59804 --- /dev/null +++ b/NET/worlds/scape/RelativeMoveAction.java @@ -0,0 +1,196 @@ +package NET.worlds.scape; + +import NET.worlds.core.Std; +import java.io.IOException; + +public class RelativeMoveAction extends Action { + int startTime; + public int cycleTime = 1000; + public int cycles = 1; + public boolean loopInfinite = false; + public Point3 extentPoint = new Point3(); + public Point3 extentScale = new Point3(1.0F, 1.0F, 1.0F); + public Point3 extentSpin = new Point3(0.0F, 0.0F, -1.0F); + public float extentRotation = 0.0F; + public float accumulatedRotation; + public Point3 accumulatedScale; + public Point3 accumulatedPoint; + protected Persister activeID; + private static Object classCookie = new Object(); + + @Override + public Persister trigger(Event e, Persister seqID) { + Object owner = this.getOwner(); + if (owner != null && owner instanceof WObject) { + WObject o = (WObject)owner; + if (seqID == null) { + if (this.activeID != null) { + return this.activeID; + } + + this.startTime = Std.getRealTime(); + this.activeID = new SuperRoot(); + seqID = this.activeID; + this.accumulatedRotation = 0.0F; + this.accumulatedPoint = new Point3(0.0F, 0.0F, 0.0F); + this.accumulatedScale = new Point3(1.0F, 1.0F, 1.0F); + } + + if (seqID != this.activeID) { + return null; + } else { + int currentTime = Std.getRealTime(); + int cycleNo = (currentTime - this.startTime) / this.cycleTime; + float frameLoc = 1.0F; + if (cycleNo >= this.cycles && !this.loopInfinite) { + this.activeID = null; + } else { + frameLoc = (float)((currentTime - this.startTime) % this.cycleTime) / this.cycleTime; + } + + float tmpSpin = this.extentRotation * frameLoc; + o.spin(this.extentSpin, tmpSpin - this.accumulatedRotation); + this.accumulatedRotation = tmpSpin; + Point3 tmpScale = new Point3( + (float)Math.pow(this.extentScale.x, frameLoc), (float)Math.pow(this.extentScale.y, frameLoc), (float)Math.pow(this.extentScale.z, frameLoc) + ); + o.scale(Point3Temp.make(tmpScale).dividedBy(this.accumulatedScale)); + this.accumulatedScale = tmpScale; + Point3 tmpPoint = new Point3(Point3Temp.make(this.extentPoint).times(frameLoc)); + o.moveBy(Point3Temp.make(tmpPoint).minus(this.accumulatedPoint)); + this.accumulatedPoint = tmpPoint; + return this.activeID; + } + } else { + return null; + } + } + + @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 = FloatPropertyEditor.make(new Property(this, index, "Cycle Time (in seconds)")); + } else if (mode == 1) { + ret = new Float(this.cycleTime / 1000.0F); + } else if (mode == 2) { + this.cycleTime = (int)(1000.0F * (Float)value); + } + break; + case 1: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Cycles")); + } else if (mode == 1) { + ret = new Integer(this.cycles); + } else if (mode == 2) { + this.cycles = (Integer)value; + } + break; + case 2: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Loop Infinite"), "False", "True"); + } else if (mode == 1) { + ret = new Boolean(this.loopInfinite); + } else if (mode == 2) { + this.loopInfinite = (Boolean)value; + } + break; + case 3: + if (mode == 0) { + ret = Point3PropertyEditor.make(new Property(this, index, "Translation Extent")); + } else if (mode == 1) { + ret = new Point3(this.extentPoint); + } else if (mode == 2) { + this.extentPoint.copy((Point3)value); + } + break; + case 4: + if (mode == 0) { + ret = Point3PropertyEditor.make(new Property(this, index, "Scale Extent")); + } else if (mode == 1) { + ret = new Point3(this.extentScale); + } else if (mode == 2) { + this.extentScale.copy((Point3)value); + } + break; + case 5: + if (mode == 0) { + ret = Point3PropertyEditor.make(new Property(this, index, "Spin Axis For Extent")); + } else if (mode == 1) { + Point3 p = new Point3(this.extentSpin); + p.x = Math.round(p.x * 10000.0F) / 10000.0F; + p.y = Math.round(p.y * 10000.0F) / 10000.0F; + p.z = Math.round(p.z * 10000.0F) / 10000.0F; + ret = p; + } else if (mode == 2) { + this.extentSpin.copy((Point3)value); + } + break; + case 6: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Extent Rotation Amount")); + } else if (mode == 1) { + ret = new Float(this.extentRotation); + } else if (mode == 2) { + this.extentRotation = (Float)value; + } + break; + default: + ret = super.properties(index, offset + 7, mode, value); + } + + return ret; + } + + @Override + public String toString() { + String retVal = super.toString() + "[cycleTime " + this.cycleTime / 1000.0F + ", cycles " + this.cycles + ", "; + if (!this.loopInfinite) { + retVal = retVal + " NOT"; + } + + return retVal + " Infinite]"; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(5, classCookie); + super.saveState(s); + s.saveBoolean(this.loopInfinite); + s.saveInt(this.cycleTime); + s.saveInt(this.cycles); + s.save(this.extentPoint); + s.save(this.extentScale); + s.save(this.extentSpin); + s.saveFloat(this.extentRotation); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 4: + super.restoreState(r); + this.cycleTime = r.restoreInt(); + this.cycles = r.restoreInt(); + this.extentPoint = (Point3)r.restore(); + this.extentScale = (Point3)r.restore(); + this.extentSpin = (Point3)r.restore(); + this.extentRotation = r.restoreFloat(); + break; + case 5: + super.restoreState(r); + this.loopInfinite = r.restoreBoolean(); + this.cycleTime = r.restoreInt(); + this.cycles = r.restoreInt(); + this.extentPoint = (Point3)r.restore(); + this.extentScale = (Point3)r.restore(); + this.extentSpin = (Point3)r.restore(); + this.extentRotation = r.restoreFloat(); + break; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/RemotePortal.java b/NET/worlds/scape/RemotePortal.java new file mode 100644 index 0000000..aa3621e --- /dev/null +++ b/NET/worlds/scape/RemotePortal.java @@ -0,0 +1,73 @@ +package NET.worlds.scape; + +import NET.worlds.network.URL; +import java.io.IOException; +import java.util.Enumeration; + +public class RemotePortal extends WObject { + private static Object classCookie = new Object(); + + RemotePortal() { + } + + @Override + public void saveState(Saver s) throws IOException { + assert false; + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + Portal p = new Portal(); + r.replace(this, p); + int vers = r.restoreVersion(classCookie); + WObject dlRepresentation = null; + WObject initialRepresentation = null; + p.superRestoreState(r); + Point3 p1 = (Point3)r.restore(); + Point3 p2 = (Point3)r.restore(); + p.moveTo(p1); + p.setFarCorner(p2); + Point3 p3 = (Point3)r.restore(); + Point3 p4 = (Point3)r.restore(); + URL wname = URL.restore(r); + String rname = r.restoreString(); + p.connectTo(wname, rname, p3, p4); + switch (vers) { + case 0: + r.setOldFlag(); + r.restoreBoolean(); + dlRepresentation = (WObject)r.restoreMaybeNull(); + initialRepresentation = (WObject)r.restoreMaybeNull(); + r.restoreMaybeNull(); + break; + case 1: + dlRepresentation = (WObject)r.restoreMaybeNull(); + initialRepresentation = (WObject)r.restoreMaybeNull(); + break; + default: + throw new TooNewException(); + } + + if (initialRepresentation instanceof Surface) { + Surface s = (Surface)initialRepresentation; + Material m = s.getMaterial(); + s.setMaterial(null); + p.setMaterial(m); + } + + if (dlRepresentation instanceof Surface) { + Surface s = (Surface)dlRepresentation; + Material m = s.getMaterial(); + s.setMaterial(null); + p.setMaterial(m); + } + + if (initialRepresentation != null) { + for (Enumeration en = initialRepresentation.getHandlers(); en.hasMoreElements(); en = initialRepresentation.getHandlers()) { + SuperRoot h = (SuperRoot)en.nextElement(); + initialRepresentation.removeHandler(h); + p.addHandler(h); + } + } + } +} diff --git a/NET/worlds/scape/RemoveObjectAction.java b/NET/worlds/scape/RemoveObjectAction.java new file mode 100644 index 0000000..73526a6 --- /dev/null +++ b/NET/worlds/scape/RemoveObjectAction.java @@ -0,0 +1,72 @@ +package NET.worlds.scape; + +import java.io.IOException; +import java.util.Vector; + +public class RemoveObjectAction extends SetPropertyAction { + private SuperRoot _value; + private static Object classCookie = new Object(); + + @Override + public Persister trigger(Event e, Persister seqID) { + assert !this.useParam(); + + this.remove(this._value); + return null; + } + + @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) { + VectorProperty vp = new VectorProperty(this, index, "Object to Remove"); + SuperRoot target = this.getTarget(); + if (this._value == null && target != null) { + ret = ObjectPropertyAdder.make(vp, target, "NET.worlds.scape.SuperRoot"); + } else { + vp.allowSetNull(); + ret = vp; + } + } else if (mode == 1) { + ret = new Vector(1); + if (this._value != null) { + ((Vector)ret).addElement(this._value); + } + } else if (mode == 4) { + assert value == this._value; + + this._value = null; + } else if (mode == 3) { + assert this._value == null; + + this._value = (SuperRoot)value; + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + super.saveState(s); + s.saveMaybeNull(this._value); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 1: + super.restoreState(r); + this._value = (SuperRoot)r.restoreMaybeNull(); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/RenderWare.java b/NET/worlds/scape/RenderWare.java new file mode 100644 index 0000000..8c811f3 --- /dev/null +++ b/NET/worlds/scape/RenderWare.java @@ -0,0 +1,7 @@ +package NET.worlds.scape; + +public class RenderWare { + public static native boolean get3DHardwareInUse(); + + public static native boolean get3DHardwareAvailable(); +} diff --git a/NET/worlds/scape/Restorer.java b/NET/worlds/scape/Restorer.java new file mode 100644 index 0000000..fa1e774 --- /dev/null +++ b/NET/worlds/scape/Restorer.java @@ -0,0 +1,430 @@ +package NET.worlds.scape; + +import NET.worlds.core.IniFile; +import NET.worlds.network.URL; +import java.io.DataInput; +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +public class Restorer { + private DataInput is; + private boolean myFile; + private Hashtable<Integer, Class<?>> classTable; + private Hashtable<Object, Persister> objectTable; + private Hashtable<Object, Integer> cookieTable; + private URL reference; + private int _version; + private boolean _oldFlag; + private int _dblevel = 0; + private Integer _firstRead = null; + + public URL getReferenceURL() { + return this.reference; + } + + public final int version() { + return this._version; + } + + private Restorer(String fileName) throws IOException, BadFormatException, TooNewException { + this(new DataInputStream(new FileInputStream(new File(fileName)))); + if (this._dblevel > 0) { + System.out.println("Restoring from " + fileName); + } + + this.myFile = true; + } + + public Restorer(String fileName, URL url) throws IOException, BadFormatException, TooNewException { + this(fileName); + this.reference = url; + } + + public Restorer(URL url) throws IOException, BadFormatException, TooNewException { + this(url.unalias(), url); + } + + public Restorer(DataInput is) throws IOException, BadFormatException, TooNewException { + this.is = is; + this._dblevel = IniFile.gamma().getIniInt("RESTORE_DEBUG", 0); + String header = this.restoreString(); + if (header != null && header.equals("PERSISTER Worlds, Inc.")) { + this._version = this.restoreInt(); + if (this._dblevel > 0) { + System.out.println("Persister version " + this._version + " {"); + } + + if (this._version < 1) { + throw new BadFormatException(); + } else if (this._version > Saver.version()) { + throw new TooNewException(); + } else { + this.classTable = new Hashtable<Integer, Class<?>>(); + this.objectTable = new Hashtable<Object, Persister>(); + this.cookieTable = new Hashtable<Object, Integer>(); + } + } else { + throw new BadFormatException(); + } + } + + public Restorer(DataInput is, URL url) throws IOException, BadFormatException, TooNewException { + this(is); + this.reference = url; + } + + public int restoreVersion(Object cookie) throws IOException { + if (this._version == 1) { + return 0; + } else { + Integer oldv = this.cookieTable.get(cookie); + int v; + if (oldv == null) { + v = this.restoreInt(); + this.cookieTable.put(cookie, new Integer(v)); + } else { + v = oldv; + } + + return v; + } + } + + public Persister restore() throws IOException, TooNewException { + return this.restore(true); + } + + public Persister restore(boolean restoreContents) throws IOException, TooNewException { + boolean firstCall = this._firstRead == null; + Integer hc = new Integer(this.restoreInt()); + if (this._dblevel > 0) { + System.out.print("Object:" + Integer.toString(hc, 16)); + } + + if (this.objectTable.containsKey(hc)) { + Persister obj = this.objectTable.get(hc); + if (this._dblevel > 0) { + System.out.println(" - old: " + obj.getClass().getName() + " (" + Integer.toString(hc, 16) + ")"); + } + + return obj; + } else { + Persister p = null; + + try { + Class<?> c = this.restoreClass(true); + if (this._dblevel > 0) { + System.out.println(" {"); + } + + try { + p = (Persister)c.newInstance(); + } catch (NoSuchMethodError var7) { + System.out.println(c); + var7.printStackTrace(System.out); + throw var7; + } + } catch (InstantiationException var8) { + var8.printStackTrace(System.out); + + assert false; + } catch (IllegalAccessException var9) { + var9.printStackTrace(System.out); + + assert false; + } + + this.objectTable.put(hc, p); + if (restoreContents) { + p.restoreState(this); + } + + if (this._dblevel > 0) { + System.out.println((restoreContents ? "} Done with: " : "} Created: ") + Integer.toString(hc, 16)); + } + + Persister obj = this.objectTable.get(hc); + if (firstCall) { + this._firstRead = hc; + } + + return obj; + } + } + + public Vector<Object> restoreVectorMaybeNull() throws IOException, TooNewException { + return this.restoreBoolean() ? this.restoreVector() : null; + } + + public Persister restoreMaybeNull() throws IOException, TooNewException { + if (this.restoreBoolean()) { + if (this._dblevel > 0) { + System.out.println("null"); + } + + return null; + } else { + return this.restore(); + } + } + + public Class<?> restoreClass() throws IOException { + return this.restoreClass(true); + } + + public Class<?> restoreClass(boolean printdebug) throws IOException { + Class<?> c = null; + Integer classhc = new Integer(this.restoreInt()); + if (this.classTable.containsKey(classhc)) { + c = this.classTable.get(classhc); + if (this._dblevel > 0 && printdebug) { + System.out.print("..." + c.getName() + " [" + Integer.toString(classhc, 16) + "]"); + } + } else { + String s = this.restoreString(); + if (this._dblevel > 0 && printdebug) { + System.out.print("---" + s + " [" + Integer.toString(classhc, 16) + "]"); + } + + try { + c = Class.forName(s); + } catch (ClassNotFoundException var8) { + try { + if (s.equals("NET.worlds.network.World")) { + if (this._dblevel > 0) { + System.out.print(" (Converting NET.worlds.network.World to NET.worlds.scape.World)"); + } + + c = Class.forName("NET.worlds.scape.World"); + } else { + if (this._dblevel > 0) { + System.out.print(" (Converting " + s + " to NET.worlds.scape." + s + ")"); + } + + c = Class.forName("NET.worlds.scape." + s); + } + } catch (ClassNotFoundException var7) { + throw new Error("Can't find class " + s); + } + } + + this.classTable.put(classhc, c); + } + + return c; + } + + private native Object makeArray(Class<?> var1, int var2); + + public Persister[] restoreArray() throws IOException, TooNewException { + Class<?> arrayclass = null; + if (this._version > 4) { + arrayclass = this.restoreClass(false); + } + + int length = this.restoreInt(); + Persister[] pa = (Persister[])null; + if (arrayclass == null) { + if (this._dblevel > 0) { + System.out.println("Array of " + Integer.toString(length, 16) + " items {"); + } + + pa = new Persister[length]; + } else { + String classname = arrayclass.getName(); + + assert classname.startsWith("[L"); + + assert classname.endsWith(";"); + + classname = classname.substring(2); + classname = classname.substring(0, classname.length() - 1); + if (this._dblevel > 0) { + System.out.println("Array of " + Integer.toString(length, 16) + " " + classname + " {"); + } + + try { + arrayclass = Class.forName(classname); + } catch (ClassNotFoundException var6) { + throw new Error("Can't find class " + classname.substring(1)); + } + + Object ob = this.makeArray(arrayclass, length); + pa = (Persister[])ob; + } + + for (int i = 0; i < length; i++) { + pa[i] = this.restoreMaybeNull(); + } + + if (this._dblevel > 0) { + System.out.println("} Done with array"); + } + + return pa; + } + + public Vector<Object> restoreVector() throws IOException, TooNewException { + int length = this.restoreInt(); + if (this._dblevel > 0) { + System.out.println("Vector of " + Integer.toString(length, 16) + " items {"); + } + + Vector<Object> v = new Vector<Object>(length); + + for (int i = 0; i < length; i++) { + v.addElement(this.restore()); + } + + if (this._dblevel > 0) { + System.out.println("} Done with vector"); + } + + return v; + } + + public Vector<SuperRoot> restoreVectorSuperRoot() throws IOException, TooNewException { + int length = this.restoreInt(); + if (this._dblevel > 0) { + System.out.println("Vector of " + Integer.toString(length, 16) + " items {"); + } + + Vector<SuperRoot> v = new Vector<SuperRoot>(length); + + for (int i = 0; i < length; i++) { + v.addElement((SuperRoot)this.restore()); + } + + if (this._dblevel > 0) { + System.out.println("} Done with vector"); + } + + return v; + } + + public Vector<Action> restoreVectorActions() throws IOException, TooNewException { + int length = this.restoreInt(); + if (this._dblevel > 0) { + System.out.println("Vector of " + Integer.toString(length, 16) + " items {"); + } + + Vector<Action> v = new Vector<Action>(length); + + for (int i = 0; i < length; i++) { + v.addElement((Action)this.restore()); + } + + if (this._dblevel > 0) { + System.out.println("} Done with vector"); + } + + return v; + } + + public String restoreString() throws IOException { + return this.restoreBoolean() ? null : this.is.readUTF(); + } + + public boolean restoreBoolean() throws IOException { + return this.is.readBoolean(); + } + + public byte restoreByte() throws IOException { + return this.is.readByte(); + } + + public short restoreShort() throws IOException { + return this.is.readShort(); + } + + public int restoreInt() throws IOException { + return this.is.readInt(); + } + + public long restoreLong() throws IOException { + return this.is.readLong(); + } + + public float restoreFloat() throws IOException { + return this.is.readFloat(); + } + + public double restoreDouble() throws IOException { + return this.is.readDouble(); + } + + public void done() throws IOException, Error { + if (this._dblevel > 0) { + System.out.println("Calling all postRestores"); + } + + Enumeration<Persister> e = this.objectTable.elements(); + + while (e.hasMoreElements()) { + Persister p = e.nextElement(); + p.postRestore(this._version); + } + + e = this.objectTable.elements(); + + while (e.hasMoreElements()) { + Object obj = e.nextElement(); + if (obj != this.objectTable.get(this._firstRead) && obj instanceof SuperRoot) { + SuperRoot s = (SuperRoot)obj; + if (s.getOwner() == null) { + System.out.println("Warning: " + s.getName() + " was not owned by any object."); + s.finalize(); + } + } + } + + String trailer = this.restoreString(); + if (!trailer.equals("END PERSISTER")) { + throw new Error("Format error in save file"); + } else { + if (this.myFile) { + ((DataInputStream)this.is).close(); + } + + this.classTable = null; + this.objectTable = null; + this.cookieTable = null; + if (this._dblevel > 0) { + System.out.println("} Done with persister"); + } + } + } + + public void setOldFlag() { + this._oldFlag = true; + if (this._dblevel > 0) { + System.out.println("----OLD!----"); + } + } + + public boolean oldFlag() { + return this._oldFlag; + } + + public void replace(Persister old, Persister replacement) { + System.out.println("Converting a " + old.getClass().getName() + " to a " + replacement.getClass().getName()); + boolean found = false; + Enumeration<Object> oe = this.objectTable.keys(); + + while (oe.hasMoreElements()) { + Object k = oe.nextElement(); + if (this.objectTable.get(k) == old) { + this.objectTable.put(k, replacement); + found = true; + break; + } + } + + assert found; + } +} diff --git a/NET/worlds/scape/RollBehavior.java b/NET/worlds/scape/RollBehavior.java new file mode 100644 index 0000000..19f5865 --- /dev/null +++ b/NET/worlds/scape/RollBehavior.java @@ -0,0 +1,79 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class RollBehavior extends VelocityBehavior { + public float rollFactor; + private long lastTime; + private float bumpFraction; + private static Object classCookie = new Object(); + + public RollBehavior(Point3Temp vel, float diameter) { + super(vel, 0.0F, Point3Temp.make(0.0F, 0.0F, 1.0F), 0.0F, 0.0F); + this.rollFactor = 360.0F / (3.1416F * diameter); + } + + public RollBehavior() { + } + + @Override + public boolean handle(FrameEvent e) { + float vel = this.linearVel; + float dT = (float)(e.time - this.lastTime) / 1000.0F; + this.bumpFraction = 1.0F; + super.handle(e); + if (vel != 0.0F && this.lastTime != 0L) { + e.receiver.worldSpin(-this.dir.y, this.dir.x, this.dir.z, this.dir.length() * dT * vel * this.rollFactor * this.bumpFraction); + } + + this.lastTime = e.time; + return true; + } + + @Override + public boolean handle(BumpEventTemp b) { + this.bumpFraction = b.fraction; + return super.handle(b); + } + + @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 = FloatPropertyEditor.make(new Property(this, index, "Roll Factor")); + } else if (mode == 1) { + ret = new Float(this.rollFactor); + } else if (mode == 2) { + this.rollFactor = (Float)value; + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + s.saveFloat(this.rollFactor); + s.saveFloat(this.bumpFraction); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this.rollFactor = r.restoreFloat(); + this.bumpFraction = r.restoreFloat(); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/RollWidget.java b/NET/worlds/scape/RollWidget.java new file mode 100644 index 0000000..e9e71b4 --- /dev/null +++ b/NET/worlds/scape/RollWidget.java @@ -0,0 +1,21 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; + +class RollWidget extends WidgetButton { + public RollWidget(ToolBar toolbar) { + super(toolbar, "roll.gif", Console.message("Roll")); + } + + @Override + public String drag(boolean initialDrag, float deltax, float deltay) { + if (Math.abs(deltay) > Math.abs(deltax)) { + deltax = 0.0F; + } + + Transform t = Transform.make(); + this.applyWorldTransform(initialDrag, t.spin(this.getWorldAxis(0, 1, 0), deltax)); + t.recycle(); + return "Roll"; + } +} diff --git a/NET/worlds/scape/RollingAttribute.java b/NET/worlds/scape/RollingAttribute.java new file mode 100644 index 0000000..5293818 --- /dev/null +++ b/NET/worlds/scape/RollingAttribute.java @@ -0,0 +1,188 @@ +package NET.worlds.scape; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class RollingAttribute extends Attribute { + RollBehavior rb = new RollBehavior(); + public float initialKickVel = 200.0F; + private Point3 kp = new Point3(); + private float kv = 0.0F; + private Point3 kd = new Point3(); + private static Object classCookie = new Object(); + + public RollingAttribute(int attrID) { + super(attrID); + this.rb.linearDamp = 0.95F; + this.rb.rollFactor = 1.0F; + this.rb.setNotifyAttribute(this); + } + + public RollingAttribute() { + this.rb.linearDamp = 0.8F; + this.rb.setNotifyAttribute(this); + } + + public void set(Point3Temp p, float v, Point3Temp d) { + if (this.kp.x != p.x || this.kp.y != p.y || this.kp.x != p.z) { + this.kp.x = p.x; + this.kp.y = p.y; + this.kp.z = p.z; + this.kv = v; + this.kd.x = d.x; + this.kd.y = d.y; + this.kd.z = d.z; + ((WObject)this.getOwner().getOwner()).moveTo(this.kp); + this.rb.linearVel = this.kv; + this.rb.setDir(this.kd); + this.noteChange(); + } + } + + public void notifyStopped() { + WObject ball = (WObject)((Sharer)this.getOwner()).getOwner(); + Point3Temp pos = ball.getPosition(); + this.set(pos, 0.0F, Point3Temp.make(0.0F, 0.0F, 0.0F)); + } + + public void get(Point3Temp p, float v, Point3Temp d) { + p.x = this.kp.x; + p.y = this.kp.y; + p.z = this.kp.z; + v = this.kv; + d.x = this.kd.x; + d.y = this.kd.y; + d.z = this.kd.z; + } + + @Override + protected void noteAddingTo(SuperRoot owner) { + WObject parent = (WObject)owner.getOwner(); + parent.addHandler(this.rb); + } + + public boolean handle(BumpEventTemp b) { + if (b.target == b.receiver && !(this.rb.linearVel > 0.0F)) { + if (this.rb.linearVel == 0.0F) { + Point3Temp pos = b.target.getWorldPosition(); + WObject kicker = (WObject)b.source; + float alpha = kicker.getYaw(); + Point3Temp kpos = kicker.getWorldPosition(); + double dx = kpos.x - pos.x; + double dy = kpos.y - pos.y; + Math.atan2(dx, dy); + float kickang = (float)((360.0F - alpha + 90.0F) * Math.PI / 180.0); + Point3Temp kickdir = Point3Temp.make((float)Math.cos(kickang), (float)Math.sin(kickang), 0.0F); + pos.x = pos.x + kickdir.x; + pos.y = pos.y + kickdir.y; + this.set(pos, this.initialKickVel, kickdir); + } + } else { + if (b.target instanceof Camera) { + double dx = this.rb.dir.x; + double dy = this.rb.dir.y; + Math.atan2(dx, dy); + double theta = dy + 60.0 * Math.random() - 30.0; + double var12 = dx * Math.cos(theta * Math.PI / 180.0); + dy = dx * Math.sin(theta * Math.PI / 180.0); + this.rb.dir.x = (float)var12; + this.rb.dir.y = (float)dy; + } + + this.rb.processBumpEvent(b); + if (b.target instanceof Camera || b.source instanceof Camera) { + Point3Temp pos = ((WObject)((Sharer)this.getOwner()).getOwner()).getWorldPosition(); + this.set(pos, this.rb.linearVel, this.rb.dir); + } + } + + return true; + } + + @Override + public void generateNetData(DataOutputStream s) throws IOException { + s.writeFloat(this.kp.x); + s.writeFloat(this.kp.y); + s.writeFloat(this.kp.z); + s.writeFloat(this.kv); + s.writeFloat(this.kd.x); + s.writeFloat(this.kd.y); + s.writeFloat(this.kd.z); + } + + @Override + public void setFromNetData(DataInputStream ds, int len) throws IOException { + Point3Temp pos = Point3Temp.make(); + float vel = 0.0F; + Point3Temp dir = Point3Temp.make(); + pos.x = ds.readFloat(); + pos.y = ds.readFloat(); + pos.z = ds.readFloat(); + vel = ds.readFloat(); + dir.x = ds.readFloat(); + dir.y = ds.readFloat(); + dir.z = ds.readFloat(); + this.set(pos, vel, dir); + } + + @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 = FloatPropertyEditor.make(new Property(this, index, "Roll Factor")); + } else if (mode == 1) { + ret = new Float(this.rb.rollFactor); + } else if (mode == 2) { + this.rb.rollFactor = (Float)value; + } + break; + case 1: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Initial Kick Velocity")); + } else if (mode == 1) { + ret = new Float(this.initialKickVel); + } else if (mode == 2) { + this.initialKickVel = (Float)value; + } + break; + default: + ret = super.properties(index, offset + 2, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + super.saveState(s); + s.saveFloat(this.initialKickVel); + s.saveFloat(this.rb.rollFactor); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this.initialKickVel = r.restoreFloat(); + float threshold = r.restoreFloat(); + break; + case 1: + super.restoreState(r); + this.initialKickVel = r.restoreFloat(); + this.rb.rollFactor = r.restoreFloat(); + break; + default: + throw new TooNewException(); + } + } + + @Override + public String toString() { + return super.toString() + " [From " + this.kp + " with velocity " + this.kv + " toward " + this.kd + "] "; + } +} diff --git a/NET/worlds/scape/Room.java b/NET/worlds/scape/Room.java new file mode 100644 index 0000000..a10305c --- /dev/null +++ b/NET/worlds/scape/Room.java @@ -0,0 +1,996 @@ +package NET.worlds.scape; + +import NET.worlds.console.Main; +import NET.worlds.core.Std; +import NET.worlds.network.Galaxy; +import NET.worlds.network.NetworkRoom; +import java.awt.Color; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Vector; + +public class Room extends WObject implements TeleportStatus { + public WObject highlightTarget; + private int sceneID; + public Point3 defaultPosition = new Point3(100.0F, 100.0F, 120.0F); + public Point3 defaultOrientationAxis = new Point3(0.0F, 0.0F, -1.0F); + public float defaultOrientation = 0.0F; + String teleportChain = "home:avatargallery/avatar.world#[email protected],145.0,150.0,89.0"; + int roomLoadTime = 0; + int teleportInterval = -1; + boolean teleported = false; + private RoomEnvironment environment; + private Vector<Portal> outgoingPortals = new Vector<Portal>(); + private Vector<AudibilityFilter> aFilters = new Vector<AudibilityFilter>(); + private Point3 lightPosition = new Point3(-1.0F, 1.0F, -1.0F); + private Color lightColor = new Color(255, 255, 255); + private int lightid = 0; + private int lightid2 = 0; + private int renderStamp; + private static int timeoutAge = 15000; + private Vector<FrameHandler> frameHandlers = new Vector<FrameHandler>(); + private Vector<WObject> frameHandlerWObjects = new Vector<WObject>(); + private Color skyColor; + private Color groundColor; + private Vector<Prerenderable> prerenderHandlers = new Vector<Prerenderable>(); + private Vector<Postrenderable> postrenderHandlers = new Vector<Postrenderable>(); + private static int isRendering = 4; + private static int isVIPOnly = 262144; + private static int isVIPViewOnly = 524288; + private NetworkRoom _netRoom; + private static String[] skyOptions = new String[]{"Blue Sky"}; + private static String[] groundOptions = new String[]{"Green Ground"}; + private boolean allowTeleport = true; + private static Object classCookie = new Object(); + private RoomEnvironment infiniteBackground; + + static { + nativeInit(); + } + + public Room(World world, String name) { + this.setName(name); + this.environment = new RoomEnvironment(); + this.infiniteBackground = new RoomEnvironment(); + super.add(this.environment); + super.add(this.infiniteBackground); + if (world != null) { + world.addRoom(this); + } + } + + public Room() { + } + + public static native void nativeInit(); + + @Override + public void getChildren(DeepEnumeration d) { + if (this.infiniteBackground != null) { + d.addChildElement(this.infiniteBackground); + } + + if (this.environment != null) { + d.addChildElement(this.environment); + } + + super.getChildren(d); + } + + @Override + public void setName(String newName) { + String oldName = this.getName(); + super.setName(newName); + World world = this.getWorld(); + if (world != null) { + world.renameRoom(oldName, this.getName(), this); + } + + if (!oldName.equals(newName)) { + synchronized (this) { + if (this._netRoom != null) { + this._netRoom.setName(newName); + } + } + } + } + + synchronized void register() { + assert this._netRoom == null; + + this._netRoom = new NetworkRoom(this); + } + + @Override + public void detach() { + if (this.hasClump()) { + System.out.println("Detaching clumped room " + this.getName()); + this.markVoid(); + } + + assert this._netRoom != null; + + boolean subscribed = Pilot.getActive().removeSubscribedRoom(this); + if (subscribed) { + this._netRoom.unsubscribe(); + } + + synchronized (this) { + this._netRoom.detach(); + this._netRoom = null; + } + + this.getWorld().removeRoom(this); + super.detach(); + } + + @Override + public void discard() { + this.environment.discard(); + this.infiniteBackground.discard(); + super.discard(); + this.frameHandlers.removeAllElements(); + this.frameHandlerWObjects.removeAllElements(); + this.outgoingPortals.removeAllElements(); + this.aFilters.removeAllElements(); + this.prerenderHandlers.removeAllElements(); + this.postrenderHandlers.removeAllElements(); + } + + int getSceneID() { + return this.sceneID; + } + + public Point3Temp getDefaultPosition() { + return Point3Temp.make(this.defaultPosition); + } + + public Point3Temp getDefaultOrientationAxis() { + return Point3Temp.make(this.defaultOrientationAxis); + } + + public float getDefaultOrientation() { + return this.defaultOrientation; + } + + @Override + protected final void noteAddingTo(SuperRoot s) { + World w = (World)s; + } + + public RoomEnvironment getEnvironment() { + return this.environment; + } + + public Vector<Portal> getOutgoingPortals() { + return this.outgoingPortals; + } + + public void addOutgoingPortal(Portal p) { + if (!this.outgoingPortals.contains(p)) { + this.outgoingPortals.addElement(p); + + for (int index = 0; index < this.aFilters.size(); index++) { + this.aFilters.elementAt(index).moveEmitter(); + } + } + } + + public void removeOutgoingPortal(Portal p) { + this.outgoingPortals.removeElement(p); + Vector<AudibilityFilter> v = this.getAFilters(); + + for (int v_index = 0; v_index < v.size(); v_index++) { + v.elementAt(v_index).moveEmitter(); + } + } + + public Vector<AudibilityFilter> getAFilters() { + return this.aFilters; + } + + public void addAFilter(AudibilityFilter p) { + this.aFilters.addElement(p); + } + + public void removeAFilter(AudibilityFilter a) { + this.aFilters.removeElement(a); + } + + public void move(Room from, Room to) { + Vector<AudibilityFilter> v = from.getAFilters(); + + for (int index = 0; index < v.size(); index++) { + v.elementAt(index).updateListenerState(); + } + + v = to.getAFilters(); + + for (int index = 0; index < v.size(); index++) { + v.elementAt(index).updateListenerState(); + } + } + + static native int addLight(int var0, float var1, float var2, float var3, float var4, float var5, float var6); + + static native void setLightPosition(int var0, float var1, float var2, float var3); + + static native void setLightColor(int var0, float var1, float var2, float var3); + + private void setLightPosition(float x, float y, float z) { + if (this.lightid != 0) { + setLightPosition(this.lightid, x, y, z); + } + + if (this.lightid2 != 0) { + setLightPosition(this.lightid2, -x, -y, -z); + } + } + + private void setLightColor(float red, float green, float blue) { + if (this.lightid != 0) { + setLightColor(this.lightid, red, green, blue); + } + + if (this.lightid2 != 0) { + setLightColor(this.lightid2, red / 2.0F, green / 2.0F, blue / 2.0F); + } + } + + public void setLightPosition(Point3Temp p) { + this.lightPosition.set(p.x, p.y, p.z); + this.setLightPosition(p.x, p.y, p.z); + RoomEnvironment re = this.getEnvironment(); + if (re != null) { + re.setLightPosition(p.x, p.y, p.z); + } + + re = this.getInfiniteBackground(); + if (re != null) { + re.setLightPosition(p.x, p.y, p.z); + } + } + + public void setLightColor(Color c) { + this.lightColor = new Color(c.getRGB()); + float r = c.getRed() / 256.0F; + float g = c.getGreen() / 256.0F; + float b = c.getBlue() / 256.0F; + this.setLightColor(r, g, b); + RoomEnvironment re = this.getEnvironment(); + if (re != null) { + re.setLightColor(r, g, b); + } + + re = this.getInfiniteBackground(); + if (re != null) { + re.setLightColor(r, g, b); + } + } + + public Point3Temp getLightPosition() { + return Point3Temp.make(this.lightPosition); + } + + public Color getLightColor() { + return new Color(this.lightColor.getRGB()); + } + + public void noteRef() { + this.renderStamp = Std.getRealTime(); + World w = this.getWorld(); + if (w != null) { + w.incRef(); + } + } + + public void discardIfOld() { + if (this.hasClump()) { + int age = Std.getFastTime() - this.renderStamp; + if (age > timeoutAge) { + this.markVoid(); + } + } + } + + public void generateFrameEvents(FrameEvent f) { + this.noteRef(); + if (Main.profile != 0) { + for (int i = 0; i < this.frameHandlers.size(); i++) { + FrameHandler fh = this.frameHandlers.elementAt(i); + WObject fhw = this.frameHandlerWObjects.elementAt(i); + int start = Std.getRealTime(); + long startBytes = Runtime.getRuntime().freeMemory(); + f.retargetAndDeliver(fh, fhw); + int dur = Std.getRealTime() - start; + long used = startBytes - Runtime.getRuntime().freeMemory(); + if (dur > Main.profile) { + if (fh instanceof SuperRoot) { + System.out.println("Took " + dur + "ms and " + used + " bytes to call frameHandler " + ((SuperRoot)fh).getName() + " of " + fhw.getName()); + } else { + System.out.println("Took " + dur + "ms and " + used + " bytes to call frameHandler " + fh + " of " + fhw.getName()); + } + } + } + } else { + for (int ix = 0; ix < this.frameHandlers.size(); ix++) { + f.retargetAndDeliver(this.frameHandlers.elementAt(ix), this.frameHandlerWObjects.elementAt(ix)); + } + } + + if (this.teleportChain != null && this.teleportInterval != -1 && !this.teleported && Std.getSynchronizedTime() % this.teleportInterval == 0) { + this.teleported = true; + TeleportAction.teleport(this.teleportChain, this); + } + } + + @Override + public void teleportStatus(String err, String dest) { + if (err != null) { + this.teleported = false; + } + } + + private int findFrameHandler(FrameHandler h, WObject o) { + int next = 0; + + while (true) { + next = this.frameHandlers.indexOf(h, next); + if (next == -1) { + return -1; + } + + if (this.frameHandlerWObjects.elementAt(next) == o) { + return next; + } + + next++; + } + } + + void addFrameHandler(FrameHandler h, WObject o) { + int i = this.findFrameHandler(h, o); + if (i < 0) { + this.frameHandlers.addElement(h); + this.frameHandlerWObjects.addElement(o); + } + } + + void removeFrameHandler(FrameHandler h, WObject o) { + int i = this.findFrameHandler(h, o); + if (i >= 0) { + this.frameHandlers.removeElementAt(i); + this.frameHandlerWObjects.removeElementAt(i); + } + } + + native void createScene(); + + native void destroyScene(); + + @Override + protected void markVoid() { + this.infiniteBackground.markVoid(); + this.environment.markVoid(); + super.markVoid(); + this.destroyScene(); + this.lightid = 0; + this.lightid2 = 0; + } + + @Override + protected void noteTransformChange() { + super.noteTransformChange(); + this.getInfiniteBackground().setTransform(this); + this.getEnvironment().setTransform(this); + int i = this.outgoingPortals.size(); + + while (--i >= 0) { + this.outgoingPortals.elementAt(i).discardTransform(); + } + } + + public void setSkyColor(Color c) { + this.skyColor = c; + } + + public Color getSkyColor() { + return this.skyColor; + } + + public void setGroundColor(Color c) { + this.groundColor = c; + } + + public Color getGroundColor() { + return this.groundColor; + } + + public boolean getVIPOnly() { + return (this.flags & isVIPOnly) != 0; + } + + public void prerender(Camera cam, float x, float y, float z, float d) { + this.flags = this.flags | isRendering; + this.infiniteBackground.prerender(); + this.environment.prerender(); + Pilot.addVisibleRoom(this, x, y, z, d); + int end = this.prerenderHandlers.size(); + + for (int i = 0; i < end; i++) { + Prerenderable p = this.prerenderHandlers.elementAt(i); + p.prerender(cam); + } + } + + public void addPrerenderHandler(Prerenderable o) { + assert (this.flags & isRendering) == 0; + + if (!this.prerenderHandlers.contains(o)) { + this.prerenderHandlers.addElement(o); + } + } + + public void prependPrerenderHandler(Prerenderable o) { + assert (this.flags & isRendering) == 0; + + if (!this.prerenderHandlers.contains(o)) { + this.prerenderHandlers.insertElementAt(o, 0); + } + } + + public void removePrerenderHandler(Prerenderable o) { + assert (this.flags & isRendering) == 0; + + this.prerenderHandlers.removeElement(o); + } + + public void postrender(Camera cam, float x, float y, float z, float d) { + Pilot.addVisibleRoom(this, x, y, z, d); + int i = this.postrenderHandlers.size(); + + while (--i >= 0) { + Postrenderable p = this.postrenderHandlers.elementAt(i); + p.postrender(cam); + } + + this.flags = this.flags & ~isRendering; + } + + public void addPostrenderHandler(Postrenderable o) { + assert (this.flags & isRendering) == 0; + + if (!this.postrenderHandlers.contains(o)) { + this.postrenderHandlers.addElement(o); + } + } + + public void prependPostrenderHandler(Postrenderable o) { + assert (this.flags & isRendering) == 0; + + if (!this.postrenderHandlers.contains(o)) { + this.postrenderHandlers.insertElementAt(o, 0); + } + } + + public void removePostrenderHandler(Postrenderable o) { + assert (this.flags & isRendering) == 0; + + this.postrenderHandlers.removeElement(o); + } + + @Override + public void detectBump(BumpEventTemp b) { + if (this.environment.getBumpable()) { + this.environment.detectBump(b); + } + + super.detectBump(b); + } + + @Override + public BoundBoxTemp getBoundBox() { + return BoundBoxTemp.make(Point3Temp.make(), Point3Temp.make()); + } + + @Override + public World getWorld() { + return (World)this.getOwner(); + } + + @Override + public Room getRoom() { + return this; + } + + @Override + public Room getRoomFromClump() { + return this; + } + + @Override + public Room getRoomNotFromClump() { + return this; + } + + public Galaxy getGalaxy() { + World w = this.getWorld(); + return w == null ? null : w.getConsole().getGalaxy(); + } + + public String getURL() { + return this.getWorld().getSourceURL().getAbsolute() + "#" + this.getName(); + } + + public boolean registerShare(WObject w) { + w.notifyRegister(1); + return true; + } + + private void processPendingRegistrations() { + this.notifyRegister(1); + } + + public NetworkRoom getNetworkRoom() { + return this._netRoom; + } + + void subscribe(RoomSubscribeInfo info) { + assert this._netRoom != null; + + this._netRoom.subscribe(info); + } + + void subscribeDist(RoomSubscribeInfo info) { + assert this._netRoom != null; + + this._netRoom.subscribeDist(info); + } + + void unsubscribe() { + if (this._netRoom != null) { + this._netRoom.unsubscribe(); + } else { + System.out.println(this + ": unsubscribing from bad room?"); + new Exception().printStackTrace(System.out); + } + } + + public boolean getAllowTeleport() { + return this.allowTeleport; + } + + @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 = new Property(this, index, "Environment"); + } else if (mode == 1) { + ret = this.environment; + } + break; + case 1: + if (mode == 0) { + ret = new Property(this, index, "Infinite Background"); + } else if (mode == 1) { + ret = this.infiniteBackground; + } + break; + case 2: + if (mode == 0) { + ret = ColorPropertyEditor.make(new Property(this, index, "Sky Color").allowSetNull()); + if (this.getSkyColor() == null) { + ret = MaybeNullPropertyEditor.make((Property)ret, Color.blue); + } + } else if (mode == 1) { + ret = this.getSkyColor(); + } else if (mode == 2) { + this.setSkyColor((Color)value); + } + break; + case 3: + if (mode == 0) { + ret = ColorPropertyEditor.make(new Property(this, index, "Ground Color").allowSetNull()); + if (this.getGroundColor() == null) { + ret = MaybeNullPropertyEditor.make((Property)ret, Color.green); + } + } else if (mode == 1) { + ret = this.getGroundColor(); + } else if (mode == 2) { + this.setGroundColor((Color)value); + } + break; + case 4: + if (mode == 0) { + ret = Point3PropertyEditor.make(new Property(this, index, "Default Position")); + } else if (mode == 1) { + ret = new Point3(this.getDefaultPosition()); + } else if (mode == 2) { + this.defaultPosition = (Point3)value; + } + break; + case 5: + if (mode == 0) { + ret = Point3PropertyEditor.make(new Property(this, index, "Default Orientation Axis")); + } else if (mode == 1) { + ret = new Point3(this.getDefaultOrientationAxis()); + } else if (mode == 2) { + this.defaultOrientationAxis = (Point3)value; + } + break; + case 6: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Default Orientation Angle")); + } else if (mode == 1) { + ret = new Float(this.getDefaultOrientation()); + } else if (mode == 2) { + this.defaultOrientation = (Float)value; + } + break; + case 7: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "VIP only"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean((this.flags & isVIPOnly) != 0); + } else if (mode == 2) { + if ((Boolean)value) { + this.flags = this.flags | isVIPOnly; + } else { + this.flags = this.flags & ~isVIPOnly; + } + } + break; + case 8: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Visible to VIP only"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean((this.flags & isVIPViewOnly) != 0); + } else if (mode == 2) { + if ((Boolean)value) { + this.flags = this.flags | isVIPViewOnly; + } else { + this.flags = this.flags & ~isVIPViewOnly; + } + } + break; + case 9: + if (mode == 0) { + ret = Point3PropertyEditor.make(new Property(this, index, "Light Source Direction")); + } else if (mode == 1) { + ret = this.lightPosition; + } else if (mode == 2) { + this.setLightPosition((Point3)value); + } + break; + case 10: + if (mode == 0) { + ret = ColorPropertyEditor.make(new Property(this, index, "Light Color")); + } else if (mode == 1) { + ret = this.lightColor; + } else if (mode == 2) { + this.setLightColor((Color)value); + } + break; + case 11: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Time To Auto-Teleport (seconds, -1 = never)")); + } else if (mode == 1) { + ret = new Integer(this.teleportInterval); + } else if (mode == 2) { + this.teleportInterval = (Integer)value; + } + break; + case 12: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Auto-Teleport destination")); + } else if (mode == 1) { + ret = this.teleportChain; + } else if (mode == 2) { + this.teleportChain = new String((String)value); + } + break; + case 13: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Allow Teleporting"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.allowTeleport); + } else if (mode == 2) { + this.allowTeleport = (Boolean)value; + } + break; + default: + ret = super.properties(index, offset + 14, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(7, classCookie); + super.saveState(s); + if (this.skyColor != null) { + s.saveBoolean(true); + s.saveInt(this.skyColor.getRGB()); + } else { + s.saveBoolean(false); + } + + if (this.groundColor != null) { + s.saveBoolean(true); + s.saveInt(this.groundColor.getRGB()); + } else { + s.saveBoolean(false); + } + + s.save(this.defaultPosition); + s.save(this.defaultOrientationAxis); + s.saveFloat(this.defaultOrientation); + s.save(this.lightPosition); + s.saveInt(this.lightColor.getRGB()); + s.save(this.environment); + s.save(this.infiniteBackground); + s.saveString(this.teleportChain); + s.saveInt(this.teleportInterval); + s.saveBoolean(this.allowTeleport); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + r.setOldFlag(); + super.restoreState(r); + this.setName(r.restoreString()); + r.restore(); + if (r.restoreBoolean()) { + this.skyColor = new Color(r.restoreInt()); + } + + if (r.restoreBoolean()) { + this.groundColor = new Color(r.restoreInt()); + } + + r.restoreMaybeNull(); + this.defaultPosition = (Point3)r.restore(); + this.defaultOrientationAxis = (Point3)r.restore(); + this.defaultOrientation = r.restoreFloat(); + r.restoreVector(); + this.environment = (RoomEnvironment)r.restore(); + this.infiniteBackground = new RoomEnvironment(); + break; + case 1: + r.setOldFlag(); + super.restoreState(r); + r.restore(); + if (r.restoreBoolean()) { + this.skyColor = new Color(r.restoreInt()); + } + + if (r.restoreBoolean()) { + this.groundColor = new Color(r.restoreInt()); + } + + r.restoreMaybeNull(); + this.defaultPosition = (Point3)r.restore(); + this.defaultOrientationAxis = (Point3)r.restore(); + this.defaultOrientation = r.restoreFloat(); + this.environment = (RoomEnvironment)r.restore(); + this.infiniteBackground = new RoomEnvironment(); + break; + case 2: + r.setOldFlag(); + super.restoreState(r); + if (r.restoreBoolean()) { + this.skyColor = new Color(r.restoreInt()); + } + + if (r.restoreBoolean()) { + this.groundColor = new Color(r.restoreInt()); + } + + r.restoreMaybeNull(); + this.defaultPosition = (Point3)r.restore(); + this.defaultOrientationAxis = (Point3)r.restore(); + this.defaultOrientation = r.restoreFloat(); + this.environment = (RoomEnvironment)r.restore(); + this.infiniteBackground = new RoomEnvironment(); + break; + case 3: + r.setOldFlag(); + super.restoreState(r); + if (r.restoreBoolean()) { + this.skyColor = new Color(r.restoreInt()); + } + + if (r.restoreBoolean()) { + this.groundColor = new Color(r.restoreInt()); + } + + r.restoreMaybeNull(); + this.defaultPosition = (Point3)r.restore(); + this.defaultOrientationAxis = (Point3)r.restore(); + this.defaultOrientation = r.restoreFloat(); + this.environment = (RoomEnvironment)r.restore(); + this.infiniteBackground = (RoomEnvironment)r.restore(); + break; + case 4: + r.setOldFlag(); + super.restoreState(r); + if (r.restoreBoolean()) { + this.skyColor = new Color(r.restoreInt()); + } + + if (r.restoreBoolean()) { + this.groundColor = new Color(r.restoreInt()); + } + + this.defaultPosition = (Point3)r.restore(); + this.defaultOrientationAxis = (Point3)r.restore(); + this.defaultOrientation = r.restoreFloat(); + this.environment = (RoomEnvironment)r.restore(); + this.infiniteBackground = (RoomEnvironment)r.restore(); + break; + case 5: + super.restoreState(r); + if (r.restoreBoolean()) { + this.skyColor = new Color(r.restoreInt()); + } + + if (r.restoreBoolean()) { + this.groundColor = new Color(r.restoreInt()); + } + + this.defaultPosition = (Point3)r.restore(); + this.defaultOrientationAxis = (Point3)r.restore(); + this.defaultOrientation = r.restoreFloat(); + this.setLightPosition((Point3)r.restore()); + this.setLightColor(new Color(r.restoreInt())); + this.environment = (RoomEnvironment)r.restore(); + this.infiniteBackground = (RoomEnvironment)r.restore(); + break; + case 6: + super.restoreState(r); + if (r.restoreBoolean()) { + this.skyColor = new Color(r.restoreInt()); + } + + if (r.restoreBoolean()) { + this.groundColor = new Color(r.restoreInt()); + } + + this.defaultPosition = (Point3)r.restore(); + this.defaultOrientationAxis = (Point3)r.restore(); + this.defaultOrientation = r.restoreFloat(); + this.setLightPosition((Point3)r.restore()); + this.setLightColor(new Color(r.restoreInt())); + this.environment = (RoomEnvironment)r.restore(); + this.infiniteBackground = (RoomEnvironment)r.restore(); + this.teleportChain = r.restoreString(); + this.teleportInterval = r.restoreInt(); + this.roomLoadTime = Std.getFastTime() / 1000; + break; + case 7: + super.restoreState(r); + if (r.restoreBoolean()) { + this.skyColor = new Color(r.restoreInt()); + } + + if (r.restoreBoolean()) { + this.groundColor = new Color(r.restoreInt()); + } + + this.defaultPosition = (Point3)r.restore(); + this.defaultOrientationAxis = (Point3)r.restore(); + this.defaultOrientation = r.restoreFloat(); + this.setLightPosition((Point3)r.restore()); + this.setLightColor(new Color(r.restoreInt())); + this.environment = (RoomEnvironment)r.restore(); + this.infiniteBackground = (RoomEnvironment)r.restore(); + this.teleportChain = r.restoreString(); + this.teleportInterval = r.restoreInt(); + this.roomLoadTime = Std.getFastTime() / 1000; + this.allowTeleport = r.restoreBoolean(); + break; + default: + throw new TooNewException(); + } + + super.add(this.environment); + super.add(this.infiniteBackground); + } + + public void aboutToDraw() { + if (!this.hasClump() && this.getOwner() instanceof World) { + this.recursiveAddRwChildren(null); + } + } + + @Override + protected void addRwChildren(WObject parent) { + assert parent == null; + + this.createClump(); + this.createScene(); + this.newRwChildHelper(); + float red = this.lightColor.getRed() / 256.0F; + float green = this.lightColor.getGreen() / 256.0F; + float blue = this.lightColor.getBlue() / 256.0F; + this.lightid = addLight(this.sceneID, this.lightPosition.x, this.lightPosition.y, this.lightPosition.z, red, green, blue); + this.lightid2 = addLight(this.sceneID, -this.lightPosition.x, -this.lightPosition.y, -this.lightPosition.z, red * 0.5F, green * 0.5F, blue * 0.5F); + } + + @Override + public void recursiveAddRwChildren(WObject parent) { + super.recursiveAddRwChildren(parent); + this.environment.recursiveAddRwChildren(this); + this.infiniteBackground.recursiveAddRwChildren(this); + } + + public final float floorHeight(float x, float y) { + return this.floorHeight(x, y, 120.0F); + } + + public float floorHeight(float x, float y, float z) { + Transform inverse = this.getObjectToWorldMatrix().invert(); + Point3Temp p = Point3Temp.make(x, y, z).times(inverse); + inverse.recycle(); + x = p.x; + y = p.y; + z = p.z; + float height = 0.0F; + boolean patchFound = false; + Enumeration<Object> e = (Enumeration<Object>)this.getContents(); + + while (e.hasMoreElements()) { + Object o = e.nextElement(); + if (o instanceof FloorPatch && ((FloorPatch)o).inPatch(x, y)) { + float patchHeight = ((FloorPatch)o).floorHeight(x, y); + if (patchHeight <= z && (patchHeight > height || !patchFound)) { + patchFound = true; + height = ((FloorPatch)o).floorHeight(x, y); + } + } + } + + return height; + } + + public Point3 surfaceNormal(float x, float y, float z) { + Point3 normal = new Point3(0.0F, 0.0F, 1.0F); + FloorPatch patch = null; + float height = 0.0F; + boolean patchFound = false; + Enumeration<Object> e = (Enumeration<Object>)this.getContents(); + + while (e.hasMoreElements()) { + Object o = e.nextElement(); + if (o instanceof FloorPatch && ((FloorPatch)o).inPatch(x, y)) { + float patchHeight = ((FloorPatch)o).floorHeight(x, y); + if (patchHeight <= z && (patchHeight > height || !patchFound)) { + patchFound = true; + height = ((FloorPatch)o).floorHeight(x, y); + patch = (FloorPatch)o; + } + } + } + + if (patch != null) { + normal = patch.surfaceNormal(x, y); + } + + normal.vectorTimes(this.getObjectToWorldMatrix()); + return normal; + } + + public RoomEnvironment getInfiniteBackground() { + return this.infiniteBackground; + } + + @Override + public String toString() { + return this.getWorld() + "#" + this.getName(); + } +} diff --git a/NET/worlds/scape/RoomEnvironment.java b/NET/worlds/scape/RoomEnvironment.java new file mode 100644 index 0000000..18b1d1f --- /dev/null +++ b/NET/worlds/scape/RoomEnvironment.java @@ -0,0 +1,116 @@ +package NET.worlds.scape; + +import java.awt.Color; +import java.io.IOException; + +public class RoomEnvironment extends WObject { + private int lightid = 0; + private int lightid2 = 0; + int nextVertex = 1; + boolean wasEdited = false; + private static Object classCookie = new Object(); + private int sceneID; + + static { + nativeInit(); + } + + RoomEnvironment() { + } + + public static native void nativeInit(); + + @Override + protected void addRwChildren(WObject parent) { + this.createClump(); + Room r = (Room)this.getOwner(); + this.createScene(r); + this.newRwChildHelper(); + this.addLight(r.getLightPosition(), r.getLightColor()); + } + + @Override + protected void noteAddingTo(SuperRoot owner) { + Room r = (Room)owner; + } + + private void addLight(Point3Temp pos, Color c) { + assert this.lightid == 0; + + float red = c.getRed() / 256.0F; + float green = c.getGreen() / 256.0F; + float blue = c.getBlue() / 256.0F; + this.lightid = Room.addLight(this.sceneID, pos.x, pos.y, pos.z, red, green, blue); + this.lightid2 = Room.addLight(this.sceneID, -pos.x, -pos.y, -pos.z, red * 0.5F, green * 0.5F, blue * 0.5F); + } + + void setLightPosition(float x, float y, float z) { + if (this.lightid != 0) { + Room.setLightPosition(this.lightid, x, y, z); + } + + if (this.lightid2 != 0) { + Room.setLightPosition(this.lightid2, -x, -y, -z); + } + } + + void setLightColor(float red, float green, float blue) { + if (this.lightid != 0) { + Room.setLightColor(this.lightid, red, green, blue); + } + + if (this.lightid2 != 0) { + Room.setLightColor(this.lightid2, red * 0.5F, green * 0.5F, blue * 0.5F); + } + } + + @Override + public BoundBoxTemp getBoundBox() { + return BoundBoxTemp.make(Point3Temp.make(), Point3Temp.make()); + } + + @Override + protected void markVoid() { + super.markVoid(); + this.destroyScene(); + this.lightid = 0; + this.lightid2 = 0; + } + + public void markClumpEdited() { + this.wasEdited = true; + } + + public void prerender() { + if (this.wasEdited) { + this.wasEdited = false; + this.doneWithEditing(); + } + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + super.saveState(s); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + r.setOldFlag(); + super.restoreState(r); + r.restore(); + break; + case 1: + super.restoreState(r); + break; + default: + throw new TooNewException(); + } + } + + native void createScene(Room var1); + + native void destroyScene(); +} diff --git a/NET/worlds/scape/RoomSubscribeInfo.java b/NET/worlds/scape/RoomSubscribeInfo.java new file mode 100644 index 0000000..0d98959 --- /dev/null +++ b/NET/worlds/scape/RoomSubscribeInfo.java @@ -0,0 +1,15 @@ +package NET.worlds.scape; + +public class RoomSubscribeInfo { + public float x; + public float y; + public float z; + public float d; + + public RoomSubscribeInfo(float x, float y, float z, float d) { + this.x = x; + this.y = y; + this.z = z; + this.d = d; + } +} diff --git a/NET/worlds/scape/RunningActionCallback.java b/NET/worlds/scape/RunningActionCallback.java new file mode 100644 index 0000000..ca58f5b --- /dev/null +++ b/NET/worlds/scape/RunningActionCallback.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface RunningActionCallback { + void actionDone(Action var1, Event var2, Object var3); +} diff --git a/NET/worlds/scape/RunningActionHandler.java b/NET/worlds/scape/RunningActionHandler.java new file mode 100644 index 0000000..a821458 --- /dev/null +++ b/NET/worlds/scape/RunningActionHandler.java @@ -0,0 +1,153 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.Vector; + +public class RunningActionHandler extends SuperRoot implements FrameHandler, NonPersister { + private Action action; + private Persister seqID; + private RunningActionCallback callback; + private Object callbackCookie; + private static Object classCookie = new Object(); + + public static void trigger(Action act, World w, Event event) { + trigger(act, w, event, null, null); + } + + public static void trigger(Action act, World w, Event event, RunningActionCallback callb, Object o) { + if (act.isActive()) { + Persister seqID = null; + if ((seqID = act.trigger(event, seqID)) != null) { + new RunningActionHandler(w, act, seqID, callb, o); + } + } + } + + public static void trigger(Vector v, World w, Event event) { + trigger(v, w, event, null, null); + } + + public static void trigger(Vector v, World w, Event event, RunningActionCallback callb, Object o) { + Vector acts = (Vector)v.clone(); + int sz = acts.size(); + + for (int i = 0; i < sz; i++) { + Action act = (Action)acts.elementAt(i); + if (v.contains(act)) { + trigger(act, w, event, callb, o); + } + } + } + + RunningActionHandler() { + } + + private RunningActionHandler(World world, Action a, Persister seqID, RunningActionCallback callb, Object o) { + this.action = a; + this.seqID = seqID; + this.callback = callb; + this.callbackCookie = o; + world.addHandler(this); + } + + @Override + public boolean handle(FrameEvent e) { + if (!this.action.isActive() || (this.seqID = this.action.trigger(e, this.seqID)) == null) { + if (this.callback != null) { + this.callback.actionDone(this.action, e, this.callbackCookie); + } + + this.getWorld().removeHandler(this); + } + + return true; + } + + @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 = new Property(this, index, "Action"); + } else if (mode == 1) { + ret = this.action; + } + break; + case 1: + if (mode == 0) { + ret = new Property(this, index, "Sequence ID Object"); + } else if (mode == 1) { + ret = this.seqID; + } + break; + default: + ret = super.properties(index, offset + 2, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + Console.println(Console.message("Save-running")); + s.saveVersion(3, classCookie); + super.saveState(s); + s.save(this.action); + s.saveMaybeNull(this.seqID); + s.saveMaybeNull((Persister)this.callback); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + r.restore(); + this.action = (Action)r.restoreMaybeNull(); + this.callback = null; + break; + case 1: + super.restoreState(r); + this.action = (Action)r.restore(); + this.callback = null; + break; + case 2: + super.restoreState(r); + this.action = (Action)r.restore(); + this.seqID = r.restoreMaybeNull(); + this.callback = null; + break; + case 3: + super.restoreState(r); + this.action = (Action)r.restore(); + this.seqID = r.restoreMaybeNull(); + this.callback = (RunningActionCallback)r.restoreMaybeNull(); + break; + default: + throw new TooNewException(); + } + } + + @Override + public void postRestore(int version) { + super.postRestore(version); + Object[] arguments = new Object[]{new String(this.getName())}; + Console.println(MessageFormat.format(Console.message("Discarding-old"), arguments)); + SuperRoot owner = this.getOwner(); + if (owner instanceof WObject) { + ((WObject)owner).removeHandler(this); + } else if (owner instanceof World) { + ((World)owner).removeHandler(this); + } else { + Console.println(MessageFormat.format(Console.message("Unable-discard"), arguments)); + } + } + + @Override + public String toString() { + return super.toString() + ":" + this.action.getName() + "[" + this.seqID + "]"; + } +} diff --git a/NET/worlds/scape/SameRoomSensor.java b/NET/worlds/scape/SameRoomSensor.java new file mode 100644 index 0000000..268573c --- /dev/null +++ b/NET/worlds/scape/SameRoomSensor.java @@ -0,0 +1,60 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class SameRoomSensor extends Sensor implements FrameHandler { + private Room lastCamRoom; + private static Object classCookie = new Object(); + + public SameRoomSensor(Action a) { + if (a != null) { + this.addAction(a); + } + } + + public SameRoomSensor() { + } + + @Override + public void detach() { + this.lastCamRoom = null; + super.detach(); + } + + @Override + public boolean handle(FrameEvent e) { + Object owner = this.getOwner(); + if (owner != null && owner instanceof WObject) { + WObject o = (WObject)owner; + Room thisRoom = o.getRoom(); + Room thisCamRoom = Pilot.getActiveRoom(); + if (thisCamRoom == thisRoom && this.lastCamRoom != thisCamRoom) { + this.trigger(e); + } + + this.lastCamRoom = thisCamRoom; + return true; + } else { + return true; + } + } + + @Override + public void saveState(Saver s) throws IOException { + super.saveState(s); + s.saveVersion(0, classCookie); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + int vers = super.restoreStateVers(r); + if (vers > 1) { + switch (r.restoreVersion(classCookie)) { + case 0: + return; + default: + throw new TooNewException(); + } + } + } +} diff --git a/NET/worlds/scape/SaveWidget.java b/NET/worlds/scape/SaveWidget.java new file mode 100644 index 0000000..d50c040 --- /dev/null +++ b/NET/worlds/scape/SaveWidget.java @@ -0,0 +1,31 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.DialogReceiver; +import NET.worlds.console.FileSysDialog; + +class SaveWidget extends ClickWidget implements DialogReceiver { + public SaveWidget(ToolBar toolbar) { + super(toolbar, "save.gif", Console.message("Save-to-file")); + } + + @Override + public void perform() { + new FileSysDialog( + Console.getFrame(), + this, + Console.message("Save-Object-As"), + 1, + " wobject |*.wob| world |*.world;*.wor| console |*.console| pilot |*.pilot| drone |*.drone| other ||", + "", + false + ); + } + + @Override + public void dialogDone(Object who, boolean confirmed) { + if (confirmed) { + Console.getFrame().getEditTile().save(((FileSysDialog)who).fileName()); + } + } +} diff --git a/NET/worlds/scape/Saver.java b/NET/worlds/scape/Saver.java new file mode 100644 index 0000000..7b202e0 --- /dev/null +++ b/NET/worlds/scape/Saver.java @@ -0,0 +1,174 @@ +package NET.worlds.scape; + +import NET.worlds.network.URL; +import java.io.DataOutput; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +public class Saver { + static final String headerString = "PERSISTER Worlds, Inc."; + static final String trailerString = "END PERSISTER"; + private static int _version = 7; + private DataOutput os; + private boolean myFile; + private Hashtable classTable; + private Hashtable objectTable; + private Hashtable cookieTable; + private URL reference; + + public static int version() { + return _version; + } + + public URL getReferenceURL() { + return this.reference; + } + + public Saver(URL url) throws IOException { + this(new DataOutputStream(new FileOutputStream(new File(url.unalias())))); + this.reference = url; + this.myFile = true; + } + + public Saver(DataOutput os) throws IOException { + this.os = os; + this.saveString("PERSISTER Worlds, Inc."); + this.saveInt(_version); + this.classTable = new Hashtable(); + this.objectTable = new Hashtable(); + this.cookieTable = new Hashtable(); + } + + public void saveVersion(int v, Object cookie) throws IOException { + Integer oldv = (Integer)this.cookieTable.get(cookie); + if (oldv == null) { + this.saveInt(v); + this.cookieTable.put(cookie, new Integer(v)); + } else { + assert oldv == v; + } + } + + public void save(Persister p) throws IOException { + assert !(p instanceof NonPersister); + + int hashed = UniqueHasher.uh().hash(p); + this.saveInt(hashed); + if (!this.objectTable.containsKey(p)) { + this.objectTable.put(p, p); + this.saveClass(p.getClass()); + p.saveState(this); + } + } + + public void saveVectorMaybeNull(Vector v) throws IOException { + if (v == null) { + this.saveBoolean(false); + } else { + this.saveBoolean(true); + this.saveVector(v); + } + } + + public void saveMaybeNull(Persister p) throws IOException { + if (p != null && !(p instanceof NonPersister)) { + this.saveBoolean(false); + this.save(p); + } else { + this.saveBoolean(true); + } + } + + public void saveClass(Class c) throws IOException { + UniqueHasher uh = UniqueHasher.uh(); + this.saveInt(uh.hash(c.toString())); + if (!this.classTable.containsKey(c)) { + this.saveString(c.getName()); + this.classTable.put(c, c); + } + } + + public void saveArray(Persister[] pa) throws IOException { + this.saveClass(pa.getClass()); + this.saveInt(pa.length); + + for (int i = 0; i < pa.length; i++) { + this.saveMaybeNull(pa[i]); + } + } + + public void saveVector(Vector v) throws IOException { + synchronized (v) { + Enumeration en = v.elements(); + int length = 0; + + while (en.hasMoreElements()) { + Object obj = en.nextElement(); + if (obj instanceof Persister && !(obj instanceof NonPersister)) { + length++; + } + } + + this.saveInt(length); + en = v.elements(); + + while (en.hasMoreElements()) { + Object obj = en.nextElement(); + if (obj instanceof Persister && !(obj instanceof NonPersister)) { + this.save((Persister)obj); + } + } + } + } + + public void saveString(String str) throws IOException { + this.saveBoolean(str == null); + if (str != null) { + this.os.writeUTF(str); + } + } + + public void saveBoolean(boolean b) throws IOException { + this.os.writeBoolean(b); + } + + public void saveByte(byte b) throws IOException { + this.os.writeByte(b); + } + + public void saveShort(short s) throws IOException { + this.os.writeShort(s); + } + + public void saveInt(int i) throws IOException { + this.os.writeInt(i); + } + + public void saveLong(long g) throws IOException { + this.os.writeLong(g); + } + + public void saveFloat(float f) throws IOException { + this.os.writeFloat(f); + } + + public void saveDouble(double d) throws IOException { + this.os.writeDouble(d); + } + + public void done() throws IOException { + this.saveString("END PERSISTER"); + if (this.myFile) { + ((DataOutputStream)this.os).close(); + } + + this.classTable = null; + this.objectTable = null; + this.cookieTable = null; + } +} diff --git a/NET/worlds/scape/ScaleWidget.java b/NET/worlds/scape/ScaleWidget.java new file mode 100644 index 0000000..4ee1084 --- /dev/null +++ b/NET/worlds/scape/ScaleWidget.java @@ -0,0 +1,23 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; + +class ScaleWidget extends WidgetButton { + public ScaleWidget(ToolBar toolbar) { + super(toolbar, "scale.gif", Console.message("Scale")); + } + + @Override + public String drag(boolean initialDrag, float deltax, float deltay) { + WObject wobj = this.getWObject(); + float delta = Math.abs(deltax) > Math.abs(deltay) ? deltax : deltay; + delta = (float)Math.pow(1.01, delta); + if (initialDrag) { + Console.getFrame().getEditTile().addUndoable(new UndoablTransform(wobj)); + } + + wobj.scale(delta); + wobj.markEdited(); + return "Scale: " + wobj.getScale(); + } +} diff --git a/NET/worlds/scape/ScapePicMovie.java b/NET/worlds/scape/ScapePicMovie.java new file mode 100644 index 0000000..773e72d --- /dev/null +++ b/NET/worlds/scape/ScapePicMovie.java @@ -0,0 +1,140 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.network.URL; +import java.io.IOException; +import java.util.Hashtable; + +public class ScapePicMovie implements Persister { + private static Hashtable movieDict = new Hashtable(); + private ScapePicTexture[] movie; + private String localName; + private URL url; + private int frameCount; + private int width; + private int height; + private static Object classCookie = new Object(); + + static { + nativeInit(); + } + + public ScapePicMovie() { + } + + public ScapePicMovie(String localName, URL url) { + this.localName = localName; + this.url = url; + this.movie = this.getAll(); + } + + public static native void nativeInit(); + + public int getW() { + return this.width; + } + + public int getH() { + return this.height; + } + + public int length() { + return this.frameCount; + } + + public URL getURL() { + return this.url; + } + + public ScapePicTexture getTexture(int frameNumber) { + ScapePicTexture ret = null; + if (this.movie != null) { + ret = this.movie[frameNumber]; + this.movie[frameNumber] = null; + int i = 0; + + while (i < this.frameCount && this.movie[i] == null) { + i++; + } + + if (i == this.frameCount) { + this.movie = null; + } + } + + return ret; + } + + public ScapePicTexture[] getTextures() { + ScapePicTexture[] ret = this.movie; + this.movie = null; + return ret; + } + + private synchronized ScapePicTexture[] getAll() { + String name = this.url.getAbsolute(); + ScapePicMovie proto = (ScapePicMovie)movieDict.get(name); + ScapePicTexture[] a = (ScapePicTexture[])null; + if (proto != null) { + this.frameCount = proto.length(); + this.width = proto.getW(); + this.height = proto.getH(); + a = this.lookupTextures(name, this.frameCount, this.width, this.height); + } + + if (a == null) { + a = this.makeTextures(this.localName, name); + if (a != null && proto == null) { + this.frameCount = a.length; + this.width = a[0].getW(); + this.height = a[0].getH(); + movieDict.put(name, this); + } + } + + return a; + } + + private native ScapePicTexture[] lookupTextures(String var1, int var2, int var3, int var4); + + private native ScapePicTexture[] makeTextures(String var1, String var2); + + @Override + public void saveState(Saver s) throws IOException { + Console.println(Console.message("Obs-ScapePicMov") + this.url); + s.saveVersion(2, classCookie); + this.url.save(s); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + this.localName = r.restoreString(); + this.url = URL.make(this.localName); + r.restoreBoolean(); + break; + case 1: + this.localName = r.restoreString(); + this.url = URL.make(this.localName); + break; + case 2: + this.url = URL.restore(r); + this.localName = this.url.unalias(); + break; + default: + throw new TooNewException(); + } + + this.movie = this.getAll(); + } + + @Override + public void postRestore(int version) { + } + + @Override + public String toString() { + return this.url.getAbsolute(); + } +} diff --git a/NET/worlds/scape/ScapePicTexture.java b/NET/worlds/scape/ScapePicTexture.java new file mode 100644 index 0000000..b2dd1ed --- /dev/null +++ b/NET/worlds/scape/ScapePicTexture.java @@ -0,0 +1,94 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import java.io.IOException; +import java.text.MessageFormat; + +public class ScapePicTexture extends Texture implements Persister { + private int w; + private int h; + private String _urlName; + private ScapePicMovie _movie; + private int _movieFrame; + private static Object classCookie = new Object(); + + static { + nativeInit(); + } + + public ScapePicTexture(String urlName, String filename) { + this._urlName = urlName; + this.makeTexture(urlName, filename); + } + + public ScapePicTexture() { + } + + public static native void nativeInit(); + + @Override + public int getW() { + return this.w; + } + + @Override + public int getH() { + return this.h; + } + + private native void makeTexture(String var1, String var2); + + @Override + public String getName() { + return this._urlName; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + super.saveState(s); + if (this._movie != null) { + s.saveBoolean(true); + s.save(this._movie); + s.saveInt(this._movieFrame); + } else { + s.saveBoolean(false); + s.saveString(this._urlName); + } + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + r.restoreBoolean(); + break; + case 1: + super.restoreState(r); + break; + default: + throw new TooNewException(); + } + + if (r.restoreBoolean()) { + this._movie = (ScapePicMovie)r.restore(); + this._movieFrame = r.restoreInt(); + ScapePicTexture t = this._movie.getTexture(this._movieFrame); + if (t == null) { + Object[] arguments = new Object[]{new String("" + this._movieFrame), new String("" + this._movie)}; + Console.println(MessageFormat.format(Console.message("Error-frame"), arguments)); + } else { + this.textureID = t.textureID; + } + } else { + this._urlName = r.restoreString(); + this.makeTexture(this._urlName, this._urlName); + } + } + + @Override + public String toString() { + return this._movie == null ? this._urlName : this._movie.toString(); + } +} diff --git a/NET/worlds/scape/ScapePicTextureDecoder.java b/NET/worlds/scape/ScapePicTextureDecoder.java new file mode 100644 index 0000000..ca0a2d0 --- /dev/null +++ b/NET/worlds/scape/ScapePicTextureDecoder.java @@ -0,0 +1,15 @@ +package NET.worlds.scape; + +class ScapePicTextureDecoder extends TextureDecoder { + private String exts = "cmp;mov"; + + @Override + protected String getExts() { + return this.exts; + } + + @Override + protected Texture read(String urlName, String filename) { + return new ScapePicTexture(urlName, filename); + } +} diff --git a/NET/worlds/scape/ScrollingImagePanel.java b/NET/worlds/scape/ScrollingImagePanel.java new file mode 100644 index 0000000..31bb498 --- /dev/null +++ b/NET/worlds/scape/ScrollingImagePanel.java @@ -0,0 +1,398 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.DialogDisabled; +import NET.worlds.console.ExposedPanel; +import NET.worlds.console.WiderScrollbar; +import NET.worlds.network.URL; +import java.awt.BorderLayout; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Image; +import java.awt.MediaTracker; +import java.awt.Point; +import java.awt.Scrollbar; +import java.awt.Toolkit; +import java.util.Enumeration; +import java.util.Vector; + +public class ScrollingImagePanel extends ExposedPanel implements LibraryDropTarget, DialogDisabled { + private Scrollbar scrollbar = new WiderScrollbar(); + private Vector items; + private int cellWidth; + private int cellHeight; + private Font font = new Font(Console.message("ScImageFont"), 1, 12); + private FontMetrics metrics = this.getFontMetrics(this.font); + private int ascent = this.metrics.getAscent(); + private int descent = this.metrics.getDescent(); + private int textHeight = this.ascent + this.descent; + private int scrollPos = 0; + private ClickEventHandler handler; + private ScrollingListElement downClicked; + private boolean isDownClicked; + private int maxScrollPos; + private boolean useIcons = false; + private boolean isDialogDisabled; + + public ScrollingImagePanel(ClickEventHandler handler, Vector icons, boolean showIcons) { + this.handler = handler; + this.setFont(this.font); + this.setForeground(Color.black); + this.setBackground(Color.lightGray); + this.items = new Vector(); + this.setContents(icons, false); + this.setLayout(new BorderLayout()); + this.add("East", this.scrollbar); + this.useIcons = showIcons; + } + + public void resetContents(Vector icons) { + this.setContents(icons); + } + + protected void add(GridBagLayout gbag, Component comp, GridBagConstraints c) { + gbag.setConstraints(comp, c); + this.add(comp); + } + + @Override + public boolean handleEvent(java.awt.Event e) { + if (this.isDialogDisabled) { + return false; + } else { + switch (e.id) { + case 601: + return this.scrollLineUp(); + case 602: + return this.scrollLineDown(); + case 603: + return this.scrollPageUp(); + case 604: + return this.scrollPageDown(); + case 605: + return this.scrollAbsolute(); + default: + return super.handleEvent(e); + } + } + } + + @Override + public void dialogDisable(boolean disable) { + this.isDialogDisabled = disable; + } + + private void setContents(Vector icons) { + this.setContents(icons, true); + } + + private void setContents(Vector icons, boolean showIt) { + this.items.removeAllElements(); + int count = icons.size(); + + for (int i = 0; i < count; i++) { + this.addIcon((Iconic)icons.elementAt(i), false); + } + + if (showIt) { + this.recalc(this.size().width, this.size().height); + this.repaint(); + } + } + + private void addIcon(Iconic icon, boolean showIt) { + String title = icon.getIconCaption(); + int titleWidth = title != null ? this.metrics.stringWidth(title) : 0; + URL name = icon.getIconURL(); + Image image = null; + if (name != null) { + MediaTracker tracker = new MediaTracker(this); + image = Toolkit.getDefaultToolkit().getImage(name.unalias()); + tracker.addImage(image, 0); + + try { + tracker.waitForID(0); + } catch (InterruptedException var9) { + } + + if (tracker.isErrorID(0)) { + image = null; + System.out.println("Error loading " + name); + } + } + + this.items.addElement(new ScrollingListElement(image, title, titleWidth)); + } + + private void findCellSize() { + this.cellWidth = 30; + this.cellHeight = 0; + if (this.useIcons) { + this.cellHeight = 30; + } + + Enumeration e = this.items.elements(); + + while (e.hasMoreElements()) { + ScrollingListElement item = (ScrollingListElement)e.nextElement(); + this.cellWidth = Math.max(this.cellWidth, item.titleWidth); + if (this.useIcons && item.image != null) { + this.cellWidth = Math.max(this.cellWidth, item.image.getWidth(this)); + this.cellHeight = Math.max(this.cellHeight, item.image.getHeight(this)); + } + } + + this.cellWidth += 2; + this.cellHeight = this.cellHeight + this.textHeight + 2; + } + + @Override + public void reshape(int x, int y, int w, int h) { + super.reshape(x, y, w, h); + this.recalc(w, h); + this.repaint(); + } + + private void recalc(int w, int h) { + this.findCellSize(); + this.scrollPos = 0; + this.scrollbar.setValue(this.scrollPos); + int pass = 0; + + while (pass < 2) { + int scrollbarWidth = 0; + if (pass == 1) { + scrollbarWidth = this.scrollbar.size().width; + } + + int lines = 0; + if (this.cellWidth != 0) { + int imagesPerLine = Math.max(1, (w - scrollbarWidth) / this.cellWidth); + lines = (this.items.size() + imagesPerLine - 1) / imagesPerLine * this.cellHeight; + } + + if (lines > h) { + if (pass == 0) { + if (!this.scrollbar.isVisible()) { + this.scrollbar.show(); + this.validate(); + } + + pass++; + continue; + } + + this.maxScrollPos = lines; + this.scrollbar.setValues(this.scrollPos, h, 0, lines); + this.scrollbar.setPageIncrement(h); + this.scrollbar.setLineIncrement(this.cellHeight); + break; + } + + if (this.scrollbar.isVisible()) { + this.scrollbar.hide(); + this.validate(); + } + break; + } + + this.clearHitTest(); + } + + private void clearHitTest() { + int count = this.items.size(); + + for (int i = 0; i < count; i++) { + ScrollingListElement e = (ScrollingListElement)this.items.elementAt(i); + e.x = e.y = -1; + } + } + + private ScrollingListElement findCell(int x, int y) { + int count = this.items.size(); + + for (int i = 0; i < count; i++) { + ScrollingListElement e = (ScrollingListElement)this.items.elementAt(i); + if (x >= 0 && y >= 0 && x < e.x && y < e.y) { + return e; + } + } + + return null; + } + + private void buttonAction(boolean down) { + if (this.isDownClicked != down) { + this.isDownClicked = down; + Graphics g = this.getGraphics(); + this.drawCell(g, this.downClicked, this.isDownClicked); + g.dispose(); + } + } + + private Component findComponent(Point p) { + Point screenLoc = this.getLocationOnScreen(); + Container cur = null; + + for (Container tmp = this.getParent(); !(tmp instanceof Frame); tmp = tmp.getParent()) { + cur = tmp; + } + + Point parentCoords = cur.getLocationOnScreen(); + p.x = p.x + screenLoc.x - parentCoords.x; + p.y = p.y + screenLoc.y - parentCoords.y; + Component found = cur; + + while (true) { + Component c = found.locate(p.x, p.y); + if (c == found || c == null) { + return found; + } + + Point tmp = c.location(); + p.x = p.x - tmp.x; + p.y = p.y - tmp.y; + found = c; + } + } + + @Override + public boolean mouseUp(java.awt.Event event, int x, int y) { + if (this.downClicked != null) { + Point p = new Point(x, y); + this.buttonAction(false); + this.handler.clickEvent(this.findComponent(p), p, 2); + this.downClicked = null; + return true; + } else { + return false; + } + } + + public int itemAt(Point p) { + ScrollingListElement cell = this.findCell(p.x, p.y); + return cell != null ? this.items.indexOf(cell) : -1; + } + + @Override + public boolean mouseDown(java.awt.Event event, int x, int y) { + if (this.downClicked == null && (this.downClicked = this.findCell(x, y)) != null) { + this.buttonAction(true); + int flags = 1; + if (event.metaDown()) { + flags |= 4; + } + + this.handler.clickEvent(this, new Point(x, y), flags); + return true; + } else { + return false; + } + } + + @Override + public boolean mouseDrag(java.awt.Event event, int x, int y) { + if (this.downClicked != null) { + Point p = new Point(x, y); + this.handler.clickEvent(this.findComponent(p), p, 8); + return true; + } else { + return false; + } + } + + private void drawCell(Graphics g, ScrollingListElement e, boolean depressed) { + int x = e.x - this.cellWidth; + int y = e.y - this.cellHeight; + int imageBoxHeight = this.cellHeight - this.textHeight; + int yTextOffset = imageBoxHeight + this.ascent; + Color normColor = g.getColor(); + g.setColor(this.getBackground()); + g.draw3DRect(x, y, this.cellWidth - 1, this.cellHeight - 1, !depressed); + g.setColor(normColor); + if (this.useIcons && e.image != null) { + int imageWidth = e.image.getWidth(this); + int imageHeight = e.image.getHeight(this); + g.drawImage(e.image, x + (this.cellWidth - imageWidth) / 2, y + (imageBoxHeight - imageHeight) / 2, null); + } + + if (e.title != null) { + g.drawString(e.title, x + (this.cellWidth - e.titleWidth) / 2, y + yTextOffset); + } + } + + @Override + public void paint(Graphics g) { + Color normColor = g.getColor(); + super.paint(g); + g.setColor(normColor); + this.clearHitTest(); + int width = this.size().width; + int height = this.size().height; + int x = 0; + int y = -this.scrollbar.getValue(); + int count = this.items.size(); + + for (int i = 0; i < count; i++) { + if (y + this.cellHeight > 0) { + ScrollingListElement e = (ScrollingListElement)this.items.elementAt(i); + e.x = x + this.cellWidth; + e.y = y + this.cellHeight; + this.drawCell(g, e, false); + } + + x += this.cellWidth; + if (x + this.cellWidth > width) { + x = 0; + if ((y += this.cellHeight) >= height) { + break; + } + } + } + } + + public boolean isIconsVisible() { + return this.useIcons; + } + + public void setIconsVisible(boolean showIcons) { + this.useIcons = showIcons; + this.recalc(this.size().width, this.size().height); + this.repaint(); + } + + private boolean setScrollValue(int value) { + this.scrollPos = Math.max(this.scrollbar.getMinimum(), value); + this.scrollPos = Math.min(this.maxScrollPos, this.scrollPos); + this.scrollbar.setValue(this.scrollPos); + this.repaint(); + return true; + } + + private boolean scrollLineUp() { + return this.setScrollValue(this.scrollPos - this.scrollbar.getLineIncrement()); + } + + private boolean scrollLineDown() { + return this.setScrollValue(this.scrollPos + this.scrollbar.getLineIncrement()); + } + + private boolean scrollPageUp() { + return this.setScrollValue(this.scrollPos - this.scrollbar.getPageIncrement()); + } + + private boolean scrollPageDown() { + return this.setScrollValue(this.scrollPos + this.scrollbar.getPageIncrement()); + } + + private boolean scrollAbsolute() { + return this.setScrollValue(this.scrollbar.getValue()); + } +} diff --git a/NET/worlds/scape/ScrollingListElement.java b/NET/worlds/scape/ScrollingListElement.java new file mode 100644 index 0000000..318dbba --- /dev/null +++ b/NET/worlds/scape/ScrollingListElement.java @@ -0,0 +1,17 @@ +package NET.worlds.scape; + +import java.awt.Image; + +class ScrollingListElement { + Image image; + String title; + int titleWidth; + int x; + int y; + + ScrollingListElement(Image image, String title, int titleWidth) { + this.image = image; + this.title = title; + this.titleWidth = titleWidth; + } +} diff --git a/NET/worlds/scape/SelectAvatarAction.java b/NET/worlds/scape/SelectAvatarAction.java new file mode 100644 index 0000000..fef58eb --- /dev/null +++ b/NET/worlds/scape/SelectAvatarAction.java @@ -0,0 +1,152 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.OkCancelDialog; +import NET.worlds.console.PolledDialog; +import NET.worlds.core.ServerTableManager; +import NET.worlds.network.URL; +import java.io.IOException; + +public class SelectAvatarAction extends DialogAction { + URL url = null; + String description; + static String[] avatarAliases = ServerTableManager.instance().getTable("avatarAliases"); + private static Object classCookie = new Object(); + + private URL getURLVal() { + URL val = this.url; + if (val == null) { + SuperRoot o = this.getOwner(); + if (o instanceof Drone) { + val = ((Drone)o).getSourceURL(); + } else if (o instanceof PosableShape) { + val = ((Shape)o).getURL(); + } else if (o instanceof Hologram) { + val = ((Hologram)o).getMovieName(); + } + } + + return val; + } + + @Override + public void doIt() { + Console console = Console.getActive(); + URL val = this.getURLVal(); + if (console != null && val != null) { + console.setAvatar(val); + } + } + + @Override + public PolledDialog getDialog() { + URL val = this.getURLVal(); + if (!Console.getActive().getVIP() && val.getInternal().toLowerCase().endsWith(".rwg")) { + return new OkCancelDialog( + Console.getFrame(), this, Console.message("Cant-change-AV"), Console.message("OK"), null, Console.message("Only-VIPs-change"), false + ); + } else { + String desc = this.description; + if (desc == null || desc.length() == 0) { + desc = getPrettyAvatarName(val.getBase()); + } + + return new ChangeAvatarDialog(Console.getFrame(), this, desc); + } + } + + public static String getPrettyAvatarName(String name) { + int extIndex = name.indexOf(46); + if (extIndex >= 0) { + name = name.substring(0, extIndex).toLowerCase(); + } else { + name = name.toLowerCase(); + } + + for (int i = 0; i < avatarAliases.length; i += 2) { + if (avatarAliases[i].equals(name)) { + return avatarAliases[i + 1]; + } + } + + String properName = name.substring(0, 1).toUpperCase(); + if (name.length() > 1) { + properName = properName + name.substring(1); + } + + return properName; + } + + @Override + public Persister trigger(Event e, Persister seqID) { + URL val = this.getURLVal(); + return val == null ? null : super.trigger(e, seqID); + } + + @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 = URLPropertyEditor.make(new Property(this, index, "Avatar URL").allowSetNull(), "pilot;drone;rwx;rwg;mov"); + } else if (mode == 1) { + ret = this.url; + } else if (mode == 2) { + this.url = (URL)value; + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public String toString() { + return super.toString() + "[url " + (this.url == null ? "null" : this.url.getRelativeTo(this) + "]"); + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(4, classCookie); + super.saveState(s); + URL.save(s, this.url); + s.saveString(this.description); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + int ver = r.restoreVersion(classCookie); + switch (ver) { + case 0: + r.setOldFlag(); + this.dialogActionSkipRestore(r); + this.url = URL.restore(r, ".world"); + break; + case 1: + r.setOldFlag(); + this.dialogActionSkipRestore(r); + this.url = URL.restore(r, ".world"); + this.showDialog = r.restoreBoolean(); + break; + case 2: + this.dialogActionSkipRestore(r); + this.url = URL.restore(r, ".world"); + this.showDialog = r.restoreBoolean(); + this.cancelOnly = r.restoreBoolean(); + break; + case 3: + case 4: + super.restoreState(r); + this.url = URL.restore(r, ".world"); + if (ver >= 4) { + this.description = r.restoreString(); + } + break; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/SendURLAction.java b/NET/worlds/scape/SendURLAction.java new file mode 100644 index 0000000..83da5e1 --- /dev/null +++ b/NET/worlds/scape/SendURLAction.java @@ -0,0 +1,442 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.InternetExplorer; +import NET.worlds.console.Main; +import NET.worlds.console.MainCallback; +import NET.worlds.console.OkCancelDialog; +import NET.worlds.console.PolledDialog; +import NET.worlds.console.WebBrowser; +import NET.worlds.console.WebControlImp; +import NET.worlds.core.IniFile; +import NET.worlds.network.RemoteFileConst; +import NET.worlds.network.URL; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.Hashtable; + +public class SendURLAction extends DialogAction implements MainCallback, RemoteFileConst { + URL destination; + URL destinationOverride; + String worldOverride; + String description; + String postData = null; + protected boolean getUser; + InternetExplorer bogusBrowser; + private static String notAvailablePrefix = "http://www.worldsstore.com/superstore/en/product/"; + private static Hashtable notAvailable = new Hashtable(); + private String trigger; + private int tries = 0; + private Persister curSeq = null; + private static Object classCookie = new Object(); + + static { + Object o = new Object(); + notAvailable.put("pa101", o); + notAvailable.put("pa102", o); + notAvailable.put("pg102", o); + notAvailable.put("pg105", o); + notAvailable.put("ph108", o); + notAvailable.put("ph502", o); + } + + public SendURLAction() { + this("http://www.worlds.net"); + } + + public SendURLAction(URL dest) { + this.destination = dest; + this.getUser = false; + } + + public SendURLAction(String dest) { + this(dest == null ? null : URL.make(dest)); + } + + public SendURLAction(String dest, boolean get) { + this(dest == null ? null : URL.make(dest), get); + } + + public SendURLAction(URL dest, boolean get) { + this.destination = dest; + this.getUser = get; + } + + public void setDestination(URL d) { + this.destination = d; + } + + public void setTrigger(String t) { + this.trigger = t; + } + + public void startBrowser() { + if (Main.isMainThread()) { + this.tryLaunch(); + } else { + Main.register(this); + } + } + + @Override + public void mainCallback() { + Main.unregister(this); + this.tryLaunch(); + } + + private URL getDestination() { + if (this.worldOverride != null) { + IniFile ini = new IniFile("InstalledWorlds"); + String first = ini.getIniString("InstalledWorld0", ""); + if (this.worldOverride.equalsIgnoreCase(first)) { + return this.destinationOverride; + } + } + + return this.destination; + } + + private void tryLaunch() { + URL destURL = this.getDestination(); + if (destURL != null) { + String dest = destURL.unalias(); + String newDest = WebControlImp.processURL(dest); + if (newDest != null) { + dest = newDest; + } + + if (this.postData != null) { + this.postData = WebControlImp.processURL(this.postData); + } + + String info = null; + Console console = Console.getActive(); + if (console != null && console.getGalaxy().getChatname() != null && !console.getGalaxy().getChatname().equals("")) { + info = "Username=" + console.getGalaxy().getUsernameU(); + } + + if (this.getUser && info != null) { + dest = dest + "?" + info; + } + + String midDest = dest.substring(dest.indexOf(":") + 1); + if (dest.startsWith("sound:")) { + dest = URL.make(midDest).unalias(); + WavSoundPlayer.pauseSystem(); + CDAudio.get().setEnabled(false); + + try { + WebBrowser.forceMinimized(true); + WebBrowser.reuseOrMake(dest, this.postData, WebBrowser.getAdPartPlacement(), "sound:"); + WebBrowser.forceMinimized(false); + return; + } catch (IOException var14) { + } + } else if (dest.startsWith("videoMap:") || dest.startsWith("overmap:")) { + dest = URL.make(midDest).unalias(); + WavSoundPlayer.pauseSystem(); + CDAudio.get().setEnabled(false); + + try { + WebBrowser.dontUseToolbar(); + WebBrowser.dontUseWindowFrame(); + WebBrowser.reuseOrMake(dest, this.postData, WebBrowser.getMapPartPlacement(), "videoMap:"); + WebBrowser.useToolbar(); + return; + } catch (IOException var15) { + } + } else if (dest.startsWith("videoAd:")) { + dest = URL.make(midDest).unalias(); + WavSoundPlayer.pauseSystem(); + CDAudio.get().setEnabled(false); + + try { + WebBrowser.dontUseToolbar(); + WebBrowser.dontUseWindowFrame(); + WebBrowser.reuseOrMake(dest, this.postData, WebBrowser.getAdPartPlacement(), "videoAd:"); + WebBrowser.useToolbar(); + return; + } catch (IOException var13) { + } + } else if (dest.startsWith("zoom:")) { + dest = URL.make(midDest).unalias(); + WavSoundPlayer.pauseSystem(); + CDAudio.get().setEnabled(false); + + try { + WebBrowser.dontUseToolbar(); + WebBrowser.dontUseWindowFrame(); + WebBrowser.reuseOrMake(dest, this.postData, WebBrowser.getRenderPartPlacement(), "zoom:"); + WebBrowser.useToolbar(); + return; + } catch (IOException var12) { + } + } else if (dest.startsWith("zoomLeft:")) { + dest = URL.make(midDest).unalias(); + WavSoundPlayer.pauseSystem(); + CDAudio.get().setEnabled(false); + + try { + WebBrowser.dontUseToolbar(); + WebBrowser.dontUseWindowFrame(); + WebBrowser.reuseOrMake(dest, this.postData, WebBrowser.getLeftRenderPartPlacement(), "zoomLeft:"); + WebBrowser.useToolbar(); + return; + } catch (IOException var11) { + } + } else if (dest.startsWith("outside:")) { + dest = URL.make(midDest).unalias(); + WavSoundPlayer.pauseSystem(); + CDAudio.get().setEnabled(false); + + try { + WebBrowser.dontUseToolbar(); + WebBrowser.reuseOrMake(dest, this.postData, WebBrowser.getOutsidePlacement(), "outside:"); + WebBrowser.useToolbar(); + return; + } catch (IOException var10) { + } + } else if (dest.startsWith("http:")) { + try { + WebBrowser.reuseOrMake(dest, this.postData); + return; + } catch (IOException var9) { + } + } + + if (this.bogusBrowser == null) { + try { + this.bogusBrowser = new InternetExplorer(null); + } catch (IOException var8) { + } + } + + if (!launchViaRegistry(dest)) { + Console.println(dest + Console.message("Unable-to-launch")); + } + } + } + + @Override + public void doIt() { + this.startBrowser(); + } + + @Override + public PolledDialog getDialog() { + URL tmpURL = this.getDestination(); + if (tmpURL == null) { + return new ItemNotAvailableDialog(Console.getFrame(), this); + } else { + String tmp = tmpURL.unalias().toLowerCase(); + if (tmp.startsWith(notAvailablePrefix) && notAvailable.containsKey(tmp.substring(notAvailablePrefix.length()))) { + return new ItemNotAvailableDialog(Console.getFrame(), this); + } else { + return (PolledDialog)(this.description != null && !this.description.equals("Would you like more information?") + ? new OkCancelDialog( + Console.getFrame(), this, Console.message("BrowseQ"), Console.message("Cancel"), Console.message("OK"), this.description, false, 1 + ) + : new MoreInfoDialog(Console.getFrame(), this)); + } + } + } + + private static native boolean launchViaRegistry(String var0); + + @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 = URLPropertyEditor.make(new Property(this, index, "Destination").allowSetNull(), null); + } else if (mode == 1) { + ret = this.destination; + } else if (mode == 2) { + this.destination = (URL)value; + } + break; + case 1: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Description")); + } else if (mode == 1) { + ret = this.description; + } else if (mode == 2) { + this.description = ((String)value).trim(); + } + break; + case 2: + if (mode == 0) { + ret = URLPropertyEditor.make(new Property(this, index, "Destination Override").allowSetNull(), null); + } else if (mode == 1) { + ret = this.destinationOverride; + } else if (mode == 2) { + this.destinationOverride = (URL)value; + } + break; + case 3: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Override World").allowSetNull()); + } else if (mode == 1) { + ret = this.worldOverride; + } else if (mode == 2) { + if (value == null) { + this.worldOverride = null; + } else { + this.worldOverride = ((String)value).trim(); + if (this.worldOverride.length() == 0) { + this.worldOverride = null; + } + } + } + break; + case 4: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Send User Info (auto-login)"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.getUser); + } else if (mode == 2) { + if ((Boolean)value) { + this.getUser = true; + } else { + this.getUser = false; + } + } + break; + case 5: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "POST data")); + } else if (mode == 1) { + ret = this.postData; + } else if (mode == 2) { + this.postData = ((String)value).trim(); + } + break; + default: + ret = super.properties(index, offset + 6, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(9, classCookie); + super.saveState(s); + s.saveString(this.description); + URL.save(s, this.destination); + URL.save(s, this.destinationOverride); + s.saveString(this.worldOverride); + s.saveBoolean(this.getUser); + s.saveString(this.postData); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + String destStr = null; + switch (r.restoreVersion(classCookie)) { + case 1: + r.setOldFlag(); + r.restoreBoolean(); + destStr = r.restoreString(); + r.restoreString(); + break; + case 2: + r.setOldFlag(); + r.restoreBoolean(); + destStr = r.restoreString(); + break; + case 3: + this.dialogActionSkipRestore(r); + r.restoreBoolean(); + destStr = r.restoreString(); + break; + case 4: + this.dialogActionSkipRestore(r); + destStr = r.restoreString(); + break; + case 5: + this.dialogActionSkipRestore(r); + destStr = r.restoreString(); + this.getUser = r.restoreBoolean(); + r.restoreBoolean(); + break; + case 6: + super.restoreState(r); + this.description = r.restoreString(); + destStr = r.restoreString(); + this.getUser = r.restoreBoolean(); + r.restoreBoolean(); + break; + case 7: + super.restoreState(r); + this.description = r.restoreString(); + destStr = r.restoreString(); + String destOverrideStr = r.restoreString(); + if (destOverrideStr != null) { + this.destinationOverride = URL.make(destOverrideStr); + } + + this.worldOverride = r.restoreString(); + this.getUser = r.restoreBoolean(); + r.restoreBoolean(); + break; + case 8: + super.restoreState(r); + this.description = r.restoreString(); + this.destination = URL.restore(r, null); + this.destinationOverride = URL.restore(r, null); + this.worldOverride = r.restoreString(); + this.getUser = r.restoreBoolean(); + r.restoreBoolean(); + break; + case 9: + super.restoreState(r); + this.description = r.restoreString(); + this.destination = URL.restore(r, null); + this.destinationOverride = URL.restore(r, null); + this.worldOverride = r.restoreString(); + this.getUser = r.restoreBoolean(); + this.postData = r.restoreString(); + break; + default: + throw new TooNewException(); + } + + if (destStr != null) { + this.destination = URL.make(destStr); + } + } + + @Override + public void postRestore(int version) { + super.postRestore(version); + if (this.trigger != null) { + SuperRoot owner = this.getOwner(); + + while (owner != null && !(owner instanceof WObject)) { + owner = owner.getOwner(); + } + + if (owner == null) { + Object[] arguments = new Object[]{new String(this.getName())}; + Console.println(MessageFormat.format(Console.message("Cannot-sensor"), arguments)); + } else if (this.trigger.equals("click")) { + ((WObject)owner).addHandler(new ClickSensor(this)); + } else if (this.trigger.equals("bump")) { + ((WObject)owner).addHandler(new BumpSensor(this)); + } else { + Room r = ((WObject)owner).getRoom(); + if (r != null) { + Object[] arguments = new Object[]{new String(this.trigger), new String(this.getName()), new String(r.getName())}; + Console.println(MessageFormat.format(Console.message("Trigger-value-in"), arguments)); + } else { + Object[] arguments = new Object[]{new String(this.trigger), new String(this.getName())}; + Console.println(MessageFormat.format(Console.message("Trigger-value"), arguments)); + } + } + + this.trigger = null; + } + } +} diff --git a/NET/worlds/scape/Sensor.java b/NET/worlds/scape/Sensor.java new file mode 100644 index 0000000..8fb989d --- /dev/null +++ b/NET/worlds/scape/Sensor.java @@ -0,0 +1,99 @@ +package NET.worlds.scape; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.Vector; + +public class Sensor extends SuperRoot { + protected Vector<Action> actions = new Vector<Action>(); + private static Object classCookie = new Object(); + + public void addAction(Action o) { + this.actions.addElement(o); + } + + public void deleteAction(Action o) { + this.actions.removeElement(o); + } + + public void deleteActions() { + while (this.actions.size() > 0) { + this.deleteAction(this.actions.elementAt(0)); + } + } + + public Enumeration<Action> getActions() { + return this.actions.elements(); + } + + public int countActions() { + return this.actions.size(); + } + + public void trigger(Event event) { + RunningActionHandler.trigger(this.actions, this.getWorld(), event); + } + + @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 = ObjectPropertyAdder.make(new VectorProperty(this, index, "Targets"), this.getRoot(), "NET.worlds.scape.Action"); + } else if (mode == 1) { + ret = this.actions.clone(); + } else if (mode == 4) { + this.deleteAction((Action)value); + } else if (mode == 3) { + this.addAction((Action)value); + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(2, classCookie); + super.saveState(s); + s.saveVector(this.actions); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + this.restoreStateVers(r); + } + + protected int restoreStateVers(Restorer r) throws IOException, TooNewException { + int vers = r.restoreVersion(classCookie); + switch (vers) { + case 1: + case 2: + super.restoreState(r); + case 0: + this.actions = r.restoreVectorActions(); + return vers; + default: + throw new TooNewException(); + } + } + + @Override + public void postRestore(int version) { + super.postRestore(version); + Enumeration<Action> en = this.getActions(); + + while (en.hasMoreElements()) { + Action a = en.nextElement(); + if (this.getOwner() != null && a.getOwner() == null) { + System.out.println("Reparenting orphan action " + a.getName()); + WObject w = (WObject)this.getOwner(); + w.addAction(a); + } + } + } +} diff --git a/NET/worlds/scape/SensorFrameHandler.java b/NET/worlds/scape/SensorFrameHandler.java new file mode 100644 index 0000000..fc3a4df --- /dev/null +++ b/NET/worlds/scape/SensorFrameHandler.java @@ -0,0 +1,17 @@ +package NET.worlds.scape; + +import java.io.IOException; + +class SensorFrameHandler extends SuperRoot { + @Override + public void saveState(Saver s) throws IOException { + assert false; + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + RunningActionHandler a = new RunningActionHandler(); + r.replace(this, a); + a.restoreState(r); + } +} diff --git a/NET/worlds/scape/SeqFile.java b/NET/worlds/scape/SeqFile.java new file mode 100644 index 0000000..2d20bc9 --- /dev/null +++ b/NET/worlds/scape/SeqFile.java @@ -0,0 +1,29 @@ +package NET.worlds.scape; + +import NET.worlds.network.URL; + +public class SeqFile implements BGLoaded { + private int nativeNotifyObject; + + public SeqFile(int obj, URL path) { + this.nativeNotifyObject = obj; + BackgroundLoader.get(this, path); + } + + @Override + public Object asyncBackgroundLoad(String localName, URL remoteURL) { + PendingCacheDrone.notifySeqLoaded(this.nativeNotifyObject, localName); + return localName; + } + + @Override + public boolean syncBackgroundLoad(Object obj, URL remoteURL) { + return false; + } + + @Override + public Room getBackgroundLoadRoom() { + Pilot p = Pilot.getActive(); + return p != null ? p.getRoom() : null; + } +} diff --git a/NET/worlds/scape/SequenceAction.java b/NET/worlds/scape/SequenceAction.java new file mode 100644 index 0000000..e206861 --- /dev/null +++ b/NET/worlds/scape/SequenceAction.java @@ -0,0 +1,135 @@ +package NET.worlds.scape; + +import java.io.IOException; +import java.util.Enumeration; +import java.util.Vector; + +public class SequenceAction extends Action { + protected int loopCount = 1; + protected boolean loopInfinite = false; + Vector actions = new Vector(); + SequenceActionState currentSeq; + private static Object classCookie = new Object(); + + @Override + public Persister trigger(Event evt, Persister seqID) { + if (seqID != this.currentSeq) { + return null; + } else { + if (seqID == null) { + this.currentSeq = new SequenceActionState(this); + } + + if (!this.currentSeq.run(evt)) { + this.currentSeq = null; + } + + return this.currentSeq; + } + } + + public void addComponent(Action act) { + this.actions.addElement(act); + } + + public void insertComponent(Action act, int index) { + this.actions.insertElementAt(act, index); + } + + public boolean removeComponent(Action act) { + return this.actions.removeElement(act); + } + + public Enumeration getComponents() { + return this.actions.elements(); + } + + public int getLoopCount() { + return this.loopCount; + } + + public void setLoopCount(int c) { + this.loopCount = c; + } + + @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) { + VectorProperty vp = new VectorProperty(this, index, "Components"); + vp.allowSorting(false); + ret = ObjectPropertyAdder.make(vp, this.getRoot(), "NET.worlds.scape.Action"); + } else if (mode == 1) { + ret = this.actions.clone(); + } else if (mode == 4) { + this.actions.removeElement(value); + } else if (mode == 3) { + this.actions.addElement((Action)value); + } + break; + case 1: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Loop Count")); + } else if (mode == 1) { + ret = new Integer(this.loopCount); + } else if (mode == 2) { + this.loopCount = (Integer)value; + } + break; + case 2: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Loop Infinite"), "False", "True"); + } else if (mode == 1) { + ret = new Boolean(this.loopInfinite); + } else if (mode == 2) { + this.loopInfinite = (Boolean)value; + } + break; + default: + ret = super.properties(index, offset + 3, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(2, classCookie); + super.saveState(s); + s.saveBoolean(this.loopInfinite); + s.saveVector(this.actions); + s.saveInt(this.loopCount); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + r.setOldFlag(); + super.restoreState(r); + this.actions = r.restoreVector(); + this.loopCount = r.restoreInt(); + this.loopInfinite = this.loopCount < 0; + this.loopCount = Math.abs(this.loopCount); + r.restoreBoolean(); + break; + case 1: + super.restoreState(r); + this.actions = r.restoreVector(); + this.loopCount = r.restoreInt(); + this.loopInfinite = this.loopCount < 0; + this.loopCount = Math.abs(this.loopCount); + break; + case 2: + super.restoreState(r); + this.loopInfinite = r.restoreBoolean(); + this.actions = r.restoreVector(); + this.loopCount = r.restoreInt(); + break; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/SequenceActionState.java b/NET/worlds/scape/SequenceActionState.java new file mode 100644 index 0000000..b7e17ed --- /dev/null +++ b/NET/worlds/scape/SequenceActionState.java @@ -0,0 +1,91 @@ +package NET.worlds.scape; + +import java.io.IOException; +import java.util.Vector; + +class SequenceActionState implements Persister { + int currentLoop; + boolean loopInfinite; + Vector actions; + Persister seqID; + int currentAct; + private static Object classCookie = new Object(); + + SequenceActionState() { + } + + SequenceActionState(SequenceAction sa) { + this.currentLoop = sa.loopCount; + this.loopInfinite = sa.loopInfinite; + this.actions = (Vector)sa.actions.clone(); + } + + boolean run(Event evt) { + if (this.currentLoop <= 0 && !this.loopInfinite) { + return false; + } else { + while (this.currentAct < this.actions.size()) { + Action act = (Action)this.actions.elementAt(this.currentAct); + if ((this.seqID = act.trigger(evt, this.seqID)) != null) { + return true; + } + + this.currentAct++; + } + + this.currentAct = 0; + if (this.currentLoop > 0) { + this.currentLoop--; + } + + return true; + } + } + + @Override + public String toString() { + String stateString = "Action #" + this.currentAct + " of loop " + this.currentLoop + ", status " + this.seqID; + if (!this.loopInfinite) { + stateString = stateString + " NOT"; + } + + return stateString + " Infinite"; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + s.saveBoolean(this.loopInfinite); + s.saveInt(this.currentLoop); + s.saveInt(this.currentAct); + s.saveVector(this.actions); + s.saveMaybeNull(this.seqID); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + this.currentLoop = r.restoreInt(); + this.loopInfinite = this.currentLoop < 0; + this.currentLoop = Math.abs(this.currentLoop); + this.currentAct = r.restoreInt(); + this.actions = r.restoreVector(); + this.seqID = r.restoreMaybeNull(); + break; + case 1: + this.loopInfinite = r.restoreBoolean(); + this.currentLoop = r.restoreInt(); + this.currentAct = r.restoreInt(); + this.actions = r.restoreVector(); + this.seqID = r.restoreMaybeNull(); + break; + default: + throw new TooNewException(); + } + } + + @Override + public void postRestore(int version) { + } +} diff --git a/NET/worlds/scape/SetBooleanAction.java b/NET/worlds/scape/SetBooleanAction.java new file mode 100644 index 0000000..942553c --- /dev/null +++ b/NET/worlds/scape/SetBooleanAction.java @@ -0,0 +1,57 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class SetBooleanAction extends SetPropertyAction { + private boolean _value; + private static Object classCookie = new Object(); + + @Override + public Persister trigger(Event e, Persister seqID) { + if (this.useParam()) { + this._value = Boolean.valueOf(this.param()); + } + + this.set(new Boolean(this._value)); + return null; + } + + @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 = BooleanPropertyEditor.make(new Property(this, index, "Set To"), "False", "True"); + } else if (mode == 1) { + ret = new Boolean(this._value); + } else if (mode == 2) { + this._value = (Boolean)value; + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + super.saveState(s); + s.saveBoolean(this._value); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 1: + super.restoreState(r); + this._value = r.restoreBoolean(); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/SetColorAction.java b/NET/worlds/scape/SetColorAction.java new file mode 100644 index 0000000..655ce33 --- /dev/null +++ b/NET/worlds/scape/SetColorAction.java @@ -0,0 +1,108 @@ +package NET.worlds.scape; + +import java.awt.Color; +import java.io.IOException; + +public class SetColorAction extends SlidePropertyAction { + private Color _value = null; + private Color _start; + private static Object classCookie = new Object(); + + @Override + public Persister trigger(Event e, Persister seqID) { + Persister ret = null; + Color val = null; + if (this.useParam()) { + try { + this._value = new Color(Integer.valueOf(this.param())); + } catch (NumberFormatException var9) { + System.out.println(this.getName() + " unable to parse " + this.paramName()); + this._value = null; + } + } + + if (this._value == null) { + assert !this.slide(); + } else { + if (this.slide()) { + if (seqID == null) { + this.start(); + this._start = (Color)this.get(); + } + + float frac = this.fraction(); + if (frac < 1.0) { + int red = (int)((this._value.getRed() - this._start.getRed()) * frac) + this._start.getRed(); + int grn = (int)((this._value.getGreen() - this._start.getGreen()) * frac) + this._start.getGreen(); + int blu = (int)((this._value.getBlue() - this._start.getBlue()) * frac) + this._start.getBlue(); + val = new Color(red, grn, blu); + ret = this; + } + } + + if (val == null) { + val = this._value; + } + } + + this.set(val); + return ret; + } + + @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 = ColorPropertyEditor.make(new Property(this, index, "Set To").allowSetNull()); + if (this._value == null) { + ret = MaybeNullPropertyEditor.make((Property)ret, Color.black); + } + } else if (mode == 1) { + ret = this._value; + } else if (mode == 2) { + this._value = (Color)value; + } else if (mode == 4) { + this._value = null; + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + super.saveState(s); + if (this._value == null) { + s.saveBoolean(false); + } else { + s.saveBoolean(true); + s.saveInt(this._value.getRed()); + s.saveInt(this._value.getGreen()); + s.saveInt(this._value.getBlue()); + } + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 1: + super.restoreState(r); + if (r.restoreBoolean()) { + int red = r.restoreInt(); + int grn = r.restoreInt(); + int blu = r.restoreInt(); + this._value = new Color(red, grn, blu); + } + + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/SetFloatAction.java b/NET/worlds/scape/SetFloatAction.java new file mode 100644 index 0000000..9c4b354 --- /dev/null +++ b/NET/worlds/scape/SetFloatAction.java @@ -0,0 +1,82 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class SetFloatAction extends SlidePropertyAction { + private float _value; + private float _start; + private static Object classCookie = new Object(); + + @Override + public Persister trigger(Event e, Persister seqID) { + Persister ret = null; + if (this.useParam()) { + try { + this._value = Float.valueOf(this.param()); + } catch (NumberFormatException var6) { + System.out.println(this.getName() + " unable to parse " + this.paramName()); + this._value = 0.0F; + } + } + + float val = this._value; + if (this.slide()) { + if (seqID == null) { + this.start(); + this._start = (Float)this.get(); + } + + float frac = this.fraction(); + if (frac < 1.0) { + val = (this._value - this._start) * frac + this._start; + ret = this; + } + } + + this.set(new Float(val)); + return ret; + } + + @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 = FloatPropertyEditor.make(new Property(this, index, "Set To")); + } else if (mode == 1) { + ret = new Float(this._value); + } else if (mode == 2) { + this._value = (Float)value; + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(2, classCookie); + super.saveState(s); + s.saveFloat(this._value); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 1: + this.setPropertyActionRestoreState(r); + this._value = r.restoreFloat(); + break; + case 2: + super.restoreState(r); + this._value = r.restoreFloat(); + break; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/SetIntegerAction.java b/NET/worlds/scape/SetIntegerAction.java new file mode 100644 index 0000000..888411a --- /dev/null +++ b/NET/worlds/scape/SetIntegerAction.java @@ -0,0 +1,82 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class SetIntegerAction extends SlidePropertyAction { + private int _value; + private int _start; + private static Object classCookie = new Object(); + + @Override + public Persister trigger(Event e, Persister seqID) { + Persister ret = null; + if (this.useParam()) { + try { + this._value = Integer.valueOf(this.param()); + } catch (NumberFormatException var6) { + System.out.println(this.getName() + " unable to parse " + this.paramName()); + this._value = 0; + } + } + + int val = this._value; + if (this.slide()) { + if (seqID == null) { + this.start(); + this._start = (Integer)this.get(); + } + + float frac = this.fraction(); + if (frac < 1.0) { + val = (int)((this._value - this._start) * frac + this._start); + ret = this; + } + } + + this.set(new Integer(val)); + return ret; + } + + @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 = IntegerPropertyEditor.make(new Property(this, index, "Set To")); + } else if (mode == 1) { + ret = new Integer(this._value); + } else if (mode == 2) { + this._value = (Integer)value; + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(2, classCookie); + super.saveState(s); + s.saveInt(this._value); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 1: + this.setPropertyActionRestoreState(r); + this._value = r.restoreInt(); + break; + case 2: + super.restoreState(r); + this._value = r.restoreInt(); + break; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/SetPoint2Action.java b/NET/worlds/scape/SetPoint2Action.java new file mode 100644 index 0000000..0063719 --- /dev/null +++ b/NET/worlds/scape/SetPoint2Action.java @@ -0,0 +1,115 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class SetPoint2Action extends SlidePropertyAction { + private Point2 _value = null; + private Point2 _start; + private static Object classCookie = new Object(); + + @Override + public Persister trigger(Event e, Persister seqID) { + Persister ret = null; + Point2 val = null; + if (this.useParam()) { + String p = this.param(); + if (p == null) { + this._value = null; + } else { + float x = 0.0F; + float y = 0.0F; + boolean ok = true; + int comma = p.indexOf(44); + if (comma == -1) { + ok = false; + } else { + try { + x = Float.valueOf(p.substring(0, comma)); + p = p.substring(comma + 1); + y = Float.valueOf(p); + } catch (NumberFormatException var11) { + ok = false; + } + } + + if (!ok) { + x = 0.0F; + y = 0.0F; + System.out.println(this.getName() + " unable to parse " + this.paramName()); + } + + this._value = new Point2(x, y); + } + } + + if (this._value == null) { + assert !this.slide(); + } else { + if (this.slide()) { + if (seqID == null) { + this.start(); + this._start = (Point2)this.get(); + } + + float frac = this.fraction(); + if (frac < 1.0 && this._start != null) { + val = new Point2(this._value); + val.x = (this._value.x - this._start.x) * frac + this._start.x; + val.y = (this._value.y - this._start.y) * frac + this._start.y; + ret = this; + } + } + + if (val == null) { + val = this._value; + } + } + + this.set(val); + return ret; + } + + @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 = Point2PropertyEditor.make(new Property(this, index, "Set To").allowSetNull()); + if (this._value == null) { + ret = MaybeNullPropertyEditor.make((Property)ret, new Point2()); + } + } else if (mode == 1) { + ret = this._value; + } else if (mode == 2) { + this._value = (Point2)value; + } else if (mode == 4) { + this._value = null; + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + super.saveState(s); + s.saveMaybeNull(this._value); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 1: + super.restoreState(r); + this._value = (Point2)r.restoreMaybeNull(); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/SetPoint3Action.java b/NET/worlds/scape/SetPoint3Action.java new file mode 100644 index 0000000..e41c624 --- /dev/null +++ b/NET/worlds/scape/SetPoint3Action.java @@ -0,0 +1,125 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class SetPoint3Action extends SlidePropertyAction { + private Point3 _value = null; + private Point3 _start; + private static Object classCookie = new Object(); + + @Override + public Persister trigger(Event e, Persister seqID) { + Persister ret = null; + Point3 val = null; + if (this.useParam()) { + String p = this.param(); + if (p == null) { + this._value = null; + } else { + float x = 0.0F; + float y = 0.0F; + float z = 0.0F; + boolean ok = true; + int comma = p.indexOf(44); + if (comma == -1) { + ok = false; + } else { + try { + x = Float.valueOf(p.substring(0, comma)); + p = p.substring(comma + 1); + comma = p.indexOf(44); + if (comma == -1) { + ok = false; + } else { + y = Float.valueOf(p.substring(0, comma)); + p = p.substring(comma + 1); + z = Float.valueOf(p); + } + } catch (NumberFormatException var12) { + ok = false; + } + } + + if (!ok) { + System.out.println(this.getName() + " unable to parse " + this.paramName()); + x = 0.0F; + y = 0.0F; + z = 0.0F; + } + + this._value = new Point3(x, y, z); + } + } + + if (this._value == null) { + assert !this.slide(); + } else { + if (this.slide()) { + if (seqID == null) { + this.start(); + this._start = (Point3)this.get(); + } + + float frac = this.fraction(); + if (frac < 1.0) { + val = new Point3(this._value); + val.x = (this._value.x - this._start.x) * frac + this._start.x; + val.y = (this._value.y - this._start.y) * frac + this._start.y; + val.z = (this._value.z - this._start.z) * frac + this._start.z; + ret = this; + } + } + + if (val == null) { + val = this._value; + } + } + + this.set(val); + return ret; + } + + @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, "Set To").allowSetNull()); + if (this._value == null) { + ret = MaybeNullPropertyEditor.make((Property)ret, new Point3()); + } + } else if (mode == 1) { + ret = this._value; + } else if (mode == 2) { + this._value = (Point3)value; + } else if (mode == 4) { + this._value = null; + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + super.saveState(s); + s.saveMaybeNull(this._value); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 1: + super.restoreState(r); + this._value = (Point3)r.restoreMaybeNull(); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/SetPropertyAction.java b/NET/worlds/scape/SetPropertyAction.java new file mode 100644 index 0000000..1bb2f45 --- /dev/null +++ b/NET/worlds/scape/SetPropertyAction.java @@ -0,0 +1,270 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.Gamma; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.Enumeration; + +public abstract class SetPropertyAction extends Action { + SuperRoot _target; + String _targetName; + String _roomName; + String _propName; + private int _propIndex = -1; + private String _paramName = null; + private static Object classCookie = new Object(); + + public SuperRoot getTarget() { + if (this._target == null && this._targetName != null) { + Room r = null; + if (this._roomName != null) { + World w = this.getWorld(); + if (w != null) { + r = w.getRoom(this._roomName); + } + } else { + r = this.getRoom(); + } + + if (r != null) { + Enumeration list = r.getDeepOwned(); + this._target = SuperRoot.nameSearch(list, this._targetName); + } + } + + return this._target != null ? this._target : this.getOwner(); + } + + protected boolean useParam() { + return this._paramName != null; + } + + protected String paramName() { + return this._paramName; + } + + protected String param() { + return this._paramName == null ? null : Gamma.getParam(this._paramName); + } + + static int index(int index, String name, Object target) { + if (index == -1 && name != null) { + Enumeration pe = new EnumProperties(target); + + while (pe.hasMoreElements()) { + Property prop = (Property)pe.nextElement(); + if (prop.getName().equals(name)) { + index = prop.getIndex(); + break; + } + } + } + + return index; + } + + public static Object propHelper(int mode, Object value, String name, SuperRoot target) { + Object ret = null; + int i = index(-1, name, target); + if (i != -1) { + try { + ret = target.properties(i, 0, mode, value); + } catch (NoSuchPropertyException var7) { + } + } + + return ret; + } + + private Object propHelper(int mode, Object value) { + SuperRoot target = this.getTarget(); + Object ret = null; + if ((this._propIndex = index(this._propIndex, this._propName, target)) != -1) { + try { + ret = target.properties(this._propIndex, 0, mode, value); + } catch (NoSuchPropertyException var6) { + assert false; + } + } else if (target == null) { + Console.println(this.getName() + Console.message("null-target")); + } else if (this._propName == null) { + Object[] arguments = new Object[]{new String(this.getName()), new String(this.getTarget().getName())}; + Console.println(MessageFormat.format(Console.message("null-property"), arguments)); + } else { + Object[] arguments = new Object[]{new String(this.getName()), new String(this._propName), new String(this.getTarget().getName())}; + Console.println(MessageFormat.format(Console.message("non-property"), arguments)); + } + + return ret; + } + + protected final void set(Object value) { + this.propHelper(2, value); + } + + protected final Object get() { + return this.propHelper(1, null); + } + + protected final void add(Object value) { + this.propHelper(3, value); + } + + protected final void remove(Object value) { + this.propHelper(4, value); + } + + protected final Property enumerate() { + return (Property)this.propHelper(0, null); + } + + @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) { + Property p = new Property(this, index, "Target"); + p.allowSetNull(); + ret = ObjPropertyEditor.make(p, this.getRoom(), "NET.worlds.scape.SuperRoot"); + } else if (mode == 1) { + ret = this.getTarget(); + } else if (mode == 2) { + this._target = (SuperRoot)value; + this._propIndex = -1; + } + break; + case 1: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Target Room")); + } else if (mode == 1) { + ret = this._roomName; + } else if (mode == 4) { + this._roomName = null; + } else if (mode == 2) { + this._roomName = (String)value; + this._target = null; + } + break; + case 2: + if (mode == 0) { + Property p = new Property(this, index, "Target Name"); + p.allowSetNull(); + ret = StringPropertyEditor.make(p); + } else if (mode == 1) { + ret = this._targetName; + } else if (mode == 4) { + this._targetName = null; + } else if (mode == 2) { + this._targetName = (String)value; + this._target = null; + } + break; + case 3: + if (mode == 0) { + ret = new Property(this, index, "Property Name"); + if (this.getTarget() != null) { + ret = PropPropEditor.make((Property)ret, this.getTarget(), true); + } + } else if (mode == 1) { + SuperRoot t = this.getTarget(); + if ((this._propIndex = index(this._propIndex, this._propName, t)) != -1 && t != null) { + ret = this.enumerate(); + } else { + ret = null; + } + } else if (mode == 2) { + if (value == null) { + this._propIndex = -1; + this._propName = null; + } else if (value instanceof String) { + this._propIndex = -1; + this._propName = (String)value; + } else { + this._propIndex = ((Property)value).getIndex(); + this._propName = ((Property)value).getName(); + } + } + break; + case 4: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Use parameter"), "Use 'Set To' value", "Use parameter"); + } else if (mode == 1) { + ret = new Boolean(this._paramName != null); + } else if (mode == 2) { + if ((Boolean)value) { + if (this._paramName == null) { + this._paramName = ""; + } + } else { + this._paramName = null; + } + } + break; + case 5: + if (mode == 0) { + ret = new Property(this, index, "Parameter Name"); + if (this._paramName != null) { + ret = StringPropertyEditor.make((Property)ret); + } + } else if (mode == 1) { + ret = this._paramName == null ? "" : this._paramName; + } else if (mode == 2) { + this._paramName = (String)value; + } + break; + default: + ret = super.properties(index, offset + 6, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(4, classCookie); + super.saveState(s); + s.saveMaybeNull(this.getTarget()); + s.saveString(this._roomName); + s.saveString(this._targetName); + s.saveString(this._propName); + s.saveString(this._paramName); + } + + protected void setPropertyActionRestoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 1: + super.restoreState(r); + this._target = (SuperRoot)r.restore(); + this._propName = r.restoreString(); + break; + case 2: + super.restoreState(r); + this._target = (SuperRoot)r.restoreMaybeNull(); + this._propName = r.restoreString(); + break; + case 3: + super.restoreState(r); + this._target = (SuperRoot)r.restoreMaybeNull(); + this._propName = r.restoreString(); + this._paramName = r.restoreString(); + break; + case 4: + super.restoreState(r); + this._target = (SuperRoot)r.restoreMaybeNull(); + this._roomName = r.restoreString(); + this._targetName = r.restoreString(); + this._propName = r.restoreString(); + this._paramName = r.restoreString(); + break; + default: + throw new TooNewException(); + } + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + this.setPropertyActionRestoreState(r); + } +} diff --git a/NET/worlds/scape/SetStringAction.java b/NET/worlds/scape/SetStringAction.java new file mode 100644 index 0000000..059d25e --- /dev/null +++ b/NET/worlds/scape/SetStringAction.java @@ -0,0 +1,57 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class SetStringAction extends SetPropertyAction { + private String _value; + private static Object classCookie = new Object(); + + @Override + public Persister trigger(Event e, Persister seqID) { + if (this.useParam()) { + this._value = this.param(); + } + + this.set(this._value); + return null; + } + + @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 = StringPropertyEditor.make(new Property(this, index, "Set To")); + } else if (mode == 1) { + ret = this._value; + } else if (mode == 2) { + this._value = (String)value; + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + super.saveState(s); + s.saveString(this._value); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 1: + super.restoreState(r); + this._value = r.restoreString(); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/SetURLAction.java b/NET/worlds/scape/SetURLAction.java new file mode 100644 index 0000000..6cbc8ff --- /dev/null +++ b/NET/worlds/scape/SetURLAction.java @@ -0,0 +1,68 @@ +package NET.worlds.scape; + +import NET.worlds.console.Cursor; +import NET.worlds.network.URL; +import java.io.IOException; +import java.net.MalformedURLException; + +public class SetURLAction extends SetPropertyAction { + URL _value; + private static Object classCookie = new Object(); + + @Override + public Persister trigger(Event e, Persister seqID) { + if (this.useParam()) { + try { + this._value = new URL(this.param()); + } catch (MalformedURLException var4) { + System.out.println(this.getName() + " unable to parse " + this.paramName()); + } + } + + this.set(this._value); + return null; + } + + @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 = URLPropertyEditor.make( + new Property(this, index, "Set To").allowSetNull(), + "ani;console;cur;drone;mid;mov;pilot;ra;ram;rwg;rwx;wav;wob;world;" + TextureDecoder.getAllExts(), + Cursor.getSysCursorURLs() + ); + } else if (mode == 1) { + ret = this._value; + } else if (mode == 2) { + this._value = (URL)value; + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + super.saveState(s); + URL.save(s, this._value); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 1: + super.restoreState(r); + this._value = URL.restore(r); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/SetVisibleBumpableAction.java b/NET/worlds/scape/SetVisibleBumpableAction.java new file mode 100644 index 0000000..6e05bfb --- /dev/null +++ b/NET/worlds/scape/SetVisibleBumpableAction.java @@ -0,0 +1,73 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class SetVisibleBumpableAction extends Action { + public boolean targetBumpable = true; + public boolean targetVisible = true; + private static Object classCookie = new Object(); + + @Override + public Persister trigger(Event e, Persister seqID) { + Object owner = this.getOwner(); + if (owner != null && owner instanceof WObject) { + WObject o = (WObject)owner; + o.setBumpable(this.targetBumpable); + o.setVisible(this.targetVisible); + return null; + } else { + return null; + } + } + + @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 = BooleanPropertyEditor.make(new Property(this, index, "Target Bumpable"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.targetBumpable); + } else if (mode == 2) { + this.targetBumpable = (Boolean)value; + } + break; + case 1: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Target Visible"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.targetVisible); + } else if (mode == 2) { + this.targetVisible = (Boolean)value; + } + break; + default: + ret = super.properties(index, offset + 2, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + super.saveState(s); + s.saveBoolean(this.targetBumpable); + s.saveBoolean(this.targetVisible); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 1: + super.restoreState(r); + case 0: + this.targetBumpable = r.restoreBoolean(); + this.targetVisible = r.restoreBoolean(); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/SetZoomMode.java b/NET/worlds/scape/SetZoomMode.java new file mode 100644 index 0000000..739f2ac --- /dev/null +++ b/NET/worlds/scape/SetZoomMode.java @@ -0,0 +1,61 @@ +package NET.worlds.scape; + +import NET.worlds.console.Window; +import java.io.IOException; +import java.util.Enumeration; + +public class SetZoomMode extends Action implements MomentumBehavior { + private boolean zoomMode; + private static Object classCookie = new Object(); + + public SetZoomMode(boolean on) { + this.zoomMode = on; + } + + public SetZoomMode() { + } + + @Override + public Persister trigger(Event e, Persister seqID) { + SuperRoot owner = this.getOwner(); + if (owner != null && owner instanceof Pilot && ((Pilot)owner).isActive()) { + Window w = Window.getMainWindow(); + if (w == null) { + return null; + } else { + w.setDeltaMode(this.zoomMode); + return null; + } + } else { + return null; + } + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + return; + default: + throw new TooNewException(); + } + } + + @Override + public void transferFrom(Enumeration oldMBs) { + while (oldMBs.hasMoreElements()) { + SuperRoot sr = (SuperRoot)oldMBs.nextElement(); + if (sr instanceof SetZoomMode) { + this.zoomMode = ((SetZoomMode)sr).zoomMode; + break; + } + } + } +} diff --git a/NET/worlds/scape/Shadow.java b/NET/worlds/scape/Shadow.java new file mode 100644 index 0000000..7fe9cab --- /dev/null +++ b/NET/worlds/scape/Shadow.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface Shadow { + void adjustShadow(WObject var1); +} diff --git a/NET/worlds/scape/ShallowEnumeration.java b/NET/worlds/scape/ShallowEnumeration.java new file mode 100644 index 0000000..ac8fbc3 --- /dev/null +++ b/NET/worlds/scape/ShallowEnumeration.java @@ -0,0 +1,38 @@ +package NET.worlds.scape; + +import java.util.Vector; + +public class ShallowEnumeration extends DeepEnumeration { + public ShallowEnumeration(SuperRoot o) { + this.roots.addElement(o); + o.getChildren(this); + } + + @Override + protected void getNextElement() { + this.valueRetrieved = false; + if (!this.roots.isEmpty()) { + this.nextValue = this.roots.elementAt(this.roots.size() - 1); + + assert this.nextValue != null; + + this.roots.removeElementAt(this.roots.size() - 1); + } else if (this.currentIndex >= 0) { + try { + this.nextValue = (SuperRoot)this.currentVector.elementAt(this.currentIndex--); + } catch (ArrayIndexOutOfBoundsException var2) { + this.currentIndex = this.currentVector.size() - 1; + this.getNextElement(); + } + + assert this.nextValue != null; + } else if (!this.vectors.isEmpty()) { + this.currentVector = (Vector<K>)this.vectors.elementAt(this.vectors.size() - 1); + this.currentIndex = this.currentVector.size() - 1; + this.vectors.removeElementAt(this.vectors.size() - 1); + this.getNextElement(); + } else { + this.nextValue = null; + } + } +} diff --git a/NET/worlds/scape/Shape.java b/NET/worlds/scape/Shape.java new file mode 100644 index 0000000..597b404 --- /dev/null +++ b/NET/worlds/scape/Shape.java @@ -0,0 +1,557 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.DefaultConsole; +import NET.worlds.console.Main; +import NET.worlds.console.MainCallback; +import NET.worlds.console.StatMemNode; +import NET.worlds.core.Archive; +import NET.worlds.core.IniFile; +import NET.worlds.network.URL; +import java.awt.PopupMenu; +import java.io.IOException; +import java.net.MalformedURLException; +import java.util.Enumeration; +import java.util.StringTokenizer; +import java.util.Vector; + +public class Shape extends WObject implements MainCallback, Animatable, MouseDownHandler { + static int disableLOD = IniFile.gamma().getIniInt("DisableLOD", 1); + static int forceLODLevel; + Vector<ShapeLoaderListener> listeners = null; + URL url; + boolean mustReload; + boolean recomputeLODs; + int numDetailLevels; + int currentLOD; + int lastLOD; + URL[] lodURLs; + float[] lodDistanceTriggers; + float[] lodAreas; + protected static int NORMAL; + protected static int ERROR; + protected static int LOADING; + private int pendingShape; + boolean isDefault; + static URL xShape; + URL realFile; + private boolean prepareRoom; + private Material animatableMaterial; + protected int animatableClumpID; + Vector<Texture> textures; + private static Object classCookie; + + static { + if (ProgressiveAdder.get().enabled()) { + disableLOD = 1; + } + + if (disableLOD == 1) { + System.out.println("Avatar dynamic LOD disabled."); + } else { + System.out.println("Using avatar dynamic LOD when available."); + } + + StatMemNode smn = StatMemNode.getNode(); + forceLODLevel = IniFile.gamma().getIniInt("LowResAvs", -1); + if (forceLODLevel != -1) { + System.out.println("Avatar LOD's forced to level " + forceLODLevel); + disableLOD = 0; + } + + int lowResThreshold = IniFile.gamma().getIniInt("ForceLowResRAMLimit", 33554432); + smn.updateMemoryStatus(); + if (smn._totPhysMem <= lowResThreshold && smn._totPhysMem > 0) { + System.out.println("Low memory detected, using LOD 2 for all avatars."); + forceLODLevel = 2; + disableLOD = 0; + } + + NORMAL = 0; + ERROR = -1; + LOADING = -2; + xShape = URL.make("home:avatar.rwg"); + nativeInit(); + classCookie = new Object(); + } + + public Shape() { + this.pendingShape = NORMAL; + this.isDefault = false; + this.numDetailLevels = 0; + this.recomputeLODs = true; + this.currentLOD = this.lastLOD = 0; + } + + void addLoadListener(ShapeLoaderListener l) { + if (this.listeners == null) { + this.listeners = new Vector<ShapeLoaderListener>(); + } + + if (!this.listeners.contains(l)) { + this.listeners.addElement(l); + } + } + + private void notifyLoadListeners() { + if (this.listeners != null) { + Enumeration<ShapeLoaderListener> e = this.listeners.elements(); + if (e != null) { + while (e.hasMoreElements()) { + ShapeLoaderListener l = e.nextElement(); + l.notifyShapeLoaded(this); + } + } + + this.listeners.removeAllElements(); + } + } + + void removeLoadListener(ShapeLoaderListener l) { + if (this.listeners != null) { + this.listeners.removeElement(l); + } + } + + public void setBaseLODURL(URL baseURL) { + if (disableLOD == 0 && baseURL != null && baseURL.getAbsolute().startsWith("avatar:")) { + int colon = baseURL.toString().indexOf(58); + int dot = baseURL.toString().indexOf(46); + String avName = baseURL.toString().substring(colon + 1, dot); + String avURLName = "avatar:lod/" + avName + ".lod"; + + URL lodURL; + try { + lodURL = new URL(avURLName); + } catch (MalformedURLException var16) { + return; + } + + byte[] lodFile = Archive.readTextFile(lodURL.unalias()); + if (lodFile != null) { + String lodText = new String(lodFile); + StringTokenizer tk = new StringTokenizer(lodText); + this.numDetailLevels = Integer.parseInt(tk.nextToken()); + this.lodURLs = new URL[this.numDetailLevels]; + this.lodAreas = new float[this.numDetailLevels]; + this.lodDistanceTriggers = new float[this.numDetailLevels]; + int x = 0; + this.lodURLs[x] = baseURL; + + for (this.lodAreas[x++] = 0.0F; tk.hasMoreTokens(); x++) { + String level = tk.nextToken(); + String value = tk.nextToken(); + Float f = new Float(value); + this.lodAreas[x] = f; + + try { + this.lodURLs[x] = new URL("avatar:lod/" + avName + level + baseURL.toString().substring(dot)); + } catch (MalformedURLException var15) { + System.out.println("Error creating lod URL!\n"); + this.numDetailLevels = 0; + return; + } + } + } + } + + this.recomputeLODs = true; + } + + public native float calcLODDistance(float var1); + + public synchronized boolean setLOD(float dist) { + boolean switched = false; + if (this.numDetailLevels > 0) { + if (forceLODLevel != -1) { + int realLOD = forceLODLevel > this.numDetailLevels - 1 ? this.numDetailLevels - 1 : forceLODLevel; + if (realLOD != this.lastLOD) { + this.setURL(this.lodURLs[realLOD]); + this.currentLOD = this.lastLOD = realLOD; + return true; + } + + return false; + } + + if (this.recomputeLODs) { + for (int x = 0; x < this.numDetailLevels; x++) { + this.lodDistanceTriggers[x] = this.calcLODDistance(this.lodAreas[x]); + } + + this.recomputeLODs = false; + } + + for (int lod = 0; lod < this.numDetailLevels; lod++) { + if (this.lodDistanceTriggers[lod] > dist) { + if (lod != this.lastLOD) { + this.currentLOD = lod; + if (this instanceof PosableShape) { + ((PosableShape)this).removeSubparts(); + } + + if (this.isLoaded()) { + this.releasePendingShape(); + } + + this.setURL(this.lodURLs[lod]); + } + break; + } + } + } + + if (this.lastLOD != this.currentLOD) { + switched = true; + } + + this.lastLOD = this.currentLOD; + return switched; + } + + public URL getURL() { + return this.url; + } + + synchronized boolean isLoaded() { + return this.pendingShape < -2 || this.pendingShape > 0; + } + + public boolean isFullyLoaded() { + return this.pendingShape == NORMAL && this.hasClump(); + } + + @Override + public boolean handle(MouseDownEvent e) { + SuperRoot ultimateOwner = this; + + while (ultimateOwner.getOwner() != null) { + ultimateOwner = ultimateOwner.getOwner(); + if (ultimateOwner instanceof PosableShape && ultimateOwner.getOwner() instanceof PosableDrone) { + return false; + } + } + + PopupMenu m = new PopupMenu(); + if (AnimatedActionManager.get().buildActionMenu(m, this)) { + Console c = Console.getActive(); + if (c instanceof DefaultConsole) { + DefaultConsole dc = (DefaultConsole)c; + if (dc.getRender() != null) { + dc.getRender().add(m); + m.addActionListener(AnimatedActionManager.get()); + m.show(dc.getRender(), e.x, e.y); + return true; + } + } + } + + m = WorldScriptManager.getInstance().shapeClicked(this); + if (m != null) { + Console c = Console.getActive(); + if (c instanceof DefaultConsole) { + DefaultConsole dc = (DefaultConsole)c; + if (dc.getRender() != null) { + dc.getRender().add(m); + m.addActionListener(WorldScriptManager.getInstance()); + m.show(dc.getRender(), e.x, e.y); + return true; + } + } + } + + return false; + } + + void setState(int mode, Vector<Texture> texs) { + if (this.isLoaded()) { + this.releasePendingShape(); + } + + this.releaseTextures(); + this.pendingShape = mode; + if (this.isLoaded()) { + this.shapeRedraw(); + } + + this.textures = texs; + } + + public synchronized void setURL(URL newName) { + if (newName != this.url && (newName == null || !newName.equals(this.url))) { + this.url = newName; + this.realFile = null; + boolean mrWas = this.mustReload; + this.mustReload = true; + this.setState(NORMAL, null); + this.shapeRedraw(); + this.mustReload = mrWas; + } + } + + void shapeRedraw() { + if (this.hasClump()) { + this.reclump(); + } + + this.notifyLoadListeners(); + } + + boolean isAv() { + return this.url != null && this.url.getAbsolute().startsWith("avatar:"); + } + + static String getBodBase(URL u) { + String s = u.getBase(); + int len = s.length(); + return s.endsWith(".bod") && len >= 6 ? s.substring(0, len - 6) : null; + } + + int getBodPartNum() { + String s = this.url.getInternal(); + int len = s.length(); + return s.endsWith(".bod") && len >= 6 ? (s.charAt(len - 6) - 48) * 10 + (s.charAt(len - 5) - 48) : 0; + } + + @Override + protected synchronized void addRwChildren(WObject container) { + assert !this.hasClump(); + + if (this.pendingShape == NORMAL && this.url != null) { + String urlStr; + if ((urlStr = this.url.getAbsolute()).startsWith("system:subclump")) { + SuperRoot o = this.getOwner(); + if (o instanceof Shape) { + int num = 0; + + try { + num = new Integer(urlStr.substring(15)); + } catch (NumberFormatException var6) { + } + + this.animatableClumpID = ((Shape)o).extractSubclump(num); + this.clumpID = addEmptyParentClump(this.animatableClumpID); + this.isDefault = false; + this.newRwClumpChildHelper(container); + return; + } + + this.pendingShape = ERROR; + } else { + this.setState(-2, null); + this.isDefault = false; + this.realFile = this.isAv() ? xShape : this.url; + if (this.url.endsWith(".bod")) { + String s = getBodBase(this.url); + this.realFile = URL.make(this.url, s + ".bod"); + } + + BackgroundLoader.get(new ShapeLoader(this), this.realFile); + } + } + + if (!this.isLoaded()) { + this.clumpID = makeDefaultShape(); + this.isDefault = true; + } else { + this.clumpID = this.pendingShape; + this.pendingShape = NORMAL; + this.isDefault = false; + } + + this.newRwClumpChildHelper(container); + } + + @Override + public void recursiveAddRwChildren(WObject parent) { + if (this.animatableMaterial != null && this.animatableClumpID == 0) { + this.animatableMaterial.addRwChildren(); + } + + super.recursiveAddRwChildren(parent); + if (this.animatableMaterial != null) { + this.nativeSetMaterial(this.animatableMaterial); + } + } + + public Material getMaterial() { + return this.animatableMaterial; + } + + @Override + protected void voidClump() { + if (!this.mustReload && !this.isDefault && this.pendingShape == NORMAL) { + this.pendingShape = this.extractClump(); + } else { + if (this.isLoaded()) { + this.releasePendingShape(); + } + + this.releaseTextures(); + super.voidClump(); + this.animatableClumpID = 0; + if (this.animatableMaterial != null) { + this.animatableMaterial.markVoid(); + } + } + } + + @Override + public void discard() { + if (this.isLoaded()) { + this.releasePendingShape(); + } + + this.releaseTextures(); + super.discard(); + } + + public void makeSpecials() { + if (!this.prepareRoom) { + Vector<WObject> detachList = new Vector<WObject>(); + Enumeration<Object> e = (Enumeration<Object>)this.getRoom().getContents(); + + while (e.hasMoreElements()) { + Object p = e.nextElement(); + if (p instanceof WObject) { + WObject w = (WObject)p; + if (w.getAutobuilt()) { + detachList.addElement(w); + } + } + } + + e = detachList.elements(); + + while (e.hasMoreElements()) { + ((WObject)e.nextElement()).detach(); + } + + Main.register(this); + this.prepareRoom = true; + } + } + + @Override + public void mainCallback() { + if (this.hasClump()) { + convertSpecial(this.clumpID); + this.prepareRoom = false; + Main.unregister(this); + } + } + + @Override + public void setMaterial(Material m) { + if (this.animatableMaterial != null) { + this.animatableMaterial.detach(); + } + + this.add(m); + this.animatableMaterial = m; + this.nativeSetMaterial(m); + } + + public native void nativeSetMaterial(Material var1); + + protected native int extractSubclump(int var1); + + protected static native int addEmptyParentClump(int var0); + + private static native void convertSpecial(int var0); + + public static native void nativeInit(); + + private static native int makeDefaultShape(); + + private native void releasePendingShape(); + + private void releaseTextures() { + if (this.textures != null) { + Enumeration<Texture> en = this.textures.elements(); + + while (en.hasMoreElements()) { + en.nextElement().decRef(); + } + + this.textures = null; + } + } + + @Override + protected void finalize() { + if (this.isLoaded()) { + this.releasePendingShape(); + } + + this.releaseTextures(); + super.finalize(); + } + + public void setReload(boolean mustReload) { + this.mustReload = mustReload; + } + + @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 = URLPropertyEditor.make(new Property(this, index, "File"), "rwx;rwg;bod"); + } else if (mode == 1) { + ret = this.url; + } else if (mode == 2) { + URL newName = (URL)value; + if (newName != null && newName.equals(this.url)) { + this.setURL(null); + } + + this.setURL(newName); + } + break; + case 1: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "PrepareRoom"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.prepareRoom); + } else if (mode == 2 && (Boolean)value) { + this.makeSpecials(); + } + break; + default: + ret = super.properties(index, offset + 2, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + super.saveState(s); + URL.save(s, this.url); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + case 1: + super.restoreState(r); + URL url = URL.restore(r); + if (url != null) { + this.setURL(url); + } + + return; + default: + throw new TooNewException(); + } + } + + @Override + public String toString() { + return super.toString() + "[" + this.url + "]"; + } +} diff --git a/NET/worlds/scape/ShapeLoader.java b/NET/worlds/scape/ShapeLoader.java new file mode 100644 index 0000000..abee9b8 --- /dev/null +++ b/NET/worlds/scape/ShapeLoader.java @@ -0,0 +1,113 @@ +package NET.worlds.scape; + +import NET.worlds.network.URL; +import java.util.Enumeration; +import java.util.Vector; + +public class ShapeLoader implements BGLoaded { + Shape shape; + int binaryParam; + private int numTexturesLoading; + private Vector<Texture> textures; + private boolean wasError; + + public ShapeLoader(Shape s) { + this.shape = s; + } + + @Override + public Room getBackgroundLoadRoom() { + return this.shape.getRoom(); + } + + @Override + public Object asyncBackgroundLoad(String localName, URL remoteName) { + if (localName == null) { + return null; + } else if (remoteName.endsWith(".rwg") || remoteName.endsWith(".RWG")) { + this.binaryParam = this.loadBinaryFile(localName, remoteName); + return new Object(); + } else if (remoteName.endsWith(".rwx") || remoteName.endsWith(".RWX")) { + this.loadTextFile(localName, remoteName); + return localName; + } else { + return !remoteName.endsWith(".bod") && !remoteName.endsWith(".BOD") ? null : localName; + } + } + + @Override + public boolean syncBackgroundLoad(Object o, URL remoteURL) { + if (o == null) { + return false; + } else if (this.numTexturesLoading > 0) { + return true; + } else { + if (!remoteURL.equals(this.shape.realFile)) { + this.wasError = true; + } else if (!this.shape.hasClump() && this.shape.isDefault) { + this.wasError = true; + if (!this.shape.isLoaded()) { + this.shape.setState(0, null); + } + } + + int newModel; + if (o instanceof String) { + if (!this.wasError) { + if (remoteURL.endsWith(".bod")) { + newModel = this.loadBodFile((String)o, this.shape.getBodPartNum()); + } else { + newModel = this.finishLoadingTextFile((String)o); + } + } else { + newModel = 0; + } + } else { + newModel = this.finishLoadingBinaryFile(this.binaryParam, this.wasError); + } + + if (newModel != 0) { + this.shape.setState(newModel, this.textures); + } + + if ((newModel == 0 || newModel == -1) && this.textures != null) { + Enumeration<Texture> en = this.textures.elements(); + + while (en.hasMoreElements()) { + en.nextElement().decRef(); + } + } + + this.textures = null; + return false; + } + } + + private void startTextureLoad(String relName, URL remoteName) { + this.numTexturesLoading++; + BackgroundLoader.get(new ShapeTextureLoader(this), URL.make(remoteName, relName), true); + } + + synchronized void textureLoadEnd(Texture tex) { + this.numTexturesLoading--; + if (tex != null) { + if (this.textures == null) { + this.textures = new Vector<Texture>(); + } + + this.textures.addElement(tex); + } else { + this.wasError = true; + } + } + + private native void loadTextFile(String var1, URL var2); + + private native int finishLoadingTextFile(String var1); + + private native int loadBodFile(String var1, int var2); + + private native int loadBinaryFile(String var1, URL var2); + + private native int finishLoadingBinaryFile(int var1, boolean var2); +} diff --git a/NET/worlds/scape/ShapeLoaderListener.java b/NET/worlds/scape/ShapeLoaderListener.java new file mode 100644 index 0000000..d91be55 --- /dev/null +++ b/NET/worlds/scape/ShapeLoaderListener.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface ShapeLoaderListener { + void notifyShapeLoaded(Shape var1); +} diff --git a/NET/worlds/scape/ShapeTextureLoader.java b/NET/worlds/scape/ShapeTextureLoader.java new file mode 100644 index 0000000..1ba82e3 --- /dev/null +++ b/NET/worlds/scape/ShapeTextureLoader.java @@ -0,0 +1,27 @@ +package NET.worlds.scape; + +import NET.worlds.network.URL; + +class ShapeTextureLoader implements BGLoaded { + ShapeLoader shapeLoader; + + public ShapeTextureLoader(ShapeLoader s) { + this.shapeLoader = s; + } + + @Override + public Object asyncBackgroundLoad(String localName, URL remoteName) { + this.shapeLoader.textureLoadEnd(TextureDecoder.decode(remoteName, remoteName.getBaseWithoutExt(), localName)); + return null; + } + + @Override + public boolean syncBackgroundLoad(Object obj, URL remoteURL) { + return false; + } + + @Override + public Room getBackgroundLoadRoom() { + return this.shapeLoader.getBackgroundLoadRoom(); + } +} diff --git a/NET/worlds/scape/Sharer.java b/NET/worlds/scape/Sharer.java new file mode 100644 index 0000000..aaa03eb --- /dev/null +++ b/NET/worlds/scape/Sharer.java @@ -0,0 +1,590 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.Main; +import NET.worlds.console.MainCallback; +import NET.worlds.core.Std; +import NET.worlds.network.InfiniteWaitException; +import NET.worlds.network.ObjID; +import NET.worlds.network.PacketTooLargeException; +import NET.worlds.network.PropertyList; +import NET.worlds.network.PropertySetCmd; +import NET.worlds.network.WorldServer; +import NET.worlds.network.net2Property; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.Enumeration; +import java.util.Vector; + +public class Sharer extends SuperRoot implements MainCallback { + private Vector<Attribute> attributes; + private ByteArrayOutputStream bs = new ByteArrayOutputStream(); + private boolean shared = false; + public static final int FIRST_TIME = 0; + public static final int STATIC = 2; + public static final int FORWARDED_STATIC = 3; + public static final int DYNAMIC = 4; + public static final int FORWARDED_DYNAMIC = 5; + public static final int FORWARDED = 1; + private boolean createdFromNet; + Vector<Attribute> noteQ; + Vector<Attribute> prepQ; + Vector<Attribute> sendQ; + private DynamicForwardAttribute dfa; + int lastSendTime; + private static Object classCookie = new Object(); + private Vector<Object> restoredAttributes = null; + + public Sharer() { + this.attributes = new Vector<Attribute>(256); + this.attributes.setSize(256); + } + + public boolean isShared() { + return this.shared; + } + + private int getMaybeDefaultMode() { + return ((WObject)this.getOwner()).getSharerMode(); + } + + public int getMode() { + int mode = this.getMaybeDefaultMode(); + if (mode == 0) { + this.setMode(mode); + } + + return mode; + } + + public void setMode(int mode) { + WObject w = (WObject)this.getOwner(); + if (w instanceof Room) { + mode = 2; + } else if (this.createdFromNet) { + mode = 4; + } else if (mode == 2 || mode == 4) { + mode = 0; + } + + if (mode == 0) { + mode = 3; + } + + int oldMode = this.getMaybeDefaultMode(); + if (oldMode != mode) { + this.unshare(); + w.setSharerMode(mode); + } + + this.share(); + } + + public void createDynamicForwardedFromNet(DynamicForwardAttribute dfa) { + assert !((WObject)this.getOwner()).isActive(); + + this.dfa = dfa; + ((WObject)this.getOwner()).setSharerMode(5); + } + + public void createDynamicFromNet() { + assert !((WObject)this.getOwner()).isActive() || this.createdFromNet; + + this.createdFromNet = true; + ((WObject)this.getOwner()).setSharerMode(4); + } + + public void adjustShare() { + this.share(); + } + + private void share() { + if (!this.shared) { + int mode = this.getMaybeDefaultMode(); + switch (mode) { + case 0: + this.setMode(0); + case 1: + case 2: + default: + break; + case 3: + this.flushQueue(); + Enumeration<Attribute> e = this.getAttributes(); + + while (e.hasMoreElements()) { + e.nextElement().addForwarding(); + } + break; + case 4: + assert this.createdFromNet; + break; + case 5: + if (this.dfa == null) { + this.flushQueue(); + WObject w = (WObject)this.getOwner(); + WObject terminal = w.getServed(); + if (w.getSourceURL() != null && terminal != null) { + this.dfa = new DynamicForwardAttribute(-1); + if (terminal.getSharer().addAttribute(this.dfa) == -1) { + this.dfa = null; + } else { + this.dfa.connect(w); + } + } + } + } + + this.shared = true; + } + } + + private void unshare() { + if (this.shared) { + int mode = this.getMaybeDefaultMode(); + switch (mode) { + case 2: + case 4: + default: + break; + case 3: + Enumeration<Attribute> e = this.getAttributes(); + + while (e.hasMoreElements()) { + e.nextElement().unforward(); + } + break; + case 5: + if (this.dfa != null) { + this.dfa.unconnect(); + this.dfa = null; + } + } + + this.shared = false; + } + } + + public int addAttribute(Attribute a) { + this.setMode(this.getMaybeDefaultMode()); + a._attrID = this.getFreeAttrIDFor(a, a._attrID); + if (a._attrID == -1) { + return a._attrID; + } else { + try { + this.add(a); + } catch (ClassCastException var3) { + Console.println(Console.message("Cant-attach") + var3); + a._attrID = -1; + return a._attrID; + } + + this.attributes.setElementAt(a, a._attrID); + if (this.getMaybeDefaultMode() == 3) { + a.addForwarding(); + } + + return a._attrID; + } + } + + public boolean attrIDAvailable(int id) { + return this.attributes.elementAt(id) == null; + } + + private int getFreeAttrID(int id, int low, int high) { + if (id >= 20 && id <= 255 && this.attrIDAvailable(id)) { + return id; + } else { + int freeCount = this.countFree(low, high); + if (freeCount == 0) { + return -1; + } else { + int i; + label42: + while (true) { + int pos = (int)(Math.random() * freeCount); + i = low; + + while (true) { + if (this.attributes.elementAt(i) == null) { + if (--pos < 0) { + assert i <= high; + + if (i != 150 && i != 155 && i != 160) { + break label42; + } + break; + } + } + + i++; + } + } + + return i; + } + } + } + + public int getFreeAttrIDFor(Attribute a, int id) { + return a instanceof DynamicForwardAttribute ? this.getFreeAttrID(id, 210, 249) : this.getFreeAttrID(id, 100, 249); + } + + public void removeAttribute(Attribute a) { + a.detach(); + if (a.getOwner() == null) { + this.attributes.setElementAt(null, a._attrID); + } + } + + public int resetAttributeID(Attribute a, int newID) { + newID = this.getFreeAttrIDFor(a, newID); + if (newID == -1) { + return newID; + } else { + if (this.attributes.elementAt(newID) == null) { + int oldID = a._attrID; + this.attributes.setElementAt(a, newID); + this.attributes.setElementAt(null, oldID); + a._attrID = newID; + } + + return newID; + } + } + + public void moveToSlot(WObject child, int newID) { + if (child.isDynamic()) { + Sharer s = child.getSharer(); + if (s.dfa != null) { + this.resetAttributeID(s.dfa, newID); + } + } + } + + public Enumeration<Attribute> getAttributes() { + return this.getAttributesList().elements(); + } + + public Vector<Attribute> getAttributesList() { + Vector<Attribute> v = new Vector<Attribute>(this.attributes.size()); + this.fillAttributesList(v); + return v; + } + + public void fillAttributesList(Vector<Attribute> v) { + int end = this.attributes.size(); + + for (int i = 0; i < end; i++) { + Attribute a = this.attributes.elementAt(i); + if (a != null) { + v.addElement(a); + } + } + } + + public Attribute getAttribute(int id) { + try { + return this.attributes.elementAt(id); + } catch (ArrayIndexOutOfBoundsException var3) { + return null; + } + } + + public boolean isEmpty() { + return this.countFree(0, 255) == 256; + } + + public int countFree(int low, int high) { + int count = 0; + + for (int i = low; i <= high; i++) { + if (this.attributes.elementAt(i) == null) { + count++; + } + } + + return count; + } + + @Override + public void getChildren(DeepEnumeration d) { + d.addChildVectorWithNulls(this.attributes); + } + + public void noteChange(Attribute a, boolean sendTriggers) { + assert Main.isMainThread(); + + if (this.prepQ == null) { + this.noteQ = new Vector<Attribute>(); + this.prepQ = new Vector<Attribute>(); + this.sendQ = new Vector<Attribute>(); + } + + if (sendTriggers && !this.noteQ.contains(a)) { + if (this.noteQ.isEmpty() && this.prepQ.isEmpty() && this.sendQ.isEmpty()) { + Main.register(this); + } + + this.noteQ.addElement(a); + } + + Attribute fa; + if (this.getMode() == 3 && (fa = a.getForwardAttribute()) != null) { + fa.noteChange(); + } else if (this.dfa != null) { + this.dfa.noteChange(); + } else if (!this.prepQ.contains(a)) { + if (this.noteQ.isEmpty() && this.prepQ.isEmpty() && this.sendQ.isEmpty()) { + Main.register(this); + } + + this.prepQ.addElement(a); + } + } + + private void prepQueue() { + if (!this.noteQ.isEmpty()) { + int end = this.noteQ.size(); + + for (int i = 0; i < end; i++) { + Attribute a = this.noteQ.elementAt(i); + ValueEvent e = new ValueEvent(Std.getFastTime(), this.getOwner(), (WObject)this.getOwner(), a); + a.trigger(e); + } + + this.noteQ.removeAllElements(); + } + + int end = this.prepQ.size(); + + for (int i = 0; i < end; i++) { + Attribute a = this.prepQ.elementAt(i); + this.bs.reset(); + + try { + a.generateNetData(new DataOutputStream(this.bs)); + } catch (IOException var5) { + System.err.println(var5); + throw new Error("Fatal in generateNetData"); + } + + a._outgoing = this.bs.toByteArray(); + if (Std.byteArraysEqual(a._outgoing, a._serverData)) { + a._outgoing = null; + } else if (!this.sendQ.contains(a)) { + this.sendQ.addElement(a); + } + } + + this.prepQ.removeAllElements(); + } + + @Override + public void mainCallback() { + if (this.noteQ.isEmpty() && this.prepQ.isEmpty() && this.sendQ.isEmpty()) { + Main.unregister(this); + } else { + int frameTime = Std.getFastTime(); + if (frameTime > this.lastSendTime + 250) { + this.sendQueue(); + Main.unregister(this); + this.lastSendTime = frameTime; + } + } + } + + private void flushQueue() { + if (this.prepQ != null) { + this.prepQueue(); + if (!this.sendQ.isEmpty()) { + int i = this.sendQ.size(); + + while (--i >= 0) { + Attribute a = this.sendQ.elementAt(i); + a._waitingForFeedback = false; + a._serverData = null; + a._outgoing = null; + } + + this.sendQ.removeAllElements(); + } + } + } + + private void sendQueue() { + this.prepQueue(); + WorldServer rs = ((WObject)this.getOwner()).getServer(); + if (rs != null) { + int end = this.sendQ.size(); + + for (int i = 0; i < end; i++) { + Attribute a = this.sendQ.elementAt(i); + if (a._outgoing != null) { + this.share(rs, a); + a._serverData = a._outgoing; + a._outgoing = null; + a._waitingForFeedback = true; + } + } + } + + this.sendQ.removeAllElements(); + } + + private void share(WorldServer ws, Attribute a) { + SuperRoot w = this.getOwner(); + ObjID objID = null; + if (w instanceof Room) { + Pilot pilot = Pilot.getActive(); + if (pilot != null && pilot.getLastServedRoom() != w) { + objID = new ObjID(((Room)w).getNetworkRoom().getLongID()); + } else { + objID = new ObjID(253); + } + } else if (w instanceof Pilot) { + objID = new ObjID(1); + } else { + objID = new ObjID(w.getName()); + } + + try { + PropertyList propList = new PropertyList(); + propList.addProperty(new net2Property(a._attrID, a.getFlags(), a.getAccessFlags(), a._outgoing)); + ws.sendNetworkMsg(new PropertySetCmd(objID, propList)); + } catch (InfiniteWaitException var6) { + Console.println(Console.message("Net-shutdown") + var6.toString()); + } catch (PacketTooLargeException var7) { + assert false; + } + } + + public void setFromNetData(int attrID, byte[] data) { + if (this.prepQ != null) { + this.prepQueue(); + } + + Attribute a = this.getAttribute(attrID); + if (a == null) { + if ((this.getMode() & 1) != 0) { + Object[] arguments = new Object[]{new String("" + attrID), new String(this.getOwner().getName())}; + Console.println(MessageFormat.format(Console.message("Unknown-attr"), arguments)); + return; + } + + a = new DynamicForwardAttribute(attrID); + this.addAttribute(a); + } + + this.setData(a, data); + if (!a.loaded) { + a.loaded = true; + if (a.callbacks != null && a.callbacks.size() > 0) { + Enumeration<LoadedAttribute> e = a.callbacks.elements(); + + while (e.hasMoreElements()) { + LoadedAttribute la = e.nextElement(); + la.loadedAttribute(a, null); + } + + a.callbacks.removeAllElements(); + } + } + } + + private void setData(Attribute a, byte[] data) { + boolean matchesLastSent = Std.byteArraysEqual(data, a._serverData); + if (a._waitingForFeedback) { + if (!matchesLastSent) { + return; + } + + a._waitingForFeedback = false; + if (data.length != 0 || a._outgoing != null) { + return; + } + } else if (matchesLastSent) { + return; + } + + a._serverData = data; + if (Std.byteArraysEqual(data, a._outgoing)) { + a._outgoing = null; + } else if (a._outgoing == null) { + try { + a.setFromNetData(new DataInputStream(new ByteArrayInputStream(data)), data.length); + } catch (IOException var5) { + var5.printStackTrace(); + Console.println(Console.message("Unrec-format") + a.getName()); + } + + ValueEvent e = new ValueEvent(Std.getFastTime(), this, (WObject)this.getOwner(), a); + a.trigger(e); + } + } + + @Override + public Object properties(int index, int offset, int mode, Object value) throws NoSuchPropertyException { + throw new NoSuchPropertyException(); + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(2, classCookie); + super.saveState(s); + s.saveVector(this.getAttributesList()); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + this.setName(r.restoreString()); + int nSharedAtts = r.restoreInt(); + this.restoredAttributes = new Vector<Object>(nSharedAtts); + + for (int i = 0; i < nSharedAtts; i++) { + this.restoredAttributes.addElement(r.restoreString()); + } + break; + case 1: + this.setName(r.restoreString()); + this.restoredAttributes = r.restoreVector(); + break; + case 2: + super.restoreState(r); + this.restoredAttributes = r.restoreVector(); + break; + default: + throw new TooNewException(); + } + } + + public void ownerPostRestore() { + int desiredMode = this.getMaybeDefaultMode(); + ((WObject)this.getOwner()).setSharerMode(0); + this.setMode(desiredMode); + Enumeration<Object> e = this.restoredAttributes.elements(); + + while (e.hasMoreElements()) { + Attribute a = (Attribute)e.nextElement(); + this.addAttribute(a); + } + + this.restoredAttributes = null; + } + + public void releaseAuxilaryData() { + for (int i = 0; i < 256; i++) { + Attribute a = this.attributes.elementAt(i); + if (a != null) { + a.releaseAuxilaryData(); + } + } + } +} diff --git a/NET/worlds/scape/SlidePropertyAction.java b/NET/worlds/scape/SlidePropertyAction.java new file mode 100644 index 0000000..1d16de2 --- /dev/null +++ b/NET/worlds/scape/SlidePropertyAction.java @@ -0,0 +1,65 @@ +package NET.worlds.scape; + +import NET.worlds.core.Std; +import java.io.IOException; + +public abstract class SlidePropertyAction extends SetPropertyAction { + private float _duration = 0.0F; + private int _startMilliTime = 0; + private static Object classCookie = new Object(); + + protected boolean slide() { + return this._duration != 0.0F; + } + + protected void start() { + this._startMilliTime = Std.getFastTime(); + } + + protected float fraction() { + return (Std.getFastTime() - this._startMilliTime) / (1000.0F * this._duration); + } + + @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 = FloatPropertyEditor.make(new Property(this, index, "Duration")); + } else { + if (mode == 1) { + return new Float(this._duration); + } + + if (mode == 2) { + this._duration = (Float)value; + } + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + super.saveState(s); + s.saveFloat(this._duration); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 1: + super.restoreState(r); + this._duration = r.restoreFloat(); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/SmoothDriver.java b/NET/worlds/scape/SmoothDriver.java new file mode 100644 index 0000000..ad02a17 --- /dev/null +++ b/NET/worlds/scape/SmoothDriver.java @@ -0,0 +1,473 @@ +package NET.worlds.scape; + +import NET.worlds.console.Window; +import java.io.IOException; +import java.util.Enumeration; + +public class SmoothDriver + extends SwitchableBehavior + implements MouseDeltaHandler, + KeyUpHandler, + KeyDownHandler, + FrameHandler, + MouseDownHandler, + MouseUpHandler, + MomentumBehavior { + protected float FB_force; + protected boolean FB_forceFromMouse; + protected float FB_vel; + protected float LR_force; + protected float LR_vel; + protected int lastTime; + protected float maxdvFB = 300.0F; + protected float FB_damp = -2.5F; + protected float minFB_vel = 4.0F; + protected float minFB_pixDouble = 40.0F; + protected float maxdvLR = 166.0F; + protected float LR_damp = -5.0F; + protected float minLR_vel = 3.0F; + protected float minLR_pixDouble = 40.0F; + protected float eyeHeight = 150.0F; + private int appliedForceThisFrame = 0; + private int forceDouble = 0; + protected float FB_key = 1200.0F; + protected float LR_key = 500.0F; + private static Object classCookie = new Object(); + + @Override + public boolean handle(MouseDeltaEvent e) { + if (UniverseHandler.handle(e)) { + return true; + } else { + if (e.dx != 0 || e.dy != 0) { + this.applyFrameForce(e); + float dx2 = e.dx * e.dx; + float dy2 = e.dy * e.dy; + double arrrr = Math.sqrt(dx2 + dy2); + if (e.dy < 0) { + dy2 = -dy2; + } + + this.FB_vel -= (float)(1.1 * dy2 / arrrr); + if (e.dx < 0) { + dx2 = -dx2; + } + + this.LR_vel -= (float)(0.5 * dx2 / arrrr); + } + + return true; + } + } + + public void setVelocityDamping(float pDamp) { + this.FB_damp = pDamp; + } + + public float getVelocityDamping() { + return this.FB_damp; + } + + public void setEyeHeight(float newHeight) { + this.eyeHeight = newHeight; + } + + public float getEyeHeight() { + return this.eyeHeight; + } + + public void applyFrameForce(Event e) { + if (e.receiver instanceof Pilot) { + Pilot pilot = (Pilot)e.receiver; + if (pilot.isActive()) { + this.appliedForceThisFrame++; + int now = e.time; + float dt = (now - this.lastTime) / 1000.0F; + if (!(dt <= 0.0F)) { + if (dt > 0.33F) { + dt = 0.33F; + } + + this.lastTime = now; + float dx = this.FB_vel * dt; + float dv = 0.0F; + if (this.FB_force != 0.0F) { + dv += this.FB_force * dt; + dv = this.maxdvFB * (float)Math.atan(dv / this.maxdvFB); + this.FB_vel += dv; + dx += dv * dt; + } + + float dz = this.eyeHeight - pilot.getZ(); + Room room = pilot.getRoom(); + if (room != null) { + dz += room.floorHeight(pilot.getX(), pilot.getY(), pilot.getZ()); + } + + if (dx != 0.0F || dz != 0.0F) { + this.moveLevel(pilot, dx, dz); + } + + this.FB_vel = (float)(this.FB_vel * Math.exp(this.FB_damp * dt)); + if (Math.abs(this.FB_vel) < this.minFB_vel) { + this.FB_vel = 0.0F; + } + + dv = this.LR_vel * dt; + dz = 0.0F; + if (this.LR_force != 0.0F) { + dz += this.LR_force * dt; + dz = this.maxdvLR * (float)Math.atan(dz / this.maxdvLR); + this.LR_vel += dz; + dv += dz * dt; + } + + if (dv != 0.0F) { + this.yawLevel(pilot, dv); + } + + this.LR_vel = (float)(this.LR_vel * Math.exp(this.LR_damp * dt)); + if (Math.abs(this.LR_vel) < this.minLR_vel) { + this.LR_vel = 0.0F; + } + } + } + } + } + + private void moveLevel(Pilot pilot, float dx, float dz) { + float currentYaw = pilot.getYaw(); + Point3Temp currentSpinAxis = Point3Temp.make(); + float currentSpin = pilot.getSpin(currentSpinAxis); + Point3Temp currentPosition = pilot.getPosition(); + pilot.makeIdentity().moveTo(currentPosition).yaw(-currentYaw); + pilot.premoveThrough(Point3Temp.make(0.0F, dx, dz)); + pilot.yaw(currentYaw); + pilot.spin(currentSpinAxis, currentSpin); + } + + private void yawLevel(Pilot pilot, float dTheta) { + float currentYaw = pilot.getYaw(); + Point3Temp currentSpinAxis = Point3Temp.make(); + float currentSpin = pilot.getSpin(currentSpinAxis); + Point3Temp currentPosition = pilot.getPosition(); + pilot.makeIdentity().moveTo(currentPosition).yaw(-currentYaw); + pilot.yaw(dTheta); + pilot.yaw(currentYaw); + pilot.spin(currentSpinAxis, currentSpin); + } + + @Override + public boolean handle(FrameEvent e) { + if (this.FB_forceFromMouse && !this.isDelta(e)) { + this.applyFrameForce(e); + this.FB_force = 0.0F; + this.FB_forceFromMouse = false; + } + + if (this.appliedForceThisFrame == 0) { + this.applyFrameForce(e); + } + + this.appliedForceThisFrame = 0; + return true; + } + + @Override + public boolean handle(KeyDownEvent e) { + if (UniverseHandler.handle(e)) { + return true; + } else { + float FB; + if (e.key == '\ue326') { + FB = this.FB_key; + } else { + if (e.key != '\ue328') { + float LR; + if (e.key == '\ue325') { + LR = this.LR_key; + } else { + if (e.key != '\ue327') { + return true; + } + + LR = -this.LR_key; + } + + this.applyFrameForce(e); + this.LR_force = LR; + return true; + } + + FB = -this.FB_key; + } + + this.applyFrameForce(e); + this.FB_force = FB; + return true; + } + } + + @Override + public boolean handle(KeyUpEvent e) { + if (UniverseHandler.handle(e)) { + return true; + } else { + if (e.key == '\ue326' || e.key == '\ue328') { + this.applyFrameForce(e); + this.FB_force = 0.0F; + } else if (e.key == '\ue325' || e.key == '\ue327') { + this.applyFrameForce(e); + this.LR_force = 0.0F; + } + + return true; + } + } + + private boolean isDelta(Event e) { + if (e.receiver instanceof Pilot && ((Pilot)e.receiver).isActive()) { + Window w = Window.getMainWindow(); + return w != null && w.getDeltaMode(); + } else { + return false; + } + } + + @Override + public boolean handle(MouseDownEvent e) { + if (e.key == '\ue302' && this.isDelta(e)) { + this.applyFrameForce(e); + this.FB_force = this.FB_key; + this.FB_forceFromMouse = true; + } + + return true; + } + + @Override + public boolean handle(MouseUpEvent e) { + if (e.key == '\ue302' && this.isDelta(e)) { + this.applyFrameForce(e); + this.FB_force = 0.0F; + this.FB_forceFromMouse = false; + } + + return true; + } + + @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 = FloatPropertyEditor.make(new Property(this, index, "Eye Height")); + } else if (mode == 1) { + ret = new Float(this.getEyeHeight()); + } else if (mode == 2) { + this.setEyeHeight((Float)value); + } + break; + case 1: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Fore/aft max acceleration")); + } else if (mode == 1) { + ret = new Float(this.maxdvFB); + } else if (mode == 2) { + this.maxdvFB = (Float)value; + } + break; + case 2: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Fore/aft velocity damping")); + } else if (mode == 1) { + ret = new Float(this.FB_damp); + } else if (mode == 2) { + this.FB_damp = (Float)value; + } + break; + case 3: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Fore/aft min velocity")); + } else if (mode == 1) { + ret = new Float(this.minFB_vel); + } else if (mode == 2) { + this.minFB_vel = (Float)value; + } + break; + case 4: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Fore/aft velocity threshold for pixel doubling")); + } else if (mode == 1) { + ret = new Float(this.minFB_pixDouble); + } else if (mode == 2) { + this.minFB_pixDouble = (Float)value; + } + break; + case 5: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Yaw max acceleration")); + } else if (mode == 1) { + ret = new Float(this.maxdvLR); + } else if (mode == 2) { + this.maxdvLR = (Float)value; + } + break; + case 6: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Yaw rate damping")); + } else if (mode == 1) { + ret = new Float(this.LR_damp); + } else if (mode == 2) { + this.LR_damp = (Float)value; + } + break; + case 7: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Yaw min rate")); + } else if (mode == 1) { + ret = new Float(this.minLR_vel); + } else if (mode == 2) { + this.minLR_vel = (Float)value; + } + break; + case 8: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Yaw rate threshold for pixel doubling")); + } else if (mode == 1) { + ret = new Float(this.minLR_pixDouble); + } else if (mode == 2) { + this.minLR_pixDouble = (Float)value; + } + break; + case 9: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Fore/aft velocity increment for up/down arrow keys")); + } else if (mode == 1) { + ret = new Float(this.FB_key); + } else if (mode == 2) { + this.FB_key = (Float)value; + } + break; + case 10: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Yaw rate increment for up/down arrow keys")); + } else if (mode == 1) { + ret = new Float(this.LR_key); + } else if (mode == 2) { + this.LR_key = (Float)value; + } + break; + default: + ret = super.properties(index, offset + 11, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(3, classCookie); + super.saveState(s); + s.saveFloat(this.FB_vel); + s.saveFloat(this.LR_vel); + s.saveFloat(this.maxdvFB); + s.saveFloat(this.FB_damp); + s.saveFloat(this.minFB_vel); + s.saveFloat(this.maxdvLR); + s.saveFloat(this.LR_damp); + s.saveFloat(this.minLR_vel); + s.saveFloat(this.eyeHeight); + s.saveFloat(this.FB_key); + s.saveFloat(this.LR_key); + s.saveInt(this.forceDouble); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + r.setOldFlag(); + super.restoreState(r); + r.restoreFloat(); + this.FB_vel = r.restoreFloat(); + r.restoreFloat(); + this.LR_vel = r.restoreFloat(); + break; + case 1: + r.setOldFlag(); + super.restoreState(r); + r.restoreFloat(); + this.FB_vel = r.restoreFloat(); + r.restoreFloat(); + this.LR_vel = r.restoreFloat(); + this.maxdvFB = r.restoreFloat(); + this.FB_damp = r.restoreFloat(); + this.minFB_vel = r.restoreFloat(); + this.maxdvLR = r.restoreFloat(); + this.LR_damp = r.restoreFloat(); + this.minLR_vel = r.restoreFloat(); + this.eyeHeight = r.restoreFloat(); + this.FB_key = r.restoreFloat(); + this.LR_key = r.restoreFloat(); + break; + case 2: + r.setOldFlag(); + super.restoreState(r); + r.restoreFloat(); + this.FB_vel = r.restoreFloat(); + r.restoreFloat(); + this.LR_vel = r.restoreFloat(); + this.maxdvFB = r.restoreFloat(); + this.FB_damp = r.restoreFloat(); + this.minFB_vel = r.restoreFloat(); + this.maxdvLR = r.restoreFloat(); + this.LR_damp = r.restoreFloat(); + this.minLR_vel = r.restoreFloat(); + this.eyeHeight = r.restoreFloat(); + this.FB_key = r.restoreFloat(); + this.LR_key = r.restoreFloat(); + this.forceDouble = r.restoreInt(); + break; + case 3: + super.restoreState(r); + this.FB_vel = r.restoreFloat(); + this.LR_vel = r.restoreFloat(); + this.maxdvFB = r.restoreFloat(); + this.FB_damp = r.restoreFloat(); + this.minFB_vel = r.restoreFloat(); + this.maxdvLR = r.restoreFloat(); + this.LR_damp = r.restoreFloat(); + this.minLR_vel = r.restoreFloat(); + this.eyeHeight = r.restoreFloat(); + this.FB_key = r.restoreFloat(); + this.LR_key = r.restoreFloat(); + this.forceDouble = r.restoreInt(); + break; + default: + throw new TooNewException(); + } + } + + @Override + public void transferFrom(Enumeration oldMBs) { + this.FB_force = 0.0F; + this.LR_force = 0.0F; + + while (oldMBs.hasMoreElements()) { + SuperRoot sr = (SuperRoot)oldMBs.nextElement(); + if (sr instanceof SmoothDriver) { + SmoothDriver sd = (SmoothDriver)sr; + this.FB_vel = sd.FB_vel; + this.LR_vel = sd.LR_vel; + this.lastTime = sd.lastTime; + return; + } + } + + this.FB_vel = 0.0F; + this.LR_vel = 0.0F; + this.lastTime = 0; + } +} diff --git a/NET/worlds/scape/Sound.java b/NET/worlds/scape/Sound.java new file mode 100644 index 0000000..aa9d5a3 --- /dev/null +++ b/NET/worlds/scape/Sound.java @@ -0,0 +1,623 @@ +package NET.worlds.scape; + +import NET.worlds.console.Main; +import NET.worlds.console.MainCallback; +import NET.worlds.core.IniFile; +import NET.worlds.network.CacheFile; +import NET.worlds.network.URL; +import java.io.IOException; +import java.util.Vector; + +public class Sound extends Action implements BGLoaded, StateContext { + static int debugLevel = IniFile.gamma().getIniInt("sounddebug", 0); + private String cachedName; + private URL soundURL; + protected CacheFile cachedFile = null; + protected float soundVolume = 1.0F; + protected float stopDistance = 1000.0F; + private int repeat = 1; + private boolean continuous = false; + private boolean attenuateOn = true; + private boolean panningOn = true; + protected SuperRoot activeSeq; + SoundPlayer player; + AudibilityFilter aFilter = null; + private int maxHopcount = 1; + private boolean doorMovementFlag = false; + private static boolean soundOn = true; + boolean playAfterLoading = true; + protected int state = 0; + protected static final int SYNC = 1; + protected static final int ASYNC = 2; + protected int backgroundState = 1; + private static SoundCallback closer; + static Vector cachedEntries; + private static Vector pendingEntries; + private boolean mainRan; + private boolean opened; + private static Object classCookie = new Object(); + + static { + debugOut(1, "SOUND DEBUGGING LEVEL = " + debugLevel); + } + + private static void debugOut(int n, String s) { + if (debugLevel > n) { + System.out.println(s); + } + } + + public Sound(URL soundURL) { + Transform.countClass(this, 1); + debugOut(9, "Sound " + soundURL); + this.setURL(soundURL); + } + + public Sound() { + Transform.countClass(this, 1); + debugOut(9, "Sound "); + this.setURL(null); + } + + public final void setURL(URL url) { + if (this.activeSeq != null) { + this.closePlayer(); + } + + this.soundURL = url; + } + + public final URL getURL() { + return this.soundURL; + } + + public final void setSoundVolume(float vol) { + this.soundVolume = vol; + } + + public final float getSoundVolume() { + return this.soundVolume; + } + + public final void setStopDistance(float i) { + this.stopDistance = i; + } + + public final float getStopDistance() { + return this.stopDistance; + } + + public final void setRepeat(int i) { + this.repeat = i; + } + + public final int getRepeat() { + return this.repeat; + } + + public final void setContinuous(boolean c) { + this.continuous = c; + } + + public final boolean isContinuous() { + return this.continuous; + } + + public final void setAttenuate(boolean b) { + this.attenuateOn = b; + } + + public final boolean getAttenuate() { + return this.attenuateOn; + } + + public final void setPanning(boolean b) { + this.panningOn = b; + } + + public final boolean getPanning() { + return this.panningOn; + } + + public final int getState() { + return this.player.getState(); + } + + public final int getHopcount() { + return this.maxHopcount; + } + + public final void setHopcount(int i) { + this.maxHopcount = i; + if (this.aFilter != null) { + this.aFilter.setHopcount(this.maxHopcount); + } + } + + public boolean getDoorMovementFlag() { + return this.doorMovementFlag; + } + + public void setDoorMovementFlag(boolean b) { + this.doorMovementFlag = b; + if (this.aFilter != null) { + this.startAudibilityFilter(); + } + } + + private void startAudibilityFilter() { + debugOut(9, "startAudibilityFilter " + this.getURL()); + WObject owner = (WObject)this.getOwner(); + if (owner != null) { + if (this.doorMovementFlag) { + this.aFilter = new DoorBasedFilter(this, owner, this.maxHopcount, this.stopDistance); + } else { + this.aFilter = new AudibilityFilter(this, owner, this.maxHopcount); + } + + this.aFilter.moveEmitter(); + } + } + + public static void turnSoundOn() { + soundOn = true; + } + + public static void turnSoundOff() { + soundOn = false; + } + + public void setPlayAfterLoading(boolean b) { + this.playAfterLoading = b; + } + + protected boolean isRealAudio(URL s) { + return s.endsWith(".ram") || s.endsWith(".ra") || s.endsWith(".rm"); + } + + @Override + public void changeState(int s) { + debugOut(9, "changeState to " + s); + this.state = s; + } + + protected Object doState(Object obj) { + return SoundState.instance().doState(this, obj); + } + + private boolean isBackgroundProcessing() { + if (this.state != 0) { + debugOut(9, "backgroundProcessing " + this.state); + } + + return this.state != 0; + } + + private void startSound() { + this.backgroundState = 1; + if (this.aFilter == null) { + this.startAudibilityFilter(); + } + + if (this.aFilter != null) { + this.aFilter.setEmitterOn(true); + } + + if (this.state == 0) { + this.state = 1; + } + + this.doState(this.soundURL); + } + + @Override + public Object asyncBackgroundLoad(String localName, URL remoteName) { + this.backgroundState = 2; + return this.doState(URL.make(localName)); + } + + @Override + public boolean syncBackgroundLoad(Object obj, URL remoteURL) { + this.backgroundState = 1; + this.doState(obj); + return false; + } + + @Override + public Room getBackgroundLoadRoom() { + WObject owner = (WObject)this.getOwner(); + return owner == null ? null : owner.getRoom(); + } + + protected void ensureClosure() { + if (closer == null) { + closer = new SoundCallback(); + Main.register(closer); + } + + if (cachedEntries == null) { + cachedEntries = new Vector(); + } + + cachedEntries.addElement(this.cachedFile); + } + + protected void unlockCache() { + if (this.cachedFile != null) { + debugOut(6, "unlocking " + this.soundURL); + this.cachedFile.finalize(); + + assert cachedEntries != null; + + assert cachedEntries.indexOf(this.cachedFile, 0) >= 0; + + cachedEntries.removeElement(this.cachedFile); + this.cachedFile = null; + } + } + + synchronized boolean openPlayer(URL url) { + assert this.player == null; + + this.cachedName = url.unalias(); + debugOut(4, "openPlayer on:: " + this.cachedName); + if (url.endsWith(".wav")) { + this.player = new WavSoundPlayer(this); + } else if (url.endsWith(".mid")) { + this.player = new MCISoundPlayer(this); + } else { + this.player = new WMPSoundPlayer(this); + } + + if (Main.isMainThread()) { + this.openInMainThread(); + } else { + this.mainRan = false; + Main.register(new MainCallback() { + @Override + public void mainCallback() { + Sound.this.openInMainThread(); + Main.unregister(this); + } + }); + + while (!this.mainRan) { + try { + this.wait(); + } catch (InterruptedException var3) { + } + } + } + + return this.opened; + } + + public synchronized void openInMainThread() { + this.opened = this.player.open(this.soundVolume, this.stopDistance, this.attenuateOn, this.panningOn); + if (!this.opened) { + this.closePlayer(); + } + + this.mainRan = true; + this.notify(); + } + + void closePlayer() { + if (this.player != null) { + this.player.stop(); + this.unlockCache(); + if (SoundResource.instance().syncUnlock()) { + this.player.close(); + } + + this.player = null; + } + + debugOut(2, " closePlayer"); + } + + @Override + public Persister trigger(Event e, Persister seqID) { + debugOut(9, "trigger in: seqID " + seqID + " activeSeq " + this.activeSeq); + if (this.isBackgroundProcessing()) { + return this.activeSeq; + } else { + if (seqID == null) { + if (this.soundURL == null || this.getOwner() == null) { + return null; + } + + if (this.activeSeq != null) { + this.closePlayer(); + } + + this.activeSeq = this; + Persister var3 = this.activeSeq; + debugOut(6, "triggering new sound " + var3); + this.startSound(); + } else if (seqID != this.activeSeq) { + this.unlockCache(); + if (!this.isContinuous()) { + this.aFilter.setEmitterOn(false); + } + + return null; + } + + if (this.player != null && this.player.getState() != 0 && !this.isContinuous()) { + this.aFilter.setEmitterOn(false); + } + + if ((this.isBackgroundProcessing() || this.updateSound() && this.player.getState() == 0) && this.getOwner() != null) { + return this.activeSeq; + } else { + this.activeSeq = null; + this.closePlayer(); + return null; + } + } + } + + boolean updateSound() { + debugOut(9, "Sound::updateSound:: in"); + if (this.player == null) { + debugOut(6, "update returning false because player is null"); + return false; + } else if (!SoundResource.instance().isOK()) { + debugOut(2, "update registering not OK"); + return false; + } else if (!this.aFilter.isAudible()) { + debugOut(4, "update stopping sound because isAudible false"); + return false; + } else { + Point3Temp pilot = Point3Temp.make(); + Point3Temp up = Point3Temp.make(); + Point3Temp forward = Point3Temp.make(); + Point3Temp obj = Point3Temp.make(); + this.aFilter.getListenerPosition(pilot, up, forward); + this.aFilter.getEmitterPosition(obj); + if (!this.player.position(pilot, obj, forward, up)) { + debugOut(6, "update returning false because position false"); + return false; + } else { + float vol = -1.0F; + if (soundOn) { + vol = this.aFilter.getEmitterVolume(); + } + + if (!this.player.setVolume(vol * this.soundVolume)) { + debugOut(6, "update returning false because volume false"); + return false; + } else { + return true; + } + } + } + } + + @Override + public void postRestore(int version) { + super.postRestore(version); + this.startAudibilityFilter(); + } + + @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 = URLPropertyEditor.make(new Property(this, index, "Sound File URL").allowSetNull(), "asf;wav;mid;ram;ra;rm;mp3"); + } else if (mode == 1) { + ret = this.soundURL; + } else if (mode == 2) { + this.soundURL = (URL)value; + } + break; + case 1: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Max Volume")); + } else if (mode == 1) { + ret = new Float(this.soundVolume); + } else if (mode == 2) { + this.soundVolume = (Float)value; + } + break; + case 2: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Stop Distance")); + } else if (mode == 1) { + ret = new Float(this.stopDistance); + } else if (mode == 2) { + this.stopDistance = (Float)value; + } + break; + case 3: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Times to Repeat")); + } else if (mode == 1) { + ret = new Integer(this.repeat); + } else if (mode == 2) { + this.repeat = (Integer)value; + } + break; + case 4: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Attenuate With Distance"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.attenuateOn); + } else if (mode == 2) { + this.attenuateOn = (Boolean)value; + } + break; + case 5: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Do panning"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.panningOn); + } else if (mode == 2) { + this.panningOn = (Boolean)value; + } + break; + case 6: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Room hops till sound dies")); + } else if (mode == 1) { + ret = new Integer(this.maxHopcount); + } else if (mode == 2) { + this.setHopcount((Integer)value); + } + break; + case 7: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Door based audibility"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.getDoorMovementFlag()); + } else if (mode == 2) { + this.setDoorMovementFlag((Boolean)value); + } + break; + case 8: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Play after loading"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.playAfterLoading); + } else if (mode == 2) { + this.setPlayAfterLoading((Boolean)value); + } + break; + case 9: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Loop Infinite"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.continuous); + } else if (mode == 2) { + this.setContinuous((Boolean)value); + } + break; + default: + ret = super.properties(index, offset + 10, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(7, classCookie); + s.saveBoolean(this.playAfterLoading); + s.saveBoolean(this.doorMovementFlag); + s.saveBoolean(this.panningOn); + s.saveBoolean(this.attenuateOn); + s.saveInt(this.maxHopcount); + super.saveState(s); + URL.save(s, this.soundURL); + s.saveFloat(this.soundVolume); + s.saveFloat(this.stopDistance); + s.saveInt(this.repeat); + s.saveBoolean(this.continuous); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + int vers = r.restoreVersion(classCookie); + switch (vers) { + case 0: + this.setURL(URL.restore(r)); + break; + case 1: + this.setURL(URL.restore(r)); + this.soundVolume = r.restoreFloat(); + this.stopDistance = r.restoreFloat(); + this.repeat = r.restoreInt(); + if (this.repeat < 0) { + this.setContinuous(true); + } + break; + case 2: + super.restoreState(r); + this.setURL(URL.restore(r)); + this.soundVolume = r.restoreFloat(); + this.stopDistance = r.restoreFloat(); + this.repeat = r.restoreInt(); + if (this.repeat < 0) { + this.setContinuous(true); + } + break; + case 3: + this.setHopcount(r.restoreInt()); + super.restoreState(r); + this.setURL(URL.restore(r)); + this.soundVolume = r.restoreFloat(); + this.stopDistance = r.restoreFloat(); + this.repeat = r.restoreInt(); + if (this.repeat < 0) { + this.setContinuous(true); + } + break; + case 4: + this.setDoorMovementFlag(r.restoreBoolean()); + this.setPanning(r.restoreBoolean()); + this.setAttenuate(r.restoreBoolean()); + this.setHopcount(r.restoreInt()); + super.restoreState(r); + this.setURL(URL.restore(r)); + this.soundVolume = r.restoreFloat(); + this.stopDistance = r.restoreFloat(); + this.repeat = r.restoreInt(); + if (this.repeat < 0) { + this.setContinuous(true); + } + break; + case 5: + this.setPlayAfterLoading(r.restoreBoolean()); + this.setDoorMovementFlag(r.restoreBoolean()); + this.setPanning(r.restoreBoolean()); + this.setAttenuate(r.restoreBoolean()); + this.setHopcount(r.restoreInt()); + super.restoreState(r); + this.setURL(URL.restore(r)); + this.soundVolume = r.restoreFloat(); + this.stopDistance = r.restoreFloat(); + this.repeat = r.restoreInt(); + if (this.repeat < 0) { + this.setContinuous(true); + } + break; + case 6: + this.setPlayAfterLoading(r.restoreBoolean()); + this.setDoorMovementFlag(r.restoreBoolean()); + this.setPanning(r.restoreBoolean()); + this.setAttenuate(r.restoreBoolean()); + this.setHopcount(r.restoreInt()); + super.restoreState(r); + this.setURL(URL.restore(r)); + this.soundVolume = r.restoreFloat(); + this.stopDistance = r.restoreFloat(); + this.repeat = r.restoreInt(); + if (this.repeat < 0) { + this.setContinuous(true); + } + break; + case 7: + this.setPlayAfterLoading(r.restoreBoolean()); + this.setDoorMovementFlag(r.restoreBoolean()); + this.setPanning(r.restoreBoolean()); + this.setAttenuate(r.restoreBoolean()); + this.setHopcount(r.restoreInt()); + super.restoreState(r); + this.setURL(URL.restore(r)); + this.soundVolume = r.restoreFloat(); + this.stopDistance = r.restoreFloat(); + this.repeat = r.restoreInt(); + this.setContinuous(r.restoreBoolean()); + break; + default: + throw new TooNewException(); + } + + if (vers < 6 && this.continuous) { + this.setContinuous(false); + } + } +} diff --git a/NET/worlds/scape/SoundCallback.java b/NET/worlds/scape/SoundCallback.java new file mode 100644 index 0000000..2a5123f --- /dev/null +++ b/NET/worlds/scape/SoundCallback.java @@ -0,0 +1,28 @@ +package NET.worlds.scape; + +import NET.worlds.console.Main; +import NET.worlds.console.MainCallback; +import NET.worlds.console.MainTerminalCallback; +import NET.worlds.core.IniFile; +import NET.worlds.network.CacheFile; + +class SoundCallback implements MainCallback, MainTerminalCallback { + @Override + public void mainCallback() { + } + + @Override + public void terminalCallback() { + while (!Sound.cachedEntries.isEmpty()) { + CacheFile file = (CacheFile)Sound.cachedEntries.firstElement(); + if (IniFile.gamma().getIniInt("sounddebug", 0) > 6) { + System.out.println("terminal unlocking " + file.getLocalName()); + } + + Sound.cachedEntries.removeElementAt(0); + file.finalize(); + } + + Main.unregister(this); + } +} diff --git a/NET/worlds/scape/SoundPlayer.java b/NET/worlds/scape/SoundPlayer.java new file mode 100644 index 0000000..8cb9a58 --- /dev/null +++ b/NET/worlds/scape/SoundPlayer.java @@ -0,0 +1,31 @@ +package NET.worlds.scape; + +public abstract class SoundPlayer { + Sound owner; + public static final int IS_PLAYING = 0; + public static final int IS_STOPPED = 1; + public static final int IS_TERMINATED = 2; + public static final int IS_ERROR = 3; + + SoundPlayer(Sound owner) { + this.owner = owner; + } + + public Sound getOwner() { + return this.owner; + } + + public abstract boolean open(float var1, float var2, boolean var3, boolean var4); + + public abstract void start(int var1); + + public abstract boolean position(Point3Temp var1, Point3Temp var2, Point3Temp var3, Point3Temp var4); + + public abstract int getState(); + + public abstract void stop(); + + public abstract void close(); + + public abstract boolean setVolume(float var1); +} diff --git a/NET/worlds/scape/SoundResource.java b/NET/worlds/scape/SoundResource.java new file mode 100644 index 0000000..19975f2 --- /dev/null +++ b/NET/worlds/scape/SoundResource.java @@ -0,0 +1,89 @@ +package NET.worlds.scape; + +class SoundResource { + private static SoundResource instance = null; + public static final int RSX = 1; + public static final int RA = 2; + private int currentPlayer = 0; + private int counter = 0; + private boolean isShutdownTime = false; + + private SoundResource() { + } + + private static void debugOut(int n, String s) { + if (Sound.debugLevel > n) { + System.out.println(s); + } + } + + public static SoundResource instance() { + if (instance == null) { + debugOut(6, "Instantiating a new SoundResource"); + instance = new SoundResource(); + } + + return instance; + } + + public boolean syncLock(int type) { + debugOut(6, "Calling syncLock with type " + type + " counter " + this.counter); + if (this.isShutdownTime) { + return false; + } else { + if (type != this.currentPlayer) { + this.currentPlayer = type; + if (this.counter > 0) { + this.isShutdownTime = true; + } else { + this.currentPlayer = type; + this.counter = 1; + } + } else { + this.counter++; + } + + return true; + } + } + + public synchronized void asyncLock() { + debugOut(6, "SoundResource::asyncLock with " + this.isShutdownTime); + boolean shutdown = false; + + while (this.isShutdownTime) { + shutdown = true; + Thread.yield(); + debugOut(6, "asyncLock yield"); + } + + if (shutdown) { + debugOut(6, "asyncLock: adding artificial delay"); + + try { + Thread.sleep(500L); + } catch (InterruptedException var3) { + } + } + } + + public boolean syncUnlock() { + debugOut(6, "SoundResource::syncUnlock with " + this.counter); + boolean rv = false; + this.counter--; + if (this.counter <= 0) { + rv = true; + } + + if (this.counter <= 0 && this.isShutdownTime) { + this.counter = 1; + this.isShutdownTime = false; + } + + return rv; + } + + public boolean isOK() { + return !this.isShutdownTime; + } +} diff --git a/NET/worlds/scape/SoundState.java b/NET/worlds/scape/SoundState.java new file mode 100644 index 0000000..eef9d07 --- /dev/null +++ b/NET/worlds/scape/SoundState.java @@ -0,0 +1,307 @@ +package NET.worlds.scape; + +import NET.worlds.network.Cache; +import NET.worlds.network.URL; + +class SoundState implements State { + public static final int IDLE = 0; + public static final int start = 1; + public static final int intel0 = 1000; + public static final int intel10 = 1010; + public static final int intel11 = 1011; + public static final int intel20 = 1020; + public static final int intel21 = 1021; + public static final int intel30 = 1030; + public static final int intel31 = 1031; + public static final int intel32 = 1032; + public static final int intel33 = 1033; + public static final int realAudio0 = 2000; + public static final int realAudio10 = 2010; + public static final int realAudio11 = 2011; + private static SoundState instance = new SoundState(); + private static URL dummy = URL.make("home:dummy.wav"); + + private SoundState() { + } + + private void debugOut(int n, String s) { + if (Sound.debugLevel > n) { + System.out.println(s); + } + } + + public static State instance() { + return instance; + } + + @Override + public Object doState(StateContext sc, Object obj) { + Sound sound = (Sound)sc; + Object rv; + switch (sound.state) { + case 1: + rv = this.start(sound, obj); + break; + case 1000: + rv = this.intel0(sound, obj); + break; + case 1010: + rv = this.intel10(sound, obj); + break; + case 1011: + rv = this.intel11(sound, obj); + break; + case 1020: + rv = this.intel20(sound, obj); + break; + case 1021: + rv = this.intel21(sound, obj); + break; + case 1030: + rv = this.intel30(sound, obj); + break; + case 1031: + rv = this.intel31(sound, obj); + break; + case 1032: + rv = this.intel32(sound, obj); + break; + case 1033: + rv = this.intel33(sound, obj); + break; + case 2000: + rv = this.realAudio0(sound, obj); + break; + case 2010: + rv = this.realAudio10(sound, obj); + break; + case 2011: + rv = this.realAudio11(sound, obj); + break; + default: + rv = this.error(sound, obj); + } + + return rv; + } + + private Object error(Sound sound, Object obj) { + this.debugOut(2, "Unknown state in SoundState " + sound.state); + return null; + } + + private Object start(Sound sound, Object obj) { + this.debugOut(6, "Entering SoundState "); + + assert sound.backgroundState == 1; + + if (sound.isRealAudio(sound.getURL())) { + sound.changeState(2000); + } else { + sound.changeState(1000); + } + + sound.doState(null); + return null; + } + + private Object intel0(Sound sound, Object obj) { + this.debugOut(6, "Entering intel0 "); + + assert sound.backgroundState == 1; + + if (!SoundResource.instance().syncLock(1)) { + return null; + } else if (!sound.getURL().isRemote()) { + sound.changeState(1010); + BackgroundLoader.get(sound, sound.getURL()); + return null; + } else { + sound.cachedFile = Cache.getFile(sound.getURL()); + if (sound.cachedFile.done()) { + sound.ensureClosure(); + sound.changeState(1020); + BackgroundLoader.get(sound, sound.getURL()); + return null; + } else { + sound.cachedFile.finalize(); + sound.cachedFile = null; + sound.changeState(1030); + BackgroundLoader.get(sound, dummy); + return null; + } + } + } + + private Object intel10(Sound sound, Object localName) { + assert sound.backgroundState == 2; + + assert localName != null; + + SoundResource.instance().asyncLock(); + sound.changeState(1011); + if (sound.openPlayer((URL)localName)) { + return localName; + } else { + this.debugOut(2, "intel10: couldn't open sound " + sound.getURL()); + return null; + } + } + + private Object intel11(Sound sound, Object obj) { + this.debugOut(6, "Entering intel11 "); + + assert sound.backgroundState == 1; + + if (obj != null) { + if (sound.updateSound()) { + sound.player.start(sound.getRepeat()); + } else { + sound.closePlayer(); + } + } + + sound.changeState(0); + return null; + } + + private Object intel20(Sound sound, Object obj) { + this.debugOut(6, "Entering intel20 "); + + assert sound.backgroundState == 2; + + SoundResource.instance().asyncLock(); + if (sound.openPlayer((URL)obj)) { + sound.changeState(1021); + return obj; + } else { + this.debugOut(2, "intel20: couldn't open player on sound " + sound.getURL()); + sound.changeState(1021); + return null; + } + } + + private Object intel21(Sound sound, Object obj) { + this.debugOut(6, "Entering intel21 "); + + assert sound.backgroundState == 1; + + if (obj == null) { + sound.unlockCache(); + } else if (sound.updateSound()) { + this.debugOut(6, "intel21 starting sound"); + sound.player.start(sound.getRepeat()); + } else { + this.debugOut(6, "intel21 closing player"); + sound.closePlayer(); + } + + sound.changeState(0); + return null; + } + + private Object intel30(Sound sound, Object obj) { + this.debugOut(6, "Entering intel30 "); + + assert sound.backgroundState == 2; + + SoundResource.instance().asyncLock(); + if (sound.openPlayer(dummy)) { + sound.changeState(1031); + return obj; + } else { + this.debugOut(2, "intel30: couldn't open player on file " + sound.getURL()); + sound.changeState(1031); + return null; + } + } + + private Object intel31(Sound sound, Object obj) { + this.debugOut(6, "Entering intel31 "); + + assert sound.backgroundState == 1; + + if (obj == null) { + sound.changeState(0); + } else if (sound.updateSound()) { + sound.player.start(1); + sound.changeState(1032); + BackgroundLoader.get(sound, sound.getURL()); + } else { + sound.closePlayer(); + sound.changeState(0); + } + + return null; + } + + private Object intel32(Sound sound, Object obj) { + this.debugOut(6, "Entering intel32 "); + + assert sound.backgroundState == 2; + + sound.changeState(1033); + return obj; + } + + private Object intel33(Sound sound, Object obj) { + this.debugOut(6, "Entering intel33 "); + + assert sound.backgroundState == 1; + + if (obj != null && sound.playAfterLoading) { + sound.closePlayer(); + sound.changeState(1000); + sound.doState(obj); + } else { + sound.changeState(0); + } + + return null; + } + + private Object realAudio0(Sound sound, Object obj) { + this.debugOut(6, "Entering RealAudio0 "); + + assert sound.backgroundState == 1; + + if (!SoundResource.instance().syncLock(2)) { + return null; + } else { + sound.changeState(2010); + BackgroundLoader.get(sound, dummy); + return null; + } + } + + private Object realAudio10(Sound sound, Object obj) { + this.debugOut(6, "Entering realAudio10 "); + + assert sound.backgroundState == 2; + + SoundResource.instance().asyncLock(); + if (sound.openPlayer(sound.getURL())) { + sound.changeState(2011); + return sound; + } else { + return null; + } + } + + private Object realAudio11(Sound sound, Object obj) { + this.debugOut(6, "Entering realAudio11 "); + + assert sound.backgroundState == 1; + + if (obj != null) { + if (sound.updateSound()) { + sound.player.start(sound.getRepeat()); + } else { + sound.closePlayer(); + } + } + + sound.changeState(0); + return null; + } +} diff --git a/NET/worlds/scape/SpinBehavior.java b/NET/worlds/scape/SpinBehavior.java new file mode 100644 index 0000000..92be2d4 --- /dev/null +++ b/NET/worlds/scape/SpinBehavior.java @@ -0,0 +1,122 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class SpinBehavior extends SwitchableBehavior implements FrameHandler { + protected float cycleTime; + protected float ax; + protected float ay; + protected float az; + private static Object classCookie = new Object(); + + public SpinBehavior() { + this(5.0F); + } + + public SpinBehavior(float cycleTime) { + this(cycleTime, 0.0F, 0.0F, 1.0F); + } + + public SpinBehavior(Point3Temp axis) { + this(5.0F, axis); + } + + public SpinBehavior(float ax, float ay, float az) { + this(5.0F, ax, ay, az); + } + + public SpinBehavior(float cycleTime, Point3Temp axis) { + this(cycleTime, axis.x, axis.y, axis.z); + } + + public SpinBehavior(float cycleTime, float ax, float ay, float az) { + this.cycleTime = cycleTime; + this.ax = ax; + this.ay = ay; + this.az = az; + } + + public float getCycleTime() { + return this.cycleTime; + } + + public void setCycleTime(float t) { + this.cycleTime = t; + } + + public Point3Temp getAxis() { + return Point3Temp.make(this.ax, this.ay, this.az); + } + + public void setAxis(Point3Temp axis) { + this.ax = axis.x; + this.ay = axis.y; + this.az = axis.z; + } + + @Override + public boolean handle(FrameEvent e) { + if (this.enabled && this.cycleTime > 0.0F) { + e.receiver.spin(this.ax, this.ay, this.az, 0.36F * e.dt / this.cycleTime); + } + + return true; + } + + @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 = FloatPropertyEditor.make(new Property(this, index, "Cycle Time")); + } else if (mode == 1) { + ret = new Float(this.cycleTime); + } else if (mode == 2) { + this.cycleTime = (Float)value; + } + break; + case 1: + if (mode == 0) { + ret = Point3PropertyEditor.make(new Property(this, index, "Axis")); + } else if (mode == 1) { + ret = new Point3(this.getAxis()); + } else if (mode == 2) { + this.setAxis((Point3)value); + } + break; + default: + ret = super.properties(index, offset + 2, mode, value); + } + + return ret; + } + + @Override + public String toString() { + return super.toString() + "[axis " + this.getAxis() + ", cycleTime " + this.cycleTime + ", enabled " + this.enabled + "]"; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + s.saveFloat(this.cycleTime); + s.saveFloat(this.ax); + s.saveFloat(this.ay); + s.saveFloat(this.az); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + this.cycleTime = r.restoreFloat(); + this.ax = r.restoreFloat(); + this.ay = r.restoreFloat(); + this.az = r.restoreFloat(); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/StandardTexture.java b/NET/worlds/scape/StandardTexture.java new file mode 100644 index 0000000..1ad283b --- /dev/null +++ b/NET/worlds/scape/StandardTexture.java @@ -0,0 +1,45 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class StandardTexture extends Texture implements Persister { + private String urlName; + private static Object classCookie = new Object(); + + public StandardTexture(String urlName, String filename) { + this.urlName = urlName; + this.makeTexture(urlName, filename); + } + + protected StandardTexture() { + } + + private void makeTexture(String urlName, String filename) { + this.textureID = new ImageConverter(urlName, filename).convert(); + } + + @Override + public String getName() { + return this.urlName; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + s.saveString(this.urlName); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this.urlName = r.restoreString(); + this.makeTexture(this.urlName, this.urlName); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/StandardTextureDecoder.java b/NET/worlds/scape/StandardTextureDecoder.java new file mode 100644 index 0000000..8501008 --- /dev/null +++ b/NET/worlds/scape/StandardTextureDecoder.java @@ -0,0 +1,15 @@ +package NET.worlds.scape; + +class StandardTextureDecoder extends TextureDecoder { + private String exts = "gif;jpg;jpeg;jpe;jfif;xbm"; + + @Override + protected String getExts() { + return this.exts; + } + + @Override + protected Texture read(String urlName, String filename) { + return new StandardTexture(urlName, filename); + } +} diff --git a/NET/worlds/scape/StartupSensor.java b/NET/worlds/scape/StartupSensor.java new file mode 100644 index 0000000..08f8e87 --- /dev/null +++ b/NET/worlds/scape/StartupSensor.java @@ -0,0 +1,41 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class StartupSensor extends Sensor implements FrameHandler { + private boolean hasTriggered = false; + private static Object classCookie = new Object(); + + @Override + public void addAction(Action o) { + this.hasTriggered = false; + super.addAction(o); + } + + @Override + public boolean handle(FrameEvent e) { + if (!this.hasTriggered) { + this.hasTriggered = true; + this.trigger(e); + } + + return true; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/State.java b/NET/worlds/scape/State.java new file mode 100644 index 0000000..93e0cd8 --- /dev/null +++ b/NET/worlds/scape/State.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface State { + Object doState(StateContext var1, Object var2); +} diff --git a/NET/worlds/scape/StateContext.java b/NET/worlds/scape/StateContext.java new file mode 100644 index 0000000..df29a2d --- /dev/null +++ b/NET/worlds/scape/StateContext.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface StateContext { + void changeState(int var1); +} diff --git a/NET/worlds/scape/StdoutAction.java b/NET/worlds/scape/StdoutAction.java new file mode 100644 index 0000000..bbb043f --- /dev/null +++ b/NET/worlds/scape/StdoutAction.java @@ -0,0 +1,96 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class StdoutAction extends Action { + String txt = null; + boolean dumpArg = false; + private static Object classCookie = new Object(); + + public StdoutAction() { + } + + public StdoutAction(String text) { + this.txt = text; + } + + @Override + public Persister trigger(Event arg, Persister seqID) { + if (this.txt != null) { + System.out.println(this.txt); + } else { + System.out.println("StdoutAction " + this.getName() + ", no text!"); + } + + if (this.dumpArg) { + if (arg == null) { + System.out.println("<Null event>"); + } else { + System.out.println("<" + arg + ">"); + } + } + + System.out.flush(); + return null; + } + + @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 = StringPropertyEditor.make(new Property(this, index, "Text Out")); + } else if (mode == 1) { + ret = this.txt; + } else if (mode == 2) { + this.txt = (String)value; + } + break; + case 1: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Dump Event"), "Don't print event", "Print event"); + } else if (mode == 1) { + ret = new Boolean(this.dumpArg); + } else if (mode == 2) { + this.dumpArg = (Boolean)value; + } + break; + default: + ret = super.properties(index, offset + 2, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + super.saveState(s); + s.saveString(this.txt); + s.saveBoolean(this.dumpArg); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this.txt = r.restoreString(); + r.setOldFlag(); + break; + case 1: + super.restoreState(r); + this.txt = r.restoreString(); + this.dumpArg = r.restoreBoolean(); + break; + default: + throw new TooNewException(); + } + } + + @Override + public String toString() { + return super.toString() + "[" + this.txt + "]"; + } +} diff --git a/NET/worlds/scape/StopRecordingAction.java b/NET/worlds/scape/StopRecordingAction.java new file mode 100644 index 0000000..9b63a91 --- /dev/null +++ b/NET/worlds/scape/StopRecordingAction.java @@ -0,0 +1,36 @@ +package NET.worlds.scape; + +import NET.worlds.console.BlackBox; +import java.io.IOException; + +public class StopRecordingAction extends Action { + private static Object classCookie = new Object(); + + @Override + public Persister trigger(Event e, Persister p) { + BlackBox.getInstance().stop(); + return null; + } + + @Override + public Object properties(int index, int offset, int mode, Object value) throws NoSuchPropertyException { + return super.properties(index, offset, mode, value); + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + super.saveState(s); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 1: + super.restoreState(r); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/StringAttribute.java b/NET/worlds/scape/StringAttribute.java new file mode 100644 index 0000000..abbf536 --- /dev/null +++ b/NET/worlds/scape/StringAttribute.java @@ -0,0 +1,81 @@ +package NET.worlds.scape; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class StringAttribute extends Attribute { + String value = ""; + private static Object classCookie = new Object(); + + public StringAttribute(int attrID) { + super(attrID); + } + + public StringAttribute() { + } + + public void set(String x) { + this.value = x; + this.noteChange(); + } + + public String get() { + return this.value; + } + + @Override + public void generateNetData(DataOutputStream s) throws IOException { + s.writeUTF(this.value); + } + + @Override + public void setFromNetData(DataInputStream ds, int len) throws IOException { + this.value = ds.readUTF(); + } + + @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 = StringPropertyEditor.make(new Property(this, index, "value")); + } else if (mode == 1) { + ret = this.get(); + } else if (mode == 2) { + this.set((String)value); + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + s.saveString(this.value); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this.value = r.restoreString(); + this.set(this.value); + return; + default: + throw new TooNewException(); + } + } + + @Override + public String toString() { + return super.toString() + "[" + this.get() + "]"; + } +} diff --git a/NET/worlds/scape/StringFieldEditorDialog.java b/NET/worlds/scape/StringFieldEditorDialog.java new file mode 100644 index 0000000..d027cd8 --- /dev/null +++ b/NET/worlds/scape/StringFieldEditorDialog.java @@ -0,0 +1,31 @@ +package NET.worlds.scape; + +class StringFieldEditorDialog extends FieldEditorDialog { + Property property; + + StringFieldEditorDialog(EditTile parent, String title, Property property) { + super(parent, title); + this.property = property; + this.ready(); + } + + @Override + protected String getValue() { + String s = (String)this.property.get(); + return s != null ? s : ""; + } + + @Override + protected boolean setValue(String text) { + if (text.length() == 0) { + if (!this.property.canSetNull()) { + return false; + } + + text = null; + } + + this.parent.addUndoableSet(this.property, text); + return true; + } +} diff --git a/NET/worlds/scape/StringPropertyEditor.java b/NET/worlds/scape/StringPropertyEditor.java new file mode 100644 index 0000000..f3a90ef --- /dev/null +++ b/NET/worlds/scape/StringPropertyEditor.java @@ -0,0 +1,19 @@ +package NET.worlds.scape; + +import NET.worlds.console.PolledDialog; + +public class StringPropertyEditor extends PropEditor { + private StringPropertyEditor(Property property) { + super(property); + } + + @Override + public PolledDialog edit(EditTile parent, String title) { + return new StringFieldEditorDialog(parent, title, this.property); + } + + public static Property make(Property property) { + property.setPropertyType(3); + return property.setEditor(new StringPropertyEditor(property)); + } +} diff --git a/NET/worlds/scape/StringTexture.java b/NET/worlds/scape/StringTexture.java new file mode 100644 index 0000000..813dfdc --- /dev/null +++ b/NET/worlds/scape/StringTexture.java @@ -0,0 +1,103 @@ +package NET.worlds.scape; + +import java.awt.Color; +import java.io.IOException; + +public class StringTexture extends Texture implements Persister { + private String _text; + private String _font; + private int _size; + private Color _fore; + private Color _back; + private char[] _array; + private int _length; + private static Object classCookie = new Object(); + + static { + nativeInit(); + } + + public StringTexture(String text, String font, int size, Color fore, Color back) { + this._text = text; + this._font = font; + this._size = size; + this._fore = fore; + this._back = back; + this._array = text.toCharArray(); + this._length = text.length(); + this.makeStringTexture(); + } + + protected StringTexture() { + } + + public static native void nativeInit(); + + private native void makeStringTexture(); + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + s.saveString(this._text); + s.saveString(this._font); + s.saveInt(this._size); + s.saveInt(this._fore.getRGB()); + s.saveInt(this._back.getRGB()); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this._text = r.restoreString(); + this._array = this._text.toCharArray(); + this._length = this._text.length(); + this._font = r.restoreString(); + this._size = r.restoreInt(); + this._fore = new Color(r.restoreInt()); + this._back = new Color(r.restoreInt()); + this.makeStringTexture(); + return; + default: + throw new TooNewException(); + } + } + + public String getText() { + return this._text; + } + + public String getFont() { + return this._font; + } + + public int getSize() { + return this._size; + } + + public Color getForegroundColor() { + return this._fore; + } + + public Color getBackgroundColor() { + return this._back; + } + + @Override + public String toString() { + return super.toString() + + "[" + + this._text + + ", Font " + + this._font + + ", Size " + + this._size + + ", Forground " + + this._fore + + ", Background " + + this._back + + "]"; + } +} diff --git a/NET/worlds/scape/SubclumpShape.java b/NET/worlds/scape/SubclumpShape.java new file mode 100644 index 0000000..000786f --- /dev/null +++ b/NET/worlds/scape/SubclumpShape.java @@ -0,0 +1,47 @@ +package NET.worlds.scape; + +public class SubclumpShape extends Shape implements ShapeLoaderListener { + private Material pendingMaterial = null; + private static final boolean debug = false; + + @Override + public void setMaterial(Material m) { + SuperRoot parentObj = this.getOwner(); + if (!(parentObj instanceof Shape)) { + super.setMaterial(m); + } else { + Shape parent = (Shape)parentObj; + if (!parent.isFullyLoaded()) { + parent.addLoadListener(this); + this.pendingMaterial = m; + } else { + super.setMaterial(m); + } + } + } + + @Override + protected synchronized void addRwChildren(WObject container) { + SuperRoot o = this.getOwner(); + if (o instanceof Shape) { + Shape parent = (Shape)o; + if (!parent.isFullyLoaded()) { + this.setState(LOADING, null); + parent.addLoadListener(this); + } + } + + super.addRwChildren(container); + } + + @Override + public void notifyShapeLoaded(Shape s) { + this.setState(NORMAL, null); + this.shapeRedraw(); + if (this.pendingMaterial != null) { + super.setMaterial(this.pendingMaterial); + } + + this.pendingMaterial = null; + } +} diff --git a/NET/worlds/scape/SuperRoot.java b/NET/worlds/scape/SuperRoot.java new file mode 100644 index 0000000..384bf05 --- /dev/null +++ b/NET/worlds/scape/SuperRoot.java @@ -0,0 +1,388 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.network.URL; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.Enumeration; +import java.util.Hashtable; + +public class SuperRoot implements Properties, Persister { + private String name; + protected static String helpURL = "home:internal/"; + private SuperRoot owner; + protected URL sourceURL; + private static Object classCookie = new Object(); + static Hashtable<Class<? extends Object>, Integer> finalizedClasses = new Hashtable<Class<? extends Object>, Integer>(); + static Hashtable<Class<? extends Object>, Integer> classCounter = new Hashtable<Class<? extends Object>, Integer>(); + + public final String getShortClassName() { + String s = this.getClass().getName(); + int index; + if ((index = s.lastIndexOf(46)) != -1) { + s = s.substring(index + 1); + } + + return s; + } + + public String getName() { + if (this.name == null) { + int digits = 0; + String classname = this.getShortClassName(); + Enumeration<Object> en = this.getRoot().getDeepOwned(); + + while (en.hasMoreElements()) { + SuperRoot x = (SuperRoot)en.nextElement(); + if (x.name != null && x.name.startsWith(classname)) { + try { + int tmp = Integer.valueOf(x.name.substring(classname.length())); + if (tmp > digits) { + digits = tmp; + } + } catch (NumberFormatException var6) { + } + } + } + + this.name = classname + ++digits; + } + + return this.name; + } + + public String getNameMaybeNull() { + return this.name; + } + + public void setName(String v) { + if (v == null && this.owner != null) { + Object[] arguments = new Object[]{new String(this.owner.getName())}; + Console.println(MessageFormat.format(Console.message("Warning-null-name"), arguments)); + } + + this.name = v; + } + + public static SuperRoot nameSearch(Enumeration<?> enumeration, String name) { + while (enumeration.hasMoreElements()) { + SuperRoot n = (SuperRoot)enumeration.nextElement(); + if (name.equals(n.name)) { + return n; + } + } + + return null; + } + + public URL getHelpURL() { + String helpString = helpURL + this.getClass().getName() + Console.message(".html"); + URL helpPage = URL.make(helpString); + if (Console.wasHttpNoSuchFile(helpString)) { + helpPage = URL.make(helpURL + this.getClass().getName() + ".html"); + } + + return helpPage; + } + + public URL getHelpURL(Property p) { + String namesub = p.getName().replace(' ', '_'); + String helpString = helpURL + this.getClass().getName() + "#" + namesub + Console.message(".html"); + URL helpPage = URL.make(helpString); + if (Console.wasHttpNoSuchFile(helpString)) { + helpPage = URL.make(helpURL + this.getClass().getName() + "#" + namesub + ".html"); + } + + return helpPage; + } + + @Override + public String toString() { + return this.isActive() ? this.getName() : this.getName() + "(inactive)"; + } + + @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 = StringPropertyEditor.make(new Property(this, index, "Name")); + } else if (mode == 1) { + ret = this.getName(); + } else if (mode == 4) { + this.setName(null); + } else if (mode == 2) { + String s = (String)value; + if (!s.equals(this.name) && this.owner != null && nameSearch(this.getRoot().getDeepOwned(), s) != null) { + Object[] arguments = new Object[]{new String(s), new String(this.getRoot().getName())}; + Console.println(MessageFormat.format(Console.message("Name-in-use"), arguments)); + } else { + this.setName((String)value); + } + } + break; + case 1: + if (mode == 0) { + ret = URLPropertyEditor.make(new Property(this, index, "Source URL").allowSetNull(), "*wob", false); + } else if (mode == 1) { + ret = this.sourceURL; + } else if (mode == 2) { + this.setSourceURL((URL)value); + } + break; + default: + throw new NoSuchPropertyException(); + } + + return ret; + } + + @Override + public Object propertyParent() { + return this.owner; + } + + public SuperRoot getOwner() { + return this.owner; + } + + public void discard() { + this.detach(); + } + + protected void add(SuperRoot x) { + if (x.owner != null && x.owner != this) { + System.out.println("double-setting owner of " + x + " from " + x.owner + " to " + this); + throw new Error("double-setting owner of " + x); + } else { + x.noteAddingTo(this); + x.owner = this; + } + } + + public void detach() { + if (this.owner != null) { + this.owner.noteUnadding(this); + this.owner = null; + } + } + + protected void noteAddingTo(SuperRoot s) { + } + + protected void noteUnadding(SuperRoot s) { + } + + public Enumeration<Object> getOwned() { + return new ShallowEnumeration(this); + } + + public Enumeration<Object> getDeepOwned() { + return new DeepEnumeration<Object>(this); + } + + public void getChildren(DeepEnumeration<?> d) { + } + + public World getWorld() { + SuperRoot owner = this.getOwner(); + return owner == null ? null : owner.getWorld(); + } + + public Room getRoom() { + SuperRoot owner = this.getOwner(); + return owner == null ? null : owner.getRoom(); + } + + public SuperRoot getRoot() { + SuperRoot owner = this.getOwner(); + return owner == null ? this : owner.getRoot(); + } + + public boolean isActive() { + return this.getWorld() != null; + } + + public URL getSourceURL() { + return this.sourceURL; + } + + public void setSourceURL(URL s) { + this.sourceURL = s; + } + + public URL getContainingSourceURL() { + if (this.sourceURL != null) { + return this.sourceURL; + } else { + return this.owner != null ? this.owner.getContainingSourceURL() : null; + } + } + + public void markEdited() { + if (this.owner != null) { + this.owner.markEdited(); + } + } + + public static SuperRoot readFile(String urlLocal, URL url) { + try { + Restorer r = new Restorer(urlLocal, url); + SuperRoot o = (SuperRoot)r.restore(); + r.done(); + o.setSourceURL(url); + return o; + } catch (FileNotFoundException var5) { + } catch (ClassCastException var6) { + } catch (IOException var7) { + } catch (TooNewException var8) { + } catch (BadFormatException var9) { + } + + return null; + } + + public static SuperRoot readFile(URL url) { + return readFile(url.unalias(), url); + } + + public void loadInit() { + } + + public void saveFile(URL url) throws IOException { + if (this instanceof NonPersister) { + throw new IOException("Can't save NonPersister"); + } else { + Saver s = new Saver(url); + s.save(this); + s.done(); + this.setSourceURL(url); + } + } + + @Override + public Object clone() { + byte[] b = this.getByteCopy(); + return getCopyFromBytes(b); + } + + public byte[] getByteCopy() { + if (this instanceof NonPersister) { + return null; + } else { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + + try { + Saver saver = new Saver(new DataOutputStream(buffer)); + saver.save(this); + saver.done(); + return buffer.toByteArray(); + } catch (Exception var3) { + var3.printStackTrace(System.out); + throw new Error("Can't save"); + } + } + } + + public static SuperRoot getCopyFromBytes(byte[] b) { + if (b == null) { + return null; + } else { + try { + Restorer r = new Restorer(new DataInputStream(new ByteArrayInputStream(b))); + SuperRoot obj = (SuperRoot)r.restore(); + r.done(); + return obj; + } catch (Exception var3) { + var3.printStackTrace(System.out); + throw new Error("Can't restore"); + } + } + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(2, classCookie); + s.saveString(this.name); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + this.restoreStateSuperRoot(r); + } + + protected final void restoreStateSuperRoot(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + r.setOldFlag(); + case 2: + String n; + if ((n = r.restoreString()) != null) { + this.setName(n); + } + break; + case 1: + r.setOldFlag(); + String nx; + if ((nx = r.restoreString()) != null) { + this.setName(nx); + } + + r.restoreMaybeNull(); + break; + default: + throw new TooNewException(); + } + } + + @Override + public void postRestore(int version) { + } + + public static void finalizeCounter(Object o) { + Class<? extends Object> c = (Class<? extends Object>)o.getClass(); + Integer icnt = finalizedClasses.get(c); + int cnt = 0; + if (icnt != null) { + cnt = icnt; + } + + if (++cnt == 1000) { + System.out.println("Finalized 1000 times: " + c); + cnt = 0; + } + + finalizedClasses.put((Class<? extends Object>)o.getClass(), new Integer(cnt)); + } + + @Override + protected void finalize() { + } + + public static void countClass(Object o, int inc) { + Class<? extends Object> c = (Class<? extends Object>)o.getClass(); + Integer icnt = classCounter.get(c); + int cnt = 0; + if (icnt != null) { + cnt = icnt; + } + + cnt += inc; + classCounter.put(c, new Integer(cnt)); + } + + public static void printClassCounts() { + Enumeration<Class<? extends Object>> e = classCounter.keys(); + + while (e.hasMoreElements()) { + Class<?> c = e.nextElement(); + System.out.println("Class " + c.getName() + " has " + classCounter.get(c)); + } + } +} diff --git a/NET/worlds/scape/Surface.java b/NET/worlds/scape/Surface.java new file mode 100644 index 0000000..61fce10 --- /dev/null +++ b/NET/worlds/scape/Surface.java @@ -0,0 +1,190 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import java.awt.Color; +import java.io.IOException; +import java.text.MessageFormat; + +public class Surface extends WObject implements Animatable { + private int[] polygonIDs; + protected Material material; + private static Object classCookie = new Object(); + + static { + nativeInit(); + } + + public Surface(Material m) { + if (m != null && m.getOwner() != null) { + m = (Material)m.clone(); + } + + this.setMaterial(m); + } + + Surface() { + } + + public static native void nativeInit(); + + @Override + public void loadInit() { + this.setMaterial(null); + } + + @Override + protected void markVoid() { + super.markVoid(); + this.polygonIDs = null; + this.material.markVoid(); + } + + @Override + public void recursiveAddRwChildren(WObject container) { + this.material.addRwChildren(); + super.recursiveAddRwChildren(container); + int hres = this.material.getHRes(); + int vres = this.material.getVRes(); + int numVerts = this.getNumVerts(); + if (numVerts != 4 || !this.material.getHiRes() && !this.uvOutOfRange()) { + assert numVerts > 0; + + int[] vi = new int[numVerts]; + + for (int i = 0; i < numVerts; i++) { + vi[i] = i + 1; + } + + this.polygonIDs = new int[1]; + this.addPolygon(vi); + } else { + int numTiles = this.addSubPolys(hres, vres); + if (numTiles >= 100 && Console.getFrame().isShaperVisible()) { + Object[] arguments = new Object[]{new Integer(numTiles), new String(this.getRoom().getName()), new String(this.getName())}; + Console.println(MessageFormat.format(Console.message("Memory-hog"), arguments)); + } + } + + this.nativeSetMaterial(); + this.doneWithEditing(); + } + + protected void setVFlip(boolean b) { + if (b) { + this.flags |= 1048576; + } else { + this.flags &= -1048577; + } + } + + protected void setUFlip(boolean b) { + if (b) { + this.flags |= 524288; + } else { + this.flags &= -524289; + } + } + + protected boolean getUFlip() { + return (this.flags & 524288) != 0; + } + + protected boolean getVFlip() { + return (this.flags & 1048576) != 0; + } + + @Override + public void setMaterial(Material m) { + this.setMaterial(m, false); + } + + public void setMaterial(Material m, boolean forceReload) { + if (m == null) { + m = new Material(new Color((int)(Math.random() * 1.6777216E7))); + } else if (this.material == m && !forceReload) { + return; + } + + boolean sameSize = this.polygonIDs != null + && this.polygonIDs.length >= 1 + && this.material.getHRes() == m.getHRes() + && this.material.getVRes() == m.getVRes(); + if (this.material != m) { + if (this.material != null) { + this.material.detach(); + } + + this.add(m); + this.material = m; + } + + if (this.polygonIDs != null) { + if (sameSize) { + this.nativeSetMaterial(); + } else { + this.reclump(); + } + } + } + + private native void nativeSetMaterial(); + + private native boolean uvOutOfRange(); + + public Material getMaterial() { + return this.material; + } + + native void addVertex(float var1, float var2, float var3, float var4, float var5); + + native void addPolygon(int[] var1); + + private native int addSubPolys(int var1, int var2); + + @Override + public void getChildren(DeepEnumeration d) { + super.getChildren(d); + d.addChildElement(this.material); + } + + @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 = new Property(this, index, "Material"); + } else if (mode == 1) { + ret = this.material; + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + super.saveState(s); + s.save(this.material); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this.setMaterial(Material.restore(r)); + break; + case 1: + super.restoreState(r); + this.setMaterial((Material)r.restore()); + break; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/SwitchableBehavior.java b/NET/worlds/scape/SwitchableBehavior.java new file mode 100644 index 0000000..645c6c4 --- /dev/null +++ b/NET/worlds/scape/SwitchableBehavior.java @@ -0,0 +1,62 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class SwitchableBehavior extends SuperRoot { + protected boolean enabled = true; + private static Object classCookie = new Object(); + + public boolean getEnabled() { + return this.enabled; + } + + public SwitchableBehavior setEnabled(boolean s) { + this.enabled = s; + return this; + } + + public SwitchableBehavior toggleEnabled() { + this.setEnabled(!this.getEnabled()); + return this; + } + + @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 = BooleanPropertyEditor.make(new Property(this, index, "Enabled"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.enabled); + } else if (mode == 2) { + this.enabled = (Boolean)value; + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + super.saveState(s); + s.saveBoolean(this.enabled); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 1: + super.restoreState(r); + case 0: + this.enabled = r.restoreBoolean(); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/TCompressor.java b/NET/worlds/scape/TCompressor.java new file mode 100644 index 0000000..d9411dd --- /dev/null +++ b/NET/worlds/scape/TCompressor.java @@ -0,0 +1,465 @@ +package NET.worlds.scape; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class TCompressor { + private static final int CMAP_MAXPOSCOMP = 128; + private static final int CMAP_DEFAULTAXIS = 0; + private static final int CMAP_XUNITARY = 32; + private static final int CMAP_YUNITARY = 64; + private static final int CMAP_ZUNITARY = 96; + private static final int CMAP_ROTATION = 16; + private static final int CMAP_ROTSIGN1 = 8; + private static final int CMAP_ROTSIGN2 = 4; + private static final int CMAP_SCALE = 2; + private static final int CMAP_UNIFORMSCALE = 1; + private static final int MODE_SENDCMAP = 8388608; + private static final int MODE_SENDZ = 4194304; + private static final int MODE_MAXPOSCOMP = 128; + private static final int MODE_SENDROTAXIS = 96; + private static final int MODE_SENDROTATION = 16; + private static final int MODE_SENDSCALE = 2; + public static final int USER_SEND_POSITION = 32768; + public static final int USER_SEND_ROTATION = 16384; + public static final int USER_SEND_SCALE = 8192; + public static final int USER_SEND_ALL = 57344; + private static final int LOW21BITSMASK = 2097151; + private static final int LOW18BITSMASK = 262143; + private static final int LOW12BITSMASK = 4095; + private static final int LOW10BITSMASK = 1023; + private static final int LOW8BITSMASK = 255; + private static final int BIT20 = 1048576; + private static final double SCFACT = 16.0; + private static final double SCOFFSET = 121.6; + static int wroteBytes = 0; + public static boolean dontSend = false; + + public static void compress(WObject w, Point3Temp defPos, Point3Temp defRAxis, float defRotation, Point3Temp defScale, int inputModes, DataOutputStream ds) throws IOException { + Point3Temp pos = w.getPosition(); + Point3Temp rAxis = Point3Temp.make(); + float rotation = w.getSpin(rAxis); + Point3Temp scale = w.getScale(); + if (dontSend) { + System.err.println("DONTSEND is TRUE on COMPRESS CALL"); + } else { + int mode = inputModes; + if ((inputModes & 32768) != 0) { + if (pos.x >= 0.0F && pos.x <= 4095.0 && pos.y >= 0.0F && pos.y <= 4095.0 && (pos.z >= 0.0F && pos.z <= 255.0 || pos.z == defPos.z)) { + mode = inputModes | 128; + } + + if (pos.z != defPos.z) { + mode |= 4194304; + } + } + + int outaxis1 = 0; + int outaxis2 = 0; + if ((mode & 16384) != 0 && !rAxis.sameValue(defRAxis)) { + int axisFlag = 0; + float maxAxis = rAxis.x; + int var24 = 32; + if (Math.abs(rAxis.y) > Math.abs(maxAxis)) { + maxAxis = rAxis.y; + var24 = 64; + } + + if (Math.abs(rAxis.z) > Math.abs(maxAxis)) { + maxAxis = rAxis.z; + var24 = 96; + } + + rAxis.x /= maxAxis; + rAxis.y /= maxAxis; + rAxis.z /= maxAxis; + mode |= var24; + if (maxAxis < 0.0F) { + rotation *= -1.0F; + } + + switch (var24) { + case 32: + if (rAxis.y < 0.0F) { + mode |= 8; + } + + if (rAxis.z < 0.0F) { + mode |= 4; + } + + outaxis1 = Math.round(Math.abs(255.0F * rAxis.y)); + outaxis2 = Math.round(Math.abs(255.0F * rAxis.z)); + break; + case 64: + if (rAxis.x < 0.0F) { + mode |= 8; + } + + if (rAxis.z < 0.0F) { + mode |= 4; + } + + outaxis1 = Math.round(Math.abs(255.0F * rAxis.x)); + outaxis2 = Math.round(Math.abs(255.0F * rAxis.z)); + break; + case 96: + if (rAxis.x < 0.0F) { + mode |= 8; + } + + if (rAxis.y < 0.0F) { + mode |= 4; + } + + outaxis1 = Math.round(Math.abs(255.0F * rAxis.x)); + outaxis2 = Math.round(Math.abs(255.0F * rAxis.y)); + } + + if (outaxis1 == 0 && outaxis2 == 0 && maxAxis < 0.0F) { + mode |= 8; + mode |= 4; + } + + while (rotation >= 360.0F) { + rotation -= 360.0F; + } + + while (rotation < 0.0F) { + rotation += 360.0F; + } + + if (rotation != defRotation) { + mode |= 8388608; + mode |= 16; + } + } + + if ((mode & 8192) != 0 && !scale.sameValue(defScale)) { + mode |= 8388608; + mode |= 2; + if (scale.x == scale.y && scale.x == scale.z) { + mode |= 1; + } + } + + if ((mode & 8388608) != 0) { + ds.writeByte(mode & 0xFF); + wroteBytes++; + } + + if ((mode & 32768) != 0) { + if ((mode & 128) != 0) { + maxCompressXY(pos.x, pos.y, ds); + if ((mode & 4194304) != 0 || (mode & 8388608) != 0) { + short iz = (short)Math.round(pos.z); + int outbyte = iz & 255; + ds.writeByte(outbyte); + wroteBytes++; + } + } else { + minCompressXYZ(pos.x, pos.y, pos.z, ds); + } + } + + if ((mode & 96) != 0) { + ds.writeByte(outaxis1); + ds.writeByte(outaxis2); + wroteBytes += 2; + } + + if ((mode & 16) != 0) { + int outbyte = (int)Math.round(256.0 * (rotation / 360.0)); + ds.writeByte(outbyte); + wroteBytes++; + } + + if ((mode & 2) != 0) { + double y = 16.0 * Math.log(scale.x / defScale.x) + 121.6; + if (y < 0.0) { + y = 0.0; + } + + if (y > 255.0) { + y = 255.0; + } + + int outbyte = (int)Math.round(y); + ds.writeByte(outbyte); + wroteBytes++; + if ((mode & 1) == 0) { + y = 16.0 * Math.log(scale.y / defScale.y) + 121.6; + if (y < 0.0) { + y = 0.0; + } + + if (y > 255.0) { + y = 255.0; + } + + outbyte = (int)Math.round(y); + ds.writeByte(outbyte); + wroteBytes++; + y = 16.0 * Math.log(scale.z / defScale.z) + 121.6; + if (y < 0.0) { + y = 0.0; + } + + if (y > 255.0) { + y = 255.0; + } + + outbyte = (int)Math.round(y); + ds.writeByte(outbyte); + wroteBytes++; + } + } + + wroteBytes = 0; + } + } + + private static void maxCompressXY(float x, float y, DataOutputStream ds) throws IOException { + short ix = (short)Math.round(x); + short iy = (short)Math.round(y); + ix = (short)(ix & 4095); + iy = (short)(iy & 4095); + int posbyte = ix >>> 4; + ds.writeByte(posbyte); + wroteBytes++; + ix = (short)(ix << 4); + ix = (short)(ix & 255); + posbyte = ix | iy >>> 8; + ds.writeByte(posbyte); + wroteBytes++; + posbyte = iy & 255; + ds.writeByte(posbyte); + wroteBytes++; + } + + private static void minCompressXYZ(float x, float y, float z, DataOutputStream ds) throws IOException { + int xval = floatTo21bits(x); + int yval = floatTo21bits(y); + int zval = floatTo21bits(z); + int outbits = xval << 10 | yval >>> 11; + ds.writeInt(outbits); + wroteBytes += 4; + outbits = yval << 21 | zval; + ds.writeInt(outbits); + wroteBytes += 4; + } + + private static int floatTo21bits(float f) { + for (int e = 0; e <= 3; e++) { + double decimal = Math.pow(10.0, e - 2); + float limit = (float)(262144.0 * decimal); + float af = Math.abs(f); + if (af < limit || e == 3) { + int m = (int)Math.round(af / decimal); + m &= 262143; + m <<= 2; + m |= e; + if (f < 0.0F) { + m |= 1048576; + } + + return m; + } + } + + return 0; + } + + public static void decompress( + WObject w, Point3Temp defPos, Point3Temp defRAxis, float defRotation, Point3Temp defScale, int inputModes, int len, DataInputStream ds + ) throws IOException { + Point3Temp pos = w.getPosition(); + Point3Temp rAxis = Point3Temp.make(); + float rotation = w.getSpin(rAxis); + Point3Temp scale = w.getScale(); + dontSend = true; + if (len == 0) { + w.moveTo(defPos); + scale.x = defScale.x / scale.x; + scale.y = defScale.y / scale.y; + scale.z = defScale.z / scale.z; + w.scale(scale); + dontSend = false; + } else if (len == 24) { + pos.x = ds.readFloat(); + pos.y = ds.readFloat(); + pos.z = ds.readFloat(); + scale.x = ds.readFloat() / scale.x; + scale.y = ds.readFloat() / scale.y; + scale.z = ds.readFloat() / scale.z; + w.moveTo(pos); + w.scale(scale); + dontSend = false; + } else { + int mode; + if (len > 4) { + mode = inputModes | 8388608; + } else { + mode = inputModes | 128; + } + + if (len == 4) { + mode |= 4194304; + } + + if ((mode & 8388608) != 0) { + int inbyte = ds.readUnsignedByte(); + mode |= inbyte; + mode |= 4194304; + } + + if ((mode & 32768) != 0) { + if ((mode & 128) != 0) { + pos = maxDecompressXY(pos, ds); + if ((mode & 4194304) != 0) { + int iz = ds.readUnsignedByte(); + pos.z = iz; + } + } else { + pos = minDecompressXYZ(pos, ds); + } + + w.moveTo(pos); + } + + if ((mode & 8388608) == 0) { + dontSend = false; + } else { + if ((mode & 16) != 0) { + w.spin(rAxis.x, rAxis.y, rAxis.z, -rotation); + } + + rAxis.x = defRAxis.x; + rAxis.y = defRAxis.y; + rAxis.z = defRAxis.z; + if ((mode & 96) != 0) { + int inaxis1 = ds.readUnsignedByte(); + int inaxis2 = ds.readUnsignedByte(); + switch (mode & 96) { + case 0: + default: + break; + case 32: + rAxis.x = 1.0F; + rAxis.y = (float)(inaxis1 / 255.0); + rAxis.z = (float)(inaxis2 / 255.0); + if ((mode & 8) != 0) { + rAxis.y = (float)(rAxis.y * -1.0); + } + + if ((mode & 4) != 0) { + rAxis.z = (float)(rAxis.z * -1.0); + } + + if (rAxis.y == 0.0F && rAxis.z == 0.0F && (mode & 8) != 0 && (mode & 4) != 0) { + rAxis.x = -1.0F; + } + break; + case 64: + rAxis.y = 1.0F; + rAxis.x = (float)(inaxis1 / 255.0); + rAxis.z = (float)(inaxis2 / 255.0); + if ((mode & 8) != 0) { + rAxis.x = (float)(rAxis.x * -1.0); + } + + if ((mode & 4) != 0) { + rAxis.z = (float)(rAxis.z * -1.0); + } + + if (rAxis.x == 0.0F && rAxis.z == 0.0F && (mode & 8) != 0 && (mode & 4) != 0) { + rAxis.y = -1.0F; + } + break; + case 96: + rAxis.z = 1.0F; + rAxis.x = (float)(inaxis1 / 255.0); + rAxis.y = (float)(inaxis2 / 255.0); + if ((mode & 8) != 0) { + rAxis.x = (float)(rAxis.x * -1.0); + } + + if ((mode & 4) != 0) { + rAxis.y = (float)(rAxis.y * -1.0); + } + + if (rAxis.x == 0.0F && rAxis.y == 0.0F && (mode & 8) != 0 && (mode & 4) != 0) { + rAxis.z = -1.0F; + } + } + } + + if ((mode & 16) != 0) { + int inbyte = ds.readUnsignedByte(); + rotation = (float)(360.0 * (inbyte / 256.0)); + w.worldSpin(rAxis.x, rAxis.y, rAxis.z, rotation); + } + + if ((mode & 2) != 0) { + int inbyte = ds.readUnsignedByte(); + double s = defScale.x * Math.exp((inbyte - 121.6) / 16.0); + scale.x = (float)s; + if ((mode & 1) != 0) { + scale.y = scale.x; + scale.z = scale.x; + } else { + inbyte = ds.readUnsignedByte(); + s = defScale.y * Math.exp((inbyte - 121.6) / 16.0); + scale.y = (float)s; + inbyte = ds.readUnsignedByte(); + s = defScale.z * Math.exp((inbyte - 121.6) / 16.0); + scale.z = (float)s; + } + + Point3Temp oldScale = w.getScale(); + scale.x = scale.x / oldScale.x; + scale.y = scale.y / oldScale.y; + scale.z = scale.z / oldScale.z; + w.scale(scale); + } + + dontSend = false; + } + } + } + + private static Point3Temp maxDecompressXY(Point3Temp pos, DataInputStream ds) throws IOException { + int ix = ds.readUnsignedByte(); + ix <<= 4; + int iy = ds.readUnsignedByte(); + ix |= iy >>> 4; + iy &= 15; + iy <<= 8; + iy |= ds.readUnsignedByte(); + pos.x = ix; + pos.y = iy; + return pos; + } + + private static Point3Temp minDecompressXYZ(Point3Temp pos, DataInputStream ds) throws IOException { + int i1 = ds.readInt(); + int i2 = ds.readInt(); + int tmp = i1 >>> 10; + pos.x = floatFrom21bits(tmp); + tmp = (i1 & 1023) << 11; + tmp |= i2 >>> 21; + pos.y = floatFrom21bits(tmp); + tmp = i2 & 2097151; + pos.z = floatFrom21bits(tmp); + return pos; + } + + private static float floatFrom21bits(int bits) { + int e = bits & 3; + int s = (bits & 1048576) << 11 | 1; + int m = (bits & -1048577) >>> 2; + double d = Math.pow(10.0, e - 2); + return (float)(m * d * s); + } +} diff --git a/NET/worlds/scape/TabbedDisplayPanel.java b/NET/worlds/scape/TabbedDisplayPanel.java new file mode 100644 index 0000000..c5b99f8 --- /dev/null +++ b/NET/worlds/scape/TabbedDisplayPanel.java @@ -0,0 +1,98 @@ +package NET.worlds.scape; + +import java.awt.CardLayout; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Panel; +import java.awt.Point; +import java.util.Vector; + +class TabbedDisplayPanel extends Panel { + private int count; + private Vector cards = new Vector(); + private Vector cardNames = new Vector(); + + TabbedDisplayPanel() { + this.setLayout(new CardLayout()); + } + + void addItem(Component c) { + this.insertItem(this.cards.size(), c); + } + + void insertItem(int index, Component c) { + String cardName = "" + this.count++; + this.cardNames.insertElementAt(cardName, index); + this.cards.insertElementAt(c, index); + this.add(cardName, c); + this.validate(); + this.repaint(); + } + + void removeItem(int index) { + this.remove((Component)this.cards.elementAt(index)); + this.cards.removeElementAt(index); + this.cardNames.removeElementAt(index); + } + + @Override + public Component getComponent(int index) { + return (Component)this.cards.elementAt(index); + } + + void setChoice(int index) { + ((CardLayout)this.getLayout()).show(this, (String)this.cardNames.elementAt(index)); + } + + @Override + public Insets insets() { + return new Insets(0, 2, 2, 0); + } + + @Override + public void paint(Graphics g) { + g.setColor(this.getBackground()); + if (this.cards.size() != 0) { + Dimension size = this.size(); + vLine(g, 1, 0, size.height); + g.setColor(this.getBackground().brighter()); + vLine(g, 0, 0, size.height - 2); + g.setColor(this.getBackground().darker()); + hLine(g, 0, size.height - 1, size.width - 1); + vLine(g, size.width - 1, size.height - 1, 0); + hLine(g, 1, size.height - 2, size.width - 2); + vLine(g, size.width - 2, size.height - 2, 0); + } else { + g.fillRect(0, 0, this.size().width, this.size().height); + } + } + + private static void vLine(Graphics g, int x1, int y1, int y2) { + g.drawLine(x1, y1, x1, y2); + } + + private static void hLine(Graphics g, int x1, int y1, int x2) { + g.drawLine(x1, y1, x2, y1); + } + + @Override + public Component locate(int x, int y) { + if (!this.inside(x, y)) { + return null; + } else { + int n = this.countComponents(); + + for (int i = 0; i < n; i++) { + Component c = this.getComponent(i); + Point loc = c.location(); + if (c != null && c.isVisible() && c.inside(x - loc.x, y - loc.y)) { + return c; + } + } + + return this; + } + } +} diff --git a/NET/worlds/scape/TabbedPanel.java b/NET/worlds/scape/TabbedPanel.java new file mode 100644 index 0000000..3e7b3fd --- /dev/null +++ b/NET/worlds/scape/TabbedPanel.java @@ -0,0 +1,274 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.DialogDisabled; +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Panel; +import java.awt.Point; +import java.util.Vector; + +public class TabbedPanel extends Panel implements ClickEventHandler, DialogDisabled { + private Vector entries = new Vector(); + private int rows; + private int itemWidth; + private int itemHeight; + private int itemsPerRow; + private int choice; + private Font nFont; + private FontMetrics nFontMetrics; + private Font bFont; + private FontMetrics bFontMetrics; + private int fontHeight; + private TabbedDisplayPanel disp = new TabbedDisplayPanel(); + private ClickEventHandler handler; + private boolean needRecalc; + private boolean isDialogDisabled; + + public TabbedPanel(ClickEventHandler handler) { + this.handler = handler; + this.setLayout(new BorderLayout()); + this.add("Center", this.disp); + } + + public TabbedPanel() { + this(null); + this.handler = this; + } + + public void addItem(String name, Component c) { + this.entries.addElement(name); + this.needRecalc = true; + this.repaint(); + this.disp.addItem(c); + } + + public void insertItem(int index, String name, Component c) { + this.entries.insertElementAt(name, index); + this.disp.insertItem(index, c); + if (index <= this.choice) { + this.choice = Math.min(this.choice + 1, this.entries.size() - 1); + } + + this.needRecalc = true; + this.repaint(); + } + + public void removeItem(int index) { + this.entries.removeElementAt(index); + this.disp.removeItem(index); + if (index == this.choice) { + int count = this.entries.size(); + if (count > 0) { + this.choice = Math.min(this.choice, count - 1); + this.disp.setChoice(this.choice); + } + } else if (index < this.choice) { + this.choice--; + } + + this.needRecalc = true; + this.repaint(); + } + + public void select(int index) { + this.choice = index; + this.repaint(); + this.disp.setChoice(index); + } + + public String getName(int index) { + return (String)this.entries.elementAt(index); + } + + public void setName(int index, String name) { + this.entries.setElementAt(name, index); + this.needRecalc = true; + this.repaint(); + } + + @Override + public Component getComponent(int index) { + return index < this.entries.size() ? this.disp.getComponent(index) : null; + } + + public int selected() { + return this.choice; + } + + public int itemAt(Point p) { + if (!this.needRecalc) { + Point tab = new Point(0, 0); + int count = this.entries.size(); + + for (int i = 0; i < count; i++) { + this.getPosition(i, tab); + if (p.x >= tab.x && p.y >= tab.y && p.x < tab.x + this.itemWidth && p.y < tab.y + this.itemHeight) { + return i; + } + } + } + + return -1; + } + + @Override + public void addNotify() { + super.addNotify(); + this.nFont = new Font(Console.message("NotifyFont"), 0, 13); + this.nFontMetrics = this.getFontMetrics(this.nFont); + this.bFont = new Font(Console.message("NotifyFont"), 1, 14); + this.bFontMetrics = this.getFontMetrics(this.bFont); + this.fontHeight = Math.max(this.nFontMetrics.getHeight(), this.bFontMetrics.getHeight()); + this.itemHeight = this.fontHeight + 5; + } + + @Override + public Insets insets() { + if (this.needRecalc) { + this.recalc(); + } + + return new Insets(this.rows * this.itemHeight, 0, 0, 0); + } + + @Override + public void reshape(int x, int y, int width, int height) { + super.reshape(x, y, width, height); + this.needRecalc = true; + this.repaint(); + } + + private void recalc() { + int row = 0; + int itemsOnRow = 0; + int x = 0; + int count = this.entries.size(); + this.itemWidth = 0; + + for (int i = 0; i < count; i++) { + String name = (String)this.entries.elementAt(i); + int w = Math.max(this.bFontMetrics.stringWidth(name), this.nFontMetrics.stringWidth(" " + name + " ")); + this.itemWidth = Math.max(w, this.itemWidth); + } + + this.itemWidth += 4; + this.itemsPerRow = Math.max(1, this.size().width / this.itemWidth); + this.rows = (count + this.itemsPerRow - 1) / this.itemsPerRow; + this.needRecalc = false; + this.invalidate(); + this.validate(); + } + + private void getPosition(int entry, Point pos) { + int count = this.entries.size(); + int firstRow = this.choice / this.itemsPerRow; + int entryRow = entry / this.itemsPerRow; + int column = entry - entryRow * this.itemsPerRow; + pos.x = column * this.itemWidth; + pos.y = (this.rows - 1 - entryRow) * this.itemHeight - 2; + } + + private static void vLine(Graphics g, int x1, int y1, int y2) { + g.drawLine(x1, y1, x1, y2); + } + + private static void hLine(Graphics g, int x1, int y1, int x2) { + g.drawLine(x1, y1, x2, y1); + } + + @Override + public void paint(Graphics g) { + if (this.needRecalc) { + this.recalc(); + } + + g.setColor(this.getBackground()); + g.fillRect(0, 0, this.size().width, this.size().height); + int count = this.entries.size(); + if (count != 0) { + Point p = new Point(0, 0); + int maxWidth = this.itemWidth - 4; + + for (int i = 0; i < count; i++) { + this.getPosition(i, p); + String ent = (String)this.entries.elementAt(i); + int x1 = p.x; + int y1 = p.y + 4; + int y2 = y1 + this.fontHeight; + int yFont = y1; + Font font = this.nFont; + FontMetrics fm = this.nFontMetrics; + boolean selected = i == this.choice; + if (selected) { + y1 = p.y + 2; + y2 = y1 + this.fontHeight + 4; + yFont = y1 + 1; + font = this.bFont; + fm = this.bFontMetrics; + } + + int width = fm.stringWidth(ent); + int spacing = (maxWidth - width) / 2; + int x2 = x1 + maxWidth; + g.setFont(font); + g.setColor(this.getBackground().brighter()); + if (selected) { + hLine(g, 0, y2, x1); + hLine(g, x2 + 3, y2, this.size().width); + } + + vLine(g, x1, y2, y1 + 2); + g.drawLine(x1, y1 + 2, x1 + 2, y1); + hLine(g, x1 + 2, y1, x2); + g.setColor(this.getBackground().darker()); + vLine(g, x2 + 1, y1 + 1, y2); + vLine(g, x2 + 2, y1 + 2, y2); + g.setColor(this.getForeground()); + g.drawString(ent, x1 + 1 + spacing, yFont + fm.getAscent() + fm.getLeading()); + } + } + } + + @Override + public void clickEvent(Component who, Point location, int flags) { + } + + @Override + public boolean mouseDown(java.awt.Event event, int x, int y) { + Point p = new Point(x, y); + int tmp = this.itemAt(p); + if (tmp != -1) { + this.choice = tmp; + this.repaint(); + this.disp.setChoice(this.choice); + int flags = 1; + if (event.metaDown()) { + flags |= 4; + } + + this.handler.clickEvent(this, p, flags); + return true; + } else { + return false; + } + } + + @Override + public boolean handleEvent(java.awt.Event event) { + return this.isDialogDisabled ? false : super.handleEvent(event); + } + + @Override + public void dialogDisable(boolean disable) { + this.isDialogDisabled = disable; + Component c = this.getComponent(this.selected()); + if (c != null && c instanceof DialogDisabled) { + ((DialogDisabled)c).dialogDisable(disable); + } + } +} diff --git a/NET/worlds/scape/TalkAction.java b/NET/worlds/scape/TalkAction.java new file mode 100644 index 0000000..7929ea3 --- /dev/null +++ b/NET/worlds/scape/TalkAction.java @@ -0,0 +1,66 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class TalkAction extends Action { + String txt = null; + private static Object classCookie = new Object(); + + public TalkAction() { + } + + public TalkAction(String text) { + this.txt = text; + } + + @Override + public Persister trigger(Event arg, Persister seqID) { + Pilot.getActive(); + Pilot.sendText(this.txt); + return null; + } + + @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 = StringPropertyEditor.make(new Property(this, index, "Message")); + } else if (mode == 1) { + ret = this.txt; + } else if (mode == 2) { + this.txt = (String)value; + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + s.saveString(this.txt); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this.txt = r.restoreString(); + return; + default: + throw new TooNewException(); + } + } + + @Override + public String toString() { + return super.toString() + "[" + this.txt + "]"; + } +} diff --git a/NET/worlds/scape/Teleport.java b/NET/worlds/scape/Teleport.java new file mode 100644 index 0000000..5034290 --- /dev/null +++ b/NET/worlds/scape/Teleport.java @@ -0,0 +1,122 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import java.io.IOException; +import java.text.MessageFormat; + +public class Teleport extends SwitchableBehavior implements FrameHandler, Persister, MouseDownHandler, BumpHandler, TeleportStatus { + String trigger = "none"; + String externalTriggerTag = ""; + String worldName = ""; + private Room currentRoom = null; + + @Override + public boolean handle(FrameEvent e) { + return true; + } + + @Override + public boolean handle(MouseDownEvent e) { + if (this.enabled && this.trigger.equals("click")) { + this.currentRoom = e.target.getRoom(); + TeleportAction.teleport(this.worldName, this); + } + + return true; + } + + @Override + public boolean handle(BumpEventTemp e) { + if (this.enabled && this.trigger.equals("bump")) { + this.currentRoom = e.target.getRoom(); + TeleportAction.teleport(this.worldName, this); + } + + return true; + } + + @Override + public void teleportStatus(String err, String url) { + } + + @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 = StringPropertyEditor.make(new Property(this, index, "Trigger")); + } else if (mode == 1) { + ret = new String(this.trigger); + } else if (mode == 2) { + this.trigger = ((String)value).trim(); + } + break; + case 1: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "External Trigger Tag")); + } else if (mode == 1) { + ret = new String(this.externalTriggerTag); + } else if (mode == 2) { + this.externalTriggerTag = ((String)value).trim(); + } + break; + case 2: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "World Name")); + } else if (mode == 1) { + ret = new String(this.worldName); + } else if (mode == 2) { + this.worldName = ((String)value).trim(); + } + break; + default: + ret = super.properties(index, offset + 3, mode, value); + } + + return ret; + } + + @Override + public String toString() { + return super.toString() + + "[trigger " + + this.trigger + + ", External trigger" + + this.externalTriggerTag + + ", World Name " + + this.worldName + + ", enabled " + + this.enabled + + "]"; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveString(this.trigger); + s.saveString(this.externalTriggerTag); + s.saveString(this.worldName); + } + + @Override + public void restoreState(Restorer r) throws IOException { + this.trigger = r.restoreString(); + this.externalTriggerTag = r.restoreString(); + this.worldName = r.restoreString(); + } + + @Override + public void postRestore(int version) { + String name = this.getName(); + String arg1 = name == null ? "<null>" : name; + SuperRoot owner = this.getOwner(); + String oname = ""; + if (owner != null) { + oname = owner.getName(); + } + + String arg2 = oname == null ? "<null>" : oname; + Object[] arguments = new Object[]{new String(arg1), new String(arg2)}; + Console.println(MessageFormat.format(Console.message("Teleport-obs"), arguments)); + } +} diff --git a/NET/worlds/scape/TeleportAction.java b/NET/worlds/scape/TeleportAction.java new file mode 100644 index 0000000..c73dada --- /dev/null +++ b/NET/worlds/scape/TeleportAction.java @@ -0,0 +1,539 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.DialogReceiver; +import NET.worlds.console.Main; +import NET.worlds.console.MainCallback; +import NET.worlds.console.WorldsMarkPart; +import NET.worlds.core.IniFile; +import NET.worlds.network.NetUpdate; +import NET.worlds.network.URL; +import java.awt.Frame; +import java.io.IOException; +import java.net.MalformedURLException; +import java.text.MessageFormat; + +public class TeleportAction extends Action implements LoadedURLSelf, MainCallback, DialogReceiver { + private Point3 targetCoords = new Point3(); + private float targetRot = 0.0F; + private Point3 targetAxis = new Point3(0.0F, 0.0F, -1.0F); + private String targetRoomName = null; + private String targetDimension = null; + private URL targetWorldURL = null; + private boolean useDefCoordinates = false; + private boolean done = false; + private boolean showDialog = true; + private boolean forceWorldLoad = false; + private boolean forceNoWorldLoad = false; + private String targetURL; + private static TeleportAction activeTeleport = null; + private TeleportDialog dialog = null; + private TeleportStatus doneCallback; + String tempParseStr; + private static Object classCookie = new Object(); + + public TeleportAction() { + } + + @Override + public Persister trigger(Event e, Persister seqID) { + if (activeTeleport != this) { + this.targetURL = this.asURL(); + this.startTeleport(); + } + + return !this.done && activeTeleport != this ? this : null; + } + + public void stopLoading() { + this.done = true; + if (activeTeleport == this) { + this.stopTeleport(null); + } + } + + public static boolean isTeleporting() { + return activeTeleport != null; + } + + public static void teleport(String url, TeleportStatus callback) { + TeleportAction t = new TeleportAction(url, callback); + if (Main.isMainThread()) { + t.startTeleport(); + } else { + Main.register(t); + } + } + + public static void teleport(String url, TeleportStatus callback, boolean forceWorldLoad) { + TeleportAction t = new TeleportAction(url, callback); + t.forceWorldLoad = forceWorldLoad; + t.forceNoWorldLoad = !forceWorldLoad; + if (Main.isMainThread()) { + t.startTeleport(); + } else { + Main.register(t); + } + } + + public static void teleport(String url, TeleportStatus callback, boolean forceWorldLoad, boolean pShowDialog) { + TeleportAction t = new TeleportAction(url, callback); + t.showDialog = pShowDialog; + t.forceWorldLoad = forceWorldLoad; + t.forceNoWorldLoad = !forceWorldLoad; + if (Main.isMainThread()) { + t.startTeleport(); + } else { + Main.register(t); + } + } + + @Override + public void mainCallback() { + Main.unregister(this); + this.startTeleport(); + } + + public static String toURLString(String url) { + if (url == null || url.equals("world:")) { + url = WorldsMarkPart.getFirstSystemMarkURL(); + } + + if (url == null) { + url = "home:NewWorld.world"; + } + + if (url.startsWith("world:")) { + if (url.equals("world:restart")) { + url = IniFile.gamma().getIniString("RestartAt", WorldsMarkPart.getFirstSystemMarkURL()); + } else if (url.equals("world:store")) { + url = World.getHomeStore().getAbsolute(); + } else { + url = url.substring(6); + } + + int i = url.indexOf(".world?"); + if (i >= 0) { + url = url.substring(0, i) + ".world#" + url.substring(i + 7); + } + } + + if (url.indexOf(58) < 0) { + if (url.indexOf(47) < 0 && url.indexOf(92) < 0 && !url.endsWith(".world")) { + url = "home:" + url + "/" + url + ".world"; + } else { + url = "file:" + url; + } + } + + return url; + } + + private TeleportAction(String url, TeleportStatus callback) { + this.doneCallback = callback; + this.targetURL = toURLString(url); + url = this.setFromURL(this.targetURL); + + try { + if (this.targetURL.startsWith("http://")) { + this.targetWorldURL = new URL(url); + } else { + this.targetWorldURL = new URL(URL.getCurDir(), URL.maybeAddExt(url, ".world")); + } + } catch (MalformedURLException var4) { + this.targetWorldURL = URL.make("error:\"" + url + '"'); + } + } + + private float getNextFloat(float def) { + String s = this.tempParseStr; + int end = this.tempParseStr.indexOf(44); + if (end == -1) { + end = this.tempParseStr.length(); + this.tempParseStr = ""; + } else { + this.tempParseStr = this.tempParseStr.substring(end + 1); + } + + try { + return Float.valueOf(s.substring(0, end)); + } catch (NumberFormatException var5) { + return def; + } + } + + private String setFromURL(String url) { + this.useDefCoordinates = true; + int roomNameStart = url.lastIndexOf(35); + if (roomNameStart >= 0) { + String rest = url.substring(roomNameStart + 1); + url = url.substring(0, roomNameStart); + int roomNameEnd = rest.lastIndexOf(64); + if (roomNameEnd < 0) { + this.targetRoomName = rest; + } else { + this.useDefCoordinates = false; + this.targetRoomName = rest.substring(0, roomNameEnd); + this.tempParseStr = rest.substring(roomNameEnd + 1); + this.targetCoords.x = this.getNextFloat(this.targetCoords.x); + this.targetCoords.y = this.getNextFloat(this.targetCoords.y); + this.targetCoords.z = this.getNextFloat(this.targetCoords.z); + this.targetRot = this.getNextFloat(this.targetRot); + this.targetAxis.x = this.getNextFloat(this.targetAxis.x); + this.targetAxis.y = this.getNextFloat(this.targetAxis.y); + this.targetAxis.z = this.getNextFloat(this.targetAxis.z); + this.tempParseStr = null; + } + } + + if (this.targetRoomName != null) { + int rightAngle = this.targetRoomName.lastIndexOf(62); + int leftAngle = this.targetRoomName.lastIndexOf(60); + if (rightAngle + 1 == this.targetRoomName.length() && leftAngle >= 0) { + this.targetDimension = this.targetRoomName.substring(leftAngle + 1, rightAngle); + this.targetRoomName = this.targetRoomName.substring(0, leftAngle); + } + } + + return url; + } + + private void makeTeleportDialog(URL url) { + if (this.showDialog) { + Frame gf = Console.getFrame(); + if (gf != null && gf.isShowing()) { + this.dialog = new TeleportDialog(gf, this); + } + } + } + + private void startTeleport() { + if (activeTeleport != null) { + if (activeTeleport.doneCallback != null) { + activeTeleport.doneCallback.teleportStatus("overridden by new teleport", activeTeleport.targetURL); + } + + activeTeleport.stopTeleport(null); + } + + activeTeleport = this; + Console.setFreezeFrameEvents(true); + this.done = false; + Console.teleportNotification("", this.targetURL); + if (this.targetWorldURL != null) { + this.makeTeleportDialog(this.targetWorldURL); + World.load(this.targetWorldURL, this, this.forceWorldLoad); + } else { + Pilot pilot = Pilot.getActive(); + World w; + if (pilot != null && (w = pilot.getWorld()) != null) { + this.makeTeleportDialog(w.getSourceURL()); + this.loadedURLSelf(w, this.targetWorldURL, null); + } else { + this.stopTeleport("Pilot not in a room for intraworld teleport"); + } + } + } + + private Room stopTeleport(String err) { + assert this == activeTeleport; + + this.done = true; + activeTeleport = null; + Console.setFreezeFrameEvents(false); + if (this.doneCallback != null) { + this.doneCallback.teleportStatus(err, this.targetURL); + } + + if (err != null && !this.forceNoWorldLoad) { + Console.teleportNotification(err, this.targetURL); + Console.println(err); + } + + if (this.dialog != null) { + this.dialog.closeIt(true); + this.dialog = null; + } + + return null; + } + + @Override + public synchronized void dialogDone(Object who, boolean confirmed) { + if (activeTeleport != null) { + activeTeleport.stopTeleport(null); + } + } + + public static String getReadableNameOfWorld(URL url) { + String worldDir = url.getAbsolute(); + String readable = worldDir; + String packageName = null; + if (worldDir.startsWith("home:") && worldDir.length() > 6) { + readable = worldDir.substring(worldDir.charAt(5) == '/' ? 6 : 5); + int slash = readable.indexOf(47); + if (slash > 0) { + packageName = readable.substring(0, slash); + if (readable.regionMatches(true, slash + 1, readable, 0, slash)) { + readable = packageName; + String s = WorldsMarkPart.getExternalName(packageName); + if (s != null) { + readable = s; + } + } + } + + int tail = readable.indexOf(".world"); + if (tail > 0) { + readable = readable.substring(0, tail); + } + + readable = "the " + readable + " world"; + } + + return readable; + } + + public static String getPackageNameOfWorld(URL url) { + String worldDir = url.getAbsolute(); + String packageName = null; + if (worldDir.startsWith("home:") && worldDir.length() > 6) { + String readable = worldDir.substring(worldDir.charAt(5) == '/' ? 6 : 5); + int slash = readable.indexOf(47); + if (slash > 0) { + packageName = readable.substring(0, slash); + } + } + + return packageName; + } + + @Override + public void loadedURLSelf(URLSelf o, URL url, String err) { + if (activeTeleport != this) { + if (o != null) { + o.decRef(); + } + } else if (err == null && o instanceof World) { + String roomName = this.targetRoomName; + if (roomName == null) { + roomName = ((World)o).getDefaultRoomName(); + } + + Room room = ((World)o).getRoom(roomName); + if (room == null) { + this.stopTeleport("Error finding room " + this.targetRoomName); + } else if (room.getVIPOnly() && !((World)o).getConsole().getVIP()) { + this.stopTeleport("Only VIPs may go there."); + if (this.forceNoWorldLoad) { + Console.println(Console.message("Only-VIPs-there")); + } + } else { + Console.teleportNotification(null, this.targetURL); + Pilot pilot = Pilot.changeActiveRoom(room); + if (this.targetDimension != null) { + pilot.changeChannel(this.targetDimension); + } + + pilot.makeIdentity(); + if (this.useDefCoordinates) { + pilot.moveTo(room.getDefaultPosition()).spin(room.getDefaultOrientationAxis(), room.getDefaultOrientation()); + } else { + pilot.moveTo(this.targetCoords).spin(this.targetAxis, this.targetRot); + } + + this.stopTeleport(null); + } + } else { + if (err == null) { + err = "file " + url + " doesn't contain a World"; + o.decRef(); + } + + String readable = getReadableNameOfWorld(url); + String packageName = getPackageNameOfWorld(url); + Object[] arguments = new Object[]{new String(readable)}; + this.stopTeleport(MessageFormat.format(Console.message("cant-teleport"), arguments)); + if (packageName != null && !this.forceNoWorldLoad) { + NetUpdate.loadWorld(packageName, this.forceWorldLoad); + } + } + } + + @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, "X, Y, Z")); + } else if (mode == 1) { + ret = new Point3(this.targetCoords); + } else if (mode == 2) { + this.targetCoords.copy((Point3)value); + } + break; + case 1: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Dir")); + } else if (mode == 1) { + ret = new Float(this.targetRot); + } else if (mode == 2) { + this.targetRot = (Float)value; + } + break; + case 2: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Room Name").allowSetNull()); + } else if (mode == 1) { + if (this.targetRoomName == null) { + ret = ""; + } else { + ret = new String(this.targetRoomName); + } + } else if (mode == 2) { + this.targetRoomName = (String)value; + this.stopLoading(); + } + break; + case 3: + if (mode == 0) { + ret = URLPropertyEditor.make(new Property(this, index, "World URL").allowSetNull(), "world"); + } else if (mode == 1) { + ret = this.targetWorldURL; + } else if (mode == 2) { + this.targetWorldURL = (URL)value; + this.stopLoading(); + } + break; + case 4: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Use default coordinates"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.useDefCoordinates); + } else if (mode == 2) { + this.useDefCoordinates = (Boolean)value; + } + break; + case 5: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Dimension Name").allowSetNull()); + } else if (mode == 1) { + if (this.targetDimension == null) { + ret = ""; + } else { + ret = new String(this.targetDimension); + } + } else if (mode == 2) { + this.targetDimension = (String)value; + if (this.targetDimension.equals("")) { + this.targetDimension = null; + } + + this.stopLoading(); + } + break; + case 6: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Show dialog"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.showDialog); + } else if (mode == 2) { + this.showDialog = (Boolean)value; + } + break; + default: + ret = super.properties(index, offset + 7, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(3, classCookie); + super.saveState(s); + s.save(this.targetCoords); + s.saveFloat(this.targetRot); + s.save(this.targetAxis); + s.saveString(this.targetRoomName); + URL.save(s, this.targetWorldURL); + s.saveBoolean(this.useDefCoordinates); + s.saveString(this.targetDimension); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + int vers = r.restoreVersion(classCookie); + switch (vers) { + case 0: + super.restoreState(r); + this.targetCoords = (Point3)r.restore(); + this.targetRot = r.restoreInt(); + this.targetRoomName = r.restoreString(); + this.targetWorldURL = URL.restore(r, ".world"); + this.useDefCoordinates = r.restoreBoolean(); + this.targetDimension = null; + break; + case 1: + case 2: + super.restoreState(r); + this.targetCoords = (Point3)r.restore(); + this.targetRot = r.restoreFloat(); + this.targetAxis = (Point3)r.restore(); + this.targetRoomName = r.restoreString(); + this.targetWorldURL = URL.restore(r, ".world"); + this.useDefCoordinates = r.restoreBoolean(); + this.targetDimension = null; + break; + case 3: + super.restoreState(r); + this.targetCoords = (Point3)r.restore(); + this.targetRot = r.restoreFloat(); + this.targetAxis = (Point3)r.restore(); + this.targetRoomName = r.restoreString(); + this.targetWorldURL = URL.restore(r, ".world"); + this.useDefCoordinates = r.restoreBoolean(); + this.targetDimension = r.restoreString(); + break; + default: + throw new TooNewException(); + } + + if (vers < 2 && this.targetAxis.x == 0.0F && this.targetAxis.y == 0.0F && this.targetAxis.z == 1.0F) { + this.targetAxis.z = -1.0F; + this.targetRot = 360.0F - this.targetRot; + } + } + + @Override + public String toString() { + return super.toString() + "[" + this.asURL() + "]"; + } + + public String asURL() { + String url; + if (this.targetWorldURL != null) { + url = this.targetWorldURL.getRelativeTo(this) + "#"; + } else { + url = "#"; + } + + if (this.targetRoomName != null) { + url = url + this.targetRoomName; + } + + if (this.targetDimension != null) { + url = url + "<" + this.targetDimension + ">"; + } + + if (!this.useDefCoordinates) { + url = url + "@" + this.targetCoords + "," + this.targetRot; + if (this.targetAxis.x != 0.0F || this.targetAxis.y != 0.0F || this.targetAxis.z != 1.0F) { + url = url + "," + this.targetAxis; + } + } + + return url; + } +} diff --git a/NET/worlds/scape/TeleportDialog.java b/NET/worlds/scape/TeleportDialog.java new file mode 100644 index 0000000..7f9d7fc --- /dev/null +++ b/NET/worlds/scape/TeleportDialog.java @@ -0,0 +1,44 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.DialogReceiver; +import NET.worlds.console.ImageButtons; +import NET.worlds.console.ImageButtonsCallback; +import NET.worlds.console.PolledDialog; +import NET.worlds.core.IniFile; +import java.awt.Component; +import java.awt.Rectangle; +import java.awt.Window; + +public class TeleportDialog extends PolledDialog implements ImageButtonsCallback { + private ImageButtons ib; + + public TeleportDialog(Window parent, DialogReceiver receiver) { + super(parent, receiver, Console.message("Teleporting"), true); + Rectangle[] rects = new Rectangle[1]; + int cancelX = IniFile.override().getIniInt("teleportCancelX", 61); + int cancelY = IniFile.override().getIniInt("teleportCancelY", 24); + int cancelW = IniFile.override().getIniInt("teleportCancelW", 84); + int cancelH = IniFile.override().getIniInt("teleportCancelH", 20); + rects[0] = new Rectangle(cancelX, cancelY, cancelW, cancelH); + String teleportGif = IniFile.override().getIniString("teleportDlg", Console.message("hangon.gif")); + this.ib = new ImageButtons(teleportGif, rects, this); + this.ready(); + } + + @Override + protected void build() { + this.add("Center", this.ib); + } + + @Override + public Object imageButtonsCallback(Component who, int which) { + this.done(false); + return null; + } + + @Override + public boolean keyDown(java.awt.Event event, int key) { + return key == 27 ? this.done(false) : super.keyDown(event, key); + } +} diff --git a/NET/worlds/scape/TeleportStatus.java b/NET/worlds/scape/TeleportStatus.java new file mode 100644 index 0000000..0c710e1 --- /dev/null +++ b/NET/worlds/scape/TeleportStatus.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface TeleportStatus { + void teleportStatus(String var1, String var2); +} diff --git a/NET/worlds/scape/Texture.java b/NET/worlds/scape/Texture.java new file mode 100644 index 0000000..9850a38 --- /dev/null +++ b/NET/worlds/scape/Texture.java @@ -0,0 +1,102 @@ +package NET.worlds.scape; + +import NET.worlds.network.URL; +import java.io.IOException; +import java.net.MalformedURLException; + +public abstract class Texture implements Persister { + protected int textureID = 0; + int refs = 1; + private static Object classCookie = new Object(); + + static { + nativeInit(); + } + + protected Texture() { + } + + public static native void nativeInit(); + + private static native int nativeGetW(int var0); + + public int getW() { + return nativeGetW(this.textureID); + } + + private static native int nativeGetH(int var0); + + public int getH() { + return nativeGetH(this.textureID); + } + + public URL getURL() { + URL u = null; + String s = this.getName(); + if (s != null) { + try { + u = new URL(URL.getCurDir(), s); + } catch (MalformedURLException var4) { + } + } + + return u; + } + + public void incRef() { + assert this.refs > 0; + + if (this.textureID != 0) { + this.refs++; + } + } + + public void copyFrom(int dc, int x1, int x2, int y1, int y2) { + assert this.textureID != 0; + + nativeCopyFrom(this.textureID, dc, x1, x2, y1, y2); + } + + private static native void nativeCopyFrom(int var0, int var1, int var2, int var3, int var4, int var5); + + private static native void nativeRelease(int var0); + + public synchronized void decRef() { + if (--this.refs <= 0 && this.textureID != 0) { + nativeRelease(this.textureID); + this.textureID = 0; + } + } + + @Override + protected void finalize() { + if (this.refs > 0) { + this.refs = 1; + this.decRef(); + this.refs = 1000000; + } + } + + protected String getName() { + return null; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + return; + default: + throw new TooNewException(); + } + } + + @Override + public void postRestore(int version) { + } +} diff --git a/NET/worlds/scape/TextureDecoder.java b/NET/worlds/scape/TextureDecoder.java new file mode 100644 index 0000000..42477db --- /dev/null +++ b/NET/worlds/scape/TextureDecoder.java @@ -0,0 +1,73 @@ +package NET.worlds.scape; + +import NET.worlds.network.URL; +import java.io.File; +import java.util.Hashtable; +import java.util.StringTokenizer; + +public abstract class TextureDecoder { + protected static Hashtable handlers = new Hashtable(); + private static TextureDecoder defaultDecoder; + private static String allExts; + + static { + addHandler(defaultDecoder = new FileTextureDecoder()); + addHandler(new StandardTextureDecoder()); + addHandler(new ScapePicTextureDecoder()); + } + + protected abstract String getExts(); + + protected abstract Texture read(String var1, String var2); + + private static void addHandler(TextureDecoder decoder) { + StringTokenizer e = new StringTokenizer(decoder.getExts(), ";"); + + while (e.hasMoreTokens()) { + String ext = e.nextToken().toLowerCase(); + handlers.put(ext, decoder); + if (allExts == null) { + allExts = ext; + } else { + allExts = allExts + File.pathSeparator + ext; + } + } + } + + public static String getAllExts() { + return allExts; + } + + public static String getJavaExts() { + return new StandardTextureDecoder().getExts(); + } + + public static Texture decode(URL url, String filename) { + return decode(url, url.getAbsolute(), filename); + } + + public static Texture decode(URL url, String lookupName, String filename) { + Texture tex = FileTexture.dictLookup(lookupName); + if (tex != null) { + return tex; + } else { + String urlName = url.getInternal(); + int delim = urlName.lastIndexOf(46); + int lastPath = urlName.lastIndexOf(47); + lastPath = Math.max(lastPath, urlName.lastIndexOf(92)); + lastPath = Math.max(lastPath, urlName.lastIndexOf(58)); + if (delim > lastPath) { + String ext = urlName.substring(delim + 1).toLowerCase(); + TextureDecoder decoder = (TextureDecoder)handlers.get(ext); + if (decoder != null) { + Texture t = decoder.read(lookupName, filename); + if (t.textureID != 0) { + return t; + } + } + } + + return null; + } + } +} diff --git a/NET/worlds/scape/TextureSurface.java b/NET/worlds/scape/TextureSurface.java new file mode 100644 index 0000000..abdd240 --- /dev/null +++ b/NET/worlds/scape/TextureSurface.java @@ -0,0 +1,85 @@ +package NET.worlds.scape; + +public class TextureSurface { + private Texture[] _textures; + private int _hwnd; + private int _oldObject; + private int _offscreen; + private int _texWidth; + private int _texHeight; + private int _width; + private int _height; + private int _rows; + private int _cols; + + public TextureSurface(Texture[] texList, int rows, int w, int h) { + this._width = w; + this._height = h; + this._oldObject = 0; + this._hwnd = this.nativeInit(w, h); + this._offscreen = this.nativeMakeDC(this._hwnd, w, h); + if (texList != null) { + this.setTextures(texList, rows); + } + } + + @Override + public void finalize() { + this.nativeDestroyDC(this._offscreen); + this._oldObject = 0; + } + + public void setTextures(Texture[] texList, int rows) { + this._textures = texList; + this._rows = rows; + this._cols = texList.length / rows; + this._texWidth = this._width / this._cols; + this._texHeight = this._height / this._rows; + } + + public synchronized boolean draw(TextureSurfaceRenderer renderer) { + renderer.renderTo(this._offscreen); + int idx = 0; + + for (int row = this._rows - 1; row >= 0; row--) { + for (int col = 0; col < this._cols; col++) { + if (this._textures[idx] != null) { + this._textures[idx] + .copyFrom(this._offscreen, col * this._texWidth, (col + 1) * this._texWidth, row * this._texHeight, (row + 1) * this._texHeight); + } + + idx++; + } + } + + return false; + } + + public void sendLeftClick(int x, int y) { + this.nativeLeftClick(this._hwnd, x, y); + } + + public int getHwnd() { + return this._hwnd; + } + + public int getWidth() { + return this._width; + } + + public int getHeight() { + return this._height; + } + + private native int nativeInit(int var1, int var2); + + private native int nativeMakeDC(int var1, int var2, int var3); + + private native int nativeGetDC(int var1); + + private native void nativeReleaseDC(int var1, int var2); + + private native void nativeDestroyDC(int var1); + + private native void nativeLeftClick(int var1, int var2, int var3); +} diff --git a/NET/worlds/scape/TextureSurfaceRenderer.java b/NET/worlds/scape/TextureSurfaceRenderer.java new file mode 100644 index 0000000..d374143 --- /dev/null +++ b/NET/worlds/scape/TextureSurfaceRenderer.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface TextureSurfaceRenderer { + void renderTo(int var1); +} diff --git a/NET/worlds/scape/Toggle.java b/NET/worlds/scape/Toggle.java new file mode 100644 index 0000000..e70da37 --- /dev/null +++ b/NET/worlds/scape/Toggle.java @@ -0,0 +1,165 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import java.io.IOException; +import java.text.MessageFormat; + +public class Toggle extends TriggeredSwitchableBehavior implements Persister, FrameHandler, MouseDownHandler, BumpHandler { + protected boolean toggleBumpable; + protected boolean toggleVisible; + protected WObject o; + protected boolean initialized = false; + + public Toggle() { + this.trigger = new String("none"); + this.externalTriggerTag = new String(""); + this.toggleBumpable = true; + this.toggleVisible = true; + } + + @Override + public void ExternalTrigger(Trigger trigger_source, int sequence_no, int event_no) { + this.trigger_source = trigger_source; + this.sequence_no = sequence_no; + this.event_no = event_no; + this.toggle(); + } + + public void toggle() { + if (this.toggleBumpable) { + this.o.setBumpable(true); + } else { + this.o.setBumpable(false); + } + + if (this.toggleVisible) { + this.o.setVisible(true); + } else { + this.o.setVisible(false); + } + + if (this.trigger_source != null) { + this.trigger_source.registerFinishedTriggerTag(this.sequence_no, this.event_no); + } + } + + @Override + public boolean handle(FrameEvent e) { + if (!this.initialized) { + this.o = e.receiver; + this.initialized = true; + } + + return true; + } + + @Override + public boolean handle(MouseDownEvent e) { + if (this.enabled && this.trigger.equals("click")) { + this.toggle(); + } + + return true; + } + + @Override + public boolean handle(BumpEventTemp e) { + if (this.enabled && this.trigger.equals("bump")) { + this.toggle(); + } + + return true; + } + + @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 = StringPropertyEditor.make(new Property(this, index, "Trigger")); + } else if (mode == 1) { + ret = new String(this.trigger); + } else if (mode == 2) { + this.trigger = ((String)value).toString().trim(); + if (this.trigger.equals("external")) { + Trigger.TriggeredSwitchableBehaviorList[Trigger.TriggeredSwitchableBehaviorListCount] = this; + Trigger.TriggeredSwitchableBehaviorListCount++; + } + } + break; + case 1: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "External Trigger Tag")); + } else if (mode == 1) { + ret = new String(this.externalTriggerTag); + } else if (mode == 2) { + this.externalTriggerTag = ((String)value).toString().trim(); + } + break; + case 2: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Toggle Bumpable"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.toggleBumpable); + } else if (mode == 2) { + this.toggleBumpable = (Boolean)value; + } + break; + case 3: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Toggle Visible"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.toggleVisible); + } else if (mode == 2) { + this.toggleVisible = (Boolean)value; + } + break; + default: + ret = super.properties(index, offset + 4, mode, value); + } + + return ret; + } + + @Override + public String toString() { + return super.toString() + "[" + " enabled " + this.enabled + ", trigger " + this.trigger + ", externalTriggerTag " + this.externalTriggerTag + "]"; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveString(this.trigger); + s.saveString(this.externalTriggerTag); + s.saveBoolean(this.toggleBumpable); + s.saveBoolean(this.toggleVisible); + } + + @Override + public void restoreState(Restorer r) throws IOException { + this.trigger = r.restoreString(); + if (this.trigger.equals("external")) { + Trigger.TriggeredSwitchableBehaviorList[Trigger.TriggeredSwitchableBehaviorListCount] = this; + Trigger.TriggeredSwitchableBehaviorListCount++; + } + + this.externalTriggerTag = r.restoreString(); + this.toggleBumpable = r.restoreBoolean(); + this.toggleVisible = r.restoreBoolean(); + } + + @Override + public void postRestore(int version) { + String name = this.getName(); + String arg1 = name == null ? "<null>" : name; + SuperRoot owner = this.getOwner(); + String oname = ""; + if (owner != null) { + oname = owner.getName(); + } + + String arg2 = oname == null ? "<null>" : oname; + Object[] arguments = new Object[]{new String(arg1), new String(arg2)}; + Console.println(MessageFormat.format(Console.message("Toggle-obs"), arguments)); + } +} diff --git a/NET/worlds/scape/ToggleZoomMode.java b/NET/worlds/scape/ToggleZoomMode.java new file mode 100644 index 0000000..ffea022 --- /dev/null +++ b/NET/worlds/scape/ToggleZoomMode.java @@ -0,0 +1,20 @@ +package NET.worlds.scape; + +import NET.worlds.console.Window; + +public class ToggleZoomMode extends Action { + @Override + public Persister trigger(Event e, Persister seqID) { + if (e.receiver instanceof Pilot && ((Pilot)e.receiver).isActive()) { + Window w = Window.getMainWindow(); + if (w == null) { + return null; + } else { + w.setDeltaMode(!w.getDeltaMode()); + return null; + } + } else { + return null; + } + } +} diff --git a/NET/worlds/scape/TooNewException.java b/NET/worlds/scape/TooNewException.java new file mode 100644 index 0000000..1172031 --- /dev/null +++ b/NET/worlds/scape/TooNewException.java @@ -0,0 +1,10 @@ +package NET.worlds.scape; + +public class TooNewException extends Exception { + public TooNewException() { + } + + public TooNewException(String s) { + super(s); + } +} diff --git a/NET/worlds/scape/ToolBar.java b/NET/worlds/scape/ToolBar.java new file mode 100644 index 0000000..ebf0cc9 --- /dev/null +++ b/NET/worlds/scape/ToolBar.java @@ -0,0 +1,238 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.DialogDisabled; +import NET.worlds.console.ExposedPanel; +import NET.worlds.console.Main; +import NET.worlds.console.MainCallback; +import NET.worlds.console.Window; +import java.awt.Color; +import java.awt.FlowLayout; +import java.util.Enumeration; +import java.util.Vector; + +class ToolBar extends ExposedPanel implements MainCallback, DialogDisabled { + private Vector buttons = new Vector(); + private WidgetButton active; + private boolean activeDown; + private WidgetButton entered; + private WObject curWObj; + private boolean haveDelta = false; + private WObjectHighlighter highlight; + private boolean initialDrag; + private boolean isDialogDisabled; + private boolean testConstrained; + private boolean constrainToX; + private boolean constrainToY; + private int cumx; + private int cumy; + private float motionDivisor = 1.0F; + private static final int constrainThresh = 5; + + public ToolBar() { + this.setLayout(new FlowLayout(0, 1, 1)); + this.addButton(new HTransWidget(this)); + this.addButton(new VTransWidget(this)); + this.addButton(new PitchWidget(this)); + this.addButton(new RollWidget(this)); + this.addButton(new YawWidget(this)); + this.addButton(new ScaleWidget(this)); + this.addButton(new CutWidget(this)); + this.addButton(new CopyWidget(this)); + this.addButton(new PasteWidget(this)); + this.addButton(new SaveWidget(this)); + this.addButton(new UndoWidget(this)); + this.setBackground(Color.lightGray); + } + + public void done() { + if (this.highlight != null) { + this.highlight.stop(); + } + } + + private void addButton(WidgetButton button) { + this.add(button); + this.buttons.addElement(button); + } + + public void setCurrentObject(Object obj) { + this.curWObj = obj instanceof WObject ? (WObject)obj : null; + if (this.highlight != null) { + this.highlight.stop(); + this.highlight = null; + } + + if (this.curWObj != null) { + this.highlight = new WObjectHighlighter(this.curWObj); + } + + Enumeration e = this.buttons.elements(); + this.clearPrompt(); + + while (e.hasMoreElements()) { + ((WidgetButton)e.nextElement()).repaint(); + } + } + + public WObject getCurrentWObject() { + return this.curWObj; + } + + @Override + public void dialogDisable(boolean disable) { + this.isDialogDisabled = disable; + } + + @Override + public boolean handleEvent(java.awt.Event event) { + return this.isDialogDisabled ? false : super.handleEvent(event); + } + + @Override + public synchronized boolean mouseDown(java.awt.Event event, int x, int y) { + WidgetButton button; + if (event.target instanceof WidgetButton && (event.modifiers & 4) == 0 && this.active == null && (button = (WidgetButton)event.target).available()) { + this.active = button; + this.active.draw(true); + if (this.active.usesDrag()) { + this.initialDrag = true; + this.highlight.stop(); + Window.hideCursor(); + Main.register(this); + this.haveDelta = true; + } else { + this.activeDown = true; + } + } + + return true; + } + + @Override + public synchronized boolean mouseDrag(java.awt.Event event, int x, int y) { + if (this.active != null) { + if (this.active.usesDrag()) { + if ((event.modifiers & 1) != 0 && !this.constrainToX && !this.constrainToY) { + this.testConstrained = true; + this.cumx = this.cumy = 0; + } + + this.motionDivisor = (event.modifiers & 2) != 0 ? 10.0F : 1.0F; + this.haveDelta = true; + } else { + boolean inside = this.active.getBounds().inside(x, y); + if (inside != this.activeDown) { + this.active.draw(this.activeDown = inside); + } + } + } + + return true; + } + + @Override + public synchronized void mainCallback() { + if (this.haveDelta && this.active != null) { + int[] pos = Window.getHiddenCursorDelta(); + if (this.testConstrained) { + this.cumx = this.cumx + pos[0]; + this.cumy = this.cumy + pos[1]; + int acumx = Math.abs(this.cumx); + int acumy = Math.abs(this.cumy); + if (acumx > acumy + 5) { + this.constrainToX = true; + } else { + if (acumy <= acumx + 5) { + return; + } + + this.constrainToY = true; + } + + this.testConstrained = false; + } + + if (this.constrainToX) { + pos[0] += this.cumx; + this.cumx = 0; + pos[1] = 0; + } else if (this.constrainToY) { + pos[1] += this.cumy; + this.cumy = 0; + pos[0] = 0; + } + + this.setPrompt(this.active.drag(this.initialDrag, pos[0] / this.motionDivisor, -pos[1] / this.motionDivisor)); + this.initialDrag = false; + this.haveDelta = false; + } + } + + @Override + public synchronized boolean mouseUp(java.awt.Event event, int x, int y) { + if (this.active != null) { + this.active.draw(false); + boolean needUpdate = true; + if (this.active.usesDrag()) { + this.highlight.start(); + Main.unregister(this); + } else if (this.activeDown) { + this.active.perform(); + this.activeDown = false; + } else { + needUpdate = false; + } + + this.active = null; + if (needUpdate) { + Console.getFrame().getEditTile().update(); + } + } + + return true; + } + + @Override + public boolean mouseEnter(java.awt.Event event, int x, int y) { + WidgetButton button; + if (this.active == null && event.target instanceof WidgetButton && (button = (WidgetButton)event.target).available()) { + this.entered = button; + this.setPrompt(this.entered.getPrompt()); + } + + return true; + } + + @Override + public boolean mouseMove(java.awt.Event event, int x, int y) { + return this.mouseEnter(event, x, y); + } + + @Override + public synchronized boolean keyUp(java.awt.Event event, int key) { + if ((event.modifiers & 1) == 0) { + this.testConstrained = this.constrainToX = this.constrainToY = false; + } + + return true; + } + + public void setPrompt(String prompt) { + Console.getFrame().getEditTile().setPrompt(prompt); + } + + private void clearPrompt() { + this.entered = null; + Console.getFrame().getEditTile().setPrompt(null); + } + + @Override + public boolean mouseExit(java.awt.Event event, int x, int y) { + if (this.active == null && event.target == this.entered) { + this.clearPrompt(); + } + + return true; + } +} diff --git a/NET/worlds/scape/ToolTipManager.java b/NET/worlds/scape/ToolTipManager.java new file mode 100644 index 0000000..e578dd1 --- /dev/null +++ b/NET/worlds/scape/ToolTipManager.java @@ -0,0 +1,102 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.DefaultConsole; +import NET.worlds.console.MultiLineLabel; +import NET.worlds.core.IniFile; +import java.awt.Color; +import java.awt.Font; +import java.awt.Frame; +import java.awt.Window; + +public class ToolTipManager { + private static ToolTipManager manager_ = null; + private static final int FRAME_DELAY = 15; + private int savedX; + private int savedY; + private int savedLoops; + private boolean toolTipActive; + private WObject savedObject; + private Window toolTipWindow; + private MultiLineLabel toolTipTextArea; + private Font toolTipFont; + + private ToolTipManager() { + this.savedX = this.savedY = this.savedLoops = 0; + this.toolTipActive = false; + this.savedObject = null; + this.toolTipFont = new Font("Arial", 0, 10); + Console.getActive(); + this.toolTipWindow = new Window((Frame)Console.getFrame()); + this.toolTipTextArea = new MultiLineLabel(); + this.toolTipTextArea.setBackground(Color.yellow); + this.toolTipTextArea.setForeground(Color.black); + this.toolTipTextArea.setMarginWidth(2); + this.toolTipTextArea.setMarginHeight(2); + this.toolTipWindow.setFont(this.toolTipFont); + this.toolTipWindow.add(this.toolTipTextArea); + } + + public static ToolTipManager toolTipManager() { + if (manager_ == null) { + manager_ = new ToolTipManager(); + } + + return manager_; + } + + public void heartbeat() { + if (IniFile.gamma().getIniInt("DisableToolTips", 0) != 1) { + WObject obj = Camera.getMousePickWObject(); + int x = (int)Camera.getMousePickX(); + int y = (int)Camera.getMousePickY(); + if (obj != null && x > 0 && y > 0 && x == this.savedX && y == this.savedY && this.savedObject == obj) { + this.savedLoops++; + } else { + if (this.toolTipActive) { + this.removeToolTip(); + this.toolTipActive = false; + } + + this.savedLoops = 0; + } + + if (!this.toolTipActive && obj != null && this.savedLoops > 15) { + this.toolTipActive = true; + if (obj != null) { + this.savedObject = obj; + if (obj.getToolTipText() != null) { + String oldText = obj.getToolTipText(); + String newText = oldText.replace('|', '\n'); + this.createToolTip(this.savedX, this.savedY, newText); + } + } + } + + this.savedX = x; + this.savedY = y; + this.savedObject = obj; + } + } + + void createToolTip(int winX, int winY, String text) { + int baseX = ((DefaultConsole)Console.getActive()).getRender().getLocationOnScreen().x; + int baseY = ((DefaultConsole)Console.getActive()).getRender().getLocationOnScreen().y; + int offsetX = 16; + int offsetY = 16; + this.toolTipWindow.setLocation(winX + baseX + offsetX, winY + baseY + offsetY); + this.toolTipTextArea.setLabel(text); + this.toolTipWindow.setSize(this.toolTipTextArea.preferredSize()); + this.toolTipWindow.setEnabled(false); + this.toolTipWindow.show(); + } + + public void removeToolTip() { + this.toolTipWindow.hide(); + } + + public void killToolTip() { + this.savedLoops = 0; + this.toolTipWindow.hide(); + } +} diff --git a/NET/worlds/scape/TradeAction.java b/NET/worlds/scape/TradeAction.java new file mode 100644 index 0000000..9efc9d3 --- /dev/null +++ b/NET/worlds/scape/TradeAction.java @@ -0,0 +1,151 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.Main; +import NET.worlds.console.MainCallback; +import NET.worlds.console.OkCancelDialog; +import NET.worlds.console.PolledDialog; +import java.io.IOException; + +public class TradeAction extends DialogAction { + int userItems = 1; + String userItem = "A"; + int serverItems = 1; + String serverItem = "A"; + private static Object classCookie = new Object(); + + @Override + public void doIt() { + StringBuffer deal = new StringBuffer(); + deal.append("&|+deal>TRADE "); + if (this.userItems > 0) { + deal.append(this.userItem); + deal.append(this.userItems); + } + + deal.append(","); + if (this.serverItems > 0) { + deal.append(this.serverItem); + deal.append(this.serverItems); + } + + final String dealStr = deal.toString(); + Main.register(new MainCallback() { + @Override + public void mainCallback() { + Pilot.sendText("TRADE", dealStr); + Main.unregister(this); + } + }); + } + + @Override + public PolledDialog getDialog() { + return InventoryManager.getInventoryManager().checkInventoryFor(this.userItem) >= this.userItems + ? new OkCancelDialog( + Console.getFrame(), + this, + "Trade?", + "No", + "Yes", + "Do you want to give " + + InventoryManager.getInventoryManager().itemName(this.userItem, this.userItems) + + " in return for " + + InventoryManager.getInventoryManager().itemName(this.serverItem, this.serverItems) + + "?", + false + ) + : new OkCancelDialog( + Console.getFrame(), + this, + "Can't trade!", + "Ok", + null, + "You need " + InventoryManager.getInventoryManager().itemName(this.userItem, this.userItems) + " in order to trade here.", + false + ); + } + + @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 = StringPropertyEditor.make(new Property(this, index, "User Item Type")); + } else if (mode == 1) { + ret = this.userItem; + } else if (mode == 2) { + this.userItem = ((String)value).toString().trim(); + } + break; + case 1: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Number of User Items")); + } else if (mode == 1) { + ret = new Integer(this.userItems); + } else if (mode == 2) { + this.userItems = (Integer)value; + } + break; + case 2: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Merchant Item Type")); + } else if (mode == 1) { + ret = this.serverItem; + } else if (mode == 2) { + this.serverItem = ((String)value).toString().trim(); + } + break; + case 3: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Number of Merchant Items")); + } else if (mode == 1) { + ret = new Integer(this.serverItems); + } else if (mode == 2) { + this.serverItems = (Integer)value; + } + break; + default: + ret = super.properties(index, offset + 4, mode, value); + } + + return ret; + } + + @Override + public String toString() { + return super.toString() + + "[give " + + InventoryManager.getInventoryManager().itemName(this.userItem, this.userItems) + + " for " + + InventoryManager.getInventoryManager().itemName(this.serverItem, this.serverItems) + + "]"; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + s.saveString(this.userItem); + s.saveInt(this.userItems); + s.saveString(this.serverItem); + s.saveInt(this.serverItems); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + int ver = r.restoreVersion(classCookie); + switch (ver) { + case 0: + super.restoreState(r); + this.userItem = r.restoreString(); + this.userItems = r.restoreInt(); + this.serverItem = r.restoreString(); + this.serverItems = r.restoreInt(); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/TrajectoryBehavior.java b/NET/worlds/scape/TrajectoryBehavior.java new file mode 100644 index 0000000..88abf49 --- /dev/null +++ b/NET/worlds/scape/TrajectoryBehavior.java @@ -0,0 +1,305 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class TrajectoryBehavior extends SwitchableBehavior implements FrameHandler, BumpHandler { + protected Point3 dir; + public float linearVel; + public Point3 axis; + public float angularVel; + private RollingAttribute attr; + public float linearDamp; + public float bounceDamp; + public float angularDamp; + public float gravity; + private long lastTime; + private boolean bumplock = false; + private static Object classCookie = new Object(); + + public TrajectoryBehavior(Point3Temp linearVelocity, float linearDamping, Point3Temp angularAxis, float angularVelocity, float angularDamping) { + this.dir = new Point3(); + this.linearVel = 0.0F; + this.linearDamp = linearDamping; + this.addVelocity(linearVelocity); + this.axis = new Point3(angularAxis); + this.axis.normalize(); + this.angularVel = angularVelocity; + this.angularDamp = angularDamping; + } + + public TrajectoryBehavior() { + this(Point3Temp.make(0.0F, 0.0F, 0.0F)); + } + + public TrajectoryBehavior(Point3Temp vel) { + this(vel, 0.0F, Point3Temp.make(0.0F, 0.0F, 1.0F), 0.0F, 0.0F); + } + + public void setDir(Point3Temp d) { + double len = Math.sqrt(d.x * d.x + d.y * d.y + d.z * d.z); + if (len == 0.0) { + this.dir.x = 0.0F; + this.dir.y = 0.0F; + this.dir.z = 0.0F; + } else { + this.dir.x = (float)(d.x / len); + this.dir.y = (float)(d.y / len); + this.dir.z = (float)(d.z / len); + } + } + + public TrajectoryBehavior addVelocity(Point3Temp vector) { + this.dir.times(this.linearVel).plus(vector); + float len = this.dir.length(); + if (len > 0.0F) { + this.dir.dividedBy(len); + } + + this.linearVel = len; + return this; + } + + public void setNotifyAttribute(RollingAttribute attr) { + this.attr = attr; + } + + @Override + public boolean handle(FrameEvent e) { + this.bumplock = false; + WObject o = e.receiver; + float dT = (float)(e.time - this.lastTime) / 1000.0F; + if (this.lastTime == 0L) { + this.lastTime = e.time; + return true; + } else { + this.lastTime = e.time; + Room room = o.getRoom(); + if (o.getZ() > room.floorHeight(o.getX(), o.getY(), o.getZ())) { + this.addVelocity(Point3Temp.make(0.0F, 0.0F, -this.gravity * dT)); + } else if (this.dir.z < 0.0F) { + this.dir.z = -this.dir.z; + if (this.bounceDamp < 1.0) { + this.linearVel = this.linearVel * this.bounceDamp; + if (this.linearVel < 0.2 && this.linearVel > -0.2) { + this.linearVel = 0.0F; + } + } + } + + if (this.linearVel != 0.0F) { + Point3Temp dist = Point3Temp.make(this.dir).times(dT * this.linearVel); + o.moveThrough(dist); + if (this.linearDamp != 0.0F) { + this.linearVel = (float)(this.linearVel * Math.exp(-this.linearDamp * dT)); + if (Math.abs(this.linearVel) < this.linearDamp * 16.0F) { + this.linearVel = 0.0F; + if (this.attr != null) { + this.attr.notifyStopped(); + } + } + } + } + + if (this.angularVel != 0.0F) { + o.spin(this.axis.x, this.axis.y, this.axis.z, this.angularVel * dT); + if (this.angularDamp != 0.0F) { + this.angularVel = (float)(this.angularVel * Math.exp(-this.angularDamp * dT)); + if (Math.abs(this.angularVel) < this.angularDamp * 0.6F) { + this.angularVel = 0.0F; + } + } + } + + return true; + } + } + + @Override + public boolean handle(BumpEventTemp b) { + if (this.bumplock) { + return true; + } else { + if (this.attr != null) { + this.attr.handle(b); + } else { + this.processBumpEvent(b); + } + + this.bumplock = true; + return true; + } + } + + public void processBumpEvent(BumpEventTemp b) { + b.postBumpPath.minus(b.postBumpPath); + if (this.dir.x != 0.0F || this.dir.y != 0.0F || this.dir.z != 0.0F) { + WObject bumper = b.receiver == b.target ? (WObject)b.source : b.target; + Point3Temp norm; + if (!(bumper instanceof Camera) && !(bumper instanceof Hologram)) { + norm = Point3Temp.make(b.bumpNormal); + } else { + float orientation = (float)((360.0F - bumper.getYaw() + 90.0F) * Math.PI / 180.0); + norm = Point3Temp.make((float)Math.cos(orientation), (float)Math.sin(orientation), 0.0F); + } + + float lb = (float)Math.sqrt(norm.x * norm.x + norm.y * norm.y + norm.z * norm.z); + norm.x /= lb; + norm.y /= lb; + norm.z /= lb; + float projection = Math.abs(this.dir.x * norm.x + this.dir.y * norm.y + this.dir.z * norm.z); + this.dir.x = this.dir.x + norm.x * 2.0F * projection; + this.dir.y = this.dir.y + norm.y * 2.0F * projection; + this.dir.z = this.dir.z + norm.z * 2.0F * projection; + double n = Math.sqrt(this.dir.x * this.dir.x + this.dir.y * this.dir.y + this.dir.z * this.dir.z); + if (n != 0.0) { + this.dir.x = (float)(this.dir.x / n); + this.dir.y = (float)(this.dir.y / n); + this.dir.z = (float)(this.dir.z / n); + } + + if (this.bounceDamp < 1.0) { + this.linearVel = this.linearVel * this.bounceDamp; + if (this.linearVel < 0.2 && this.linearVel > -0.2) { + this.linearVel = 0.0F; + } + } + } + } + + @Override + public String toString() { + return super.toString() + + "[" + + this.getName() + + ": lin. velocity " + + this.linearVel + + ", lin. damp " + + this.linearDamp + + ", direction " + + this.dir + + ", ang. vel " + + this.angularVel + + ", ang. damp " + + this.angularDamp + + ", axis " + + this.axis + + "]"; + } + + @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 = FloatPropertyEditor.make(new Property(this, index, "Linear Velocity")); + } else if (mode == 1) { + ret = new Float(this.linearVel); + } else if (mode == 2) { + this.linearVel = (Float)value; + } + break; + case 1: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Linear Damping")); + } else if (mode == 1) { + ret = new Float(this.linearDamp); + } else if (mode == 2) { + this.linearDamp = (Float)value; + } + break; + case 2: + if (mode == 0) { + ret = Point3PropertyEditor.make(new Property(this, index, "Direction")); + } else if (mode == 1) { + ret = new Point3(this.dir); + } else if (mode == 2) { + this.dir = (Point3)value; + } + break; + case 3: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Angular Velocity")); + } else if (mode == 1) { + ret = new Float(this.angularVel); + } else if (mode == 2) { + this.angularVel = (Float)value; + } + break; + case 4: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Angular Damping")); + } else if (mode == 1) { + ret = new Float(this.angularDamp); + } else if (mode == 2) { + this.angularDamp = (Float)value; + } + break; + case 5: + if (mode == 0) { + ret = Point3PropertyEditor.make(new Property(this, index, "Axis")); + } else if (mode == 1) { + ret = new Point3(this.axis); + } else if (mode == 2) { + this.axis = (Point3)value; + } + break; + case 6: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Gravitational Acceleration")); + } else if (mode == 1) { + ret = new Float(this.gravity); + } else if (mode == 2) { + this.gravity = (Float)value; + } + break; + case 7: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Bounce Damping (1 = superball, 0 = beanbag)")); + } else if (mode == 1) { + ret = new Float(this.bounceDamp); + } else if (mode == 2) { + this.bounceDamp = (Float)value; + this.bounceDamp = (float)Math.max(0.0, Math.min(1.0, (double)this.bounceDamp)); + } + break; + default: + ret = super.properties(index, offset + 8, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + s.saveFloat(this.linearVel); + s.saveFloat(this.linearDamp); + s.save(this.dir); + s.saveFloat(this.angularVel); + s.saveFloat(this.angularDamp); + s.save(this.axis); + s.saveFloat(this.gravity); + s.saveFloat(this.bounceDamp); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this.linearVel = r.restoreFloat(); + this.linearDamp = r.restoreFloat(); + this.dir = (Point3)r.restore(); + this.angularVel = r.restoreFloat(); + this.angularDamp = r.restoreFloat(); + this.axis = (Point3)r.restore(); + this.gravity = r.restoreFloat(); + this.bounceDamp = r.restoreFloat(); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/TransAttribute.java b/NET/worlds/scape/TransAttribute.java new file mode 100644 index 0000000..bd74407 --- /dev/null +++ b/NET/worlds/scape/TransAttribute.java @@ -0,0 +1,214 @@ +package NET.worlds.scape; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class TransAttribute extends Attribute { + private Point3 defPos; + private Point3 defRAxis; + private float defRotation; + private Point3 defScale; + private int _sharingMode = 57344; + private static Object classCookie = new Object(); + + public TransAttribute(int attrID) { + super(attrID); + } + + public TransAttribute() { + } + + @Override + protected void noteAddingTo(SuperRoot owner) { + WObject w = (WObject)((Sharer)owner).getOwner(); + w._transformAttribute = this; + this.initDefault(); + } + + @Override + public void detach() { + WObject w = (WObject)((Sharer)this.getOwner()).getOwner(); + w._transformAttribute = null; + super.detach(); + } + + @Override + public void noteChange() { + if (!TCompressor.dontSend) { + super.noteChange(); + } + } + + @Override + public void generateNetData(DataOutputStream s) throws IOException { + WObject w = (WObject)this.getOwner().getOwner(); + if (this._shorthandVersion == 0) { + Point3Temp pos = w.getPosition(); + s.writeFloat(pos.x); + s.writeFloat(pos.y); + s.writeFloat(pos.z); + Point3Temp scale = w.getScale(); + s.writeFloat(scale.x); + s.writeFloat(scale.y); + s.writeFloat(scale.z); + } else { + this.initDefault(); + TCompressor.compress(w, this.defPos, this.defRAxis, this.defRotation, this.defScale, this._sharingMode, s); + } + } + + private void initDefault() { + if (this.defPos == null) { + WObject w = (WObject)((Sharer)this.getOwner()).getOwner(); + this.defPos = new Point3(w.getPosition()); + this.defRAxis = new Point3(); + this.defRotation = w.getSpin(this.defRAxis); + this.defScale = new Point3(w.getScale()); + } + } + + @Override + public void setFromNetData(DataInputStream ds, int len) throws IOException { + WObject w = (WObject)this.getOwner().getOwner(); + this.initDefault(); + + try { + TCompressor.decompress(w, this.defPos, this.defRAxis, this.defRotation, this.defScale, this._sharingMode, len, ds); + } catch (IOException var5) { + TCompressor.dontSend = false; + throw var5; + } + } + + public boolean getSharingPosition() { + return (this._sharingMode & 32768) != 0; + } + + public void setSharingPosition(boolean b) { + if (b) { + this._sharingMode |= 32768; + } else { + this._sharingMode &= -32769; + } + } + + public boolean getSharingRotation() { + return (this._sharingMode & 16384) != 0; + } + + public void setSharingRotation(boolean b) { + if (b) { + this._sharingMode |= 16384; + } else { + this._sharingMode &= -16385; + } + } + + public boolean getSharingScale() { + return (this._sharingMode & 8192) != 0; + } + + public void setSharingScale(boolean b) { + if (b) { + this._sharingMode |= 8192; + } else { + this._sharingMode &= -8193; + } + } + + @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 = BooleanPropertyEditor.make(new Property(this, index, "Share Position"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.getSharingPosition()); + } else if (mode == 2) { + this.setSharingPosition((Boolean)value); + } + break; + case 1: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Share Rotation"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.getSharingRotation()); + } else if (mode == 2) { + this.setSharingRotation((Boolean)value); + } + break; + case 2: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Share Scale"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.getSharingScale()); + } else if (mode == 2) { + this.setSharingScale((Boolean)value); + } + break; + default: + ret = super.properties(index, offset + 3, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(2, classCookie); + super.saveState(s); + this.initDefault(); + s.saveInt(this._sharingMode); + s.saveFloat(this.defPos.x); + s.saveFloat(this.defPos.y); + s.saveFloat(this.defPos.z); + s.saveFloat(this.defRAxis.x); + s.saveFloat(this.defRAxis.y); + s.saveFloat(this.defRAxis.z); + s.saveFloat(this.defRotation); + s.saveFloat(this.defScale.x); + s.saveFloat(this.defScale.y); + s.saveFloat(this.defScale.z); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + int vers = r.restoreVersion(classCookie); + switch (vers) { + case 0: + super.restoreState(r); + break; + case 1: + case 2: + this.defPos = new Point3(); + this.defRAxis = new Point3(); + this.defScale = new Point3(); + super.restoreState(r); + this._sharingMode = r.restoreInt(); + this.defPos.x = r.restoreFloat(); + this.defPos.y = r.restoreFloat(); + this.defPos.z = r.restoreFloat(); + this.defRAxis.x = r.restoreFloat(); + this.defRAxis.y = r.restoreFloat(); + this.defRAxis.z = r.restoreFloat(); + this.defRotation = r.restoreFloat(); + this.defScale.x = r.restoreFloat(); + this.defScale.y = r.restoreFloat(); + this.defScale.z = r.restoreFloat(); + break; + default: + throw new TooNewException(); + } + + if (vers < 2) { + this._shorthandVersion = vers; + } + } + + @Override + public int getMaxShorthandVersion() { + return 1; + } +} diff --git a/NET/worlds/scape/Transform.java b/NET/worlds/scape/Transform.java new file mode 100644 index 0000000..8b7bc26 --- /dev/null +++ b/NET/worlds/scape/Transform.java @@ -0,0 +1,362 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.Main; +import java.io.IOException; +import java.util.Vector; + +public class Transform extends SuperRoot { + private static Vector<Transform> recycled = new Vector<Transform>(); + private int transformID; + private float xScale; + private float yScale; + private float zScale; + private static Object classCookie = new Object(); + + static { + nativeInit(); + } + + public static native void nativeInit(); + + public static Transform make() { + assert Main.isMainThread(); + + int last = recycled.size() - 1; + if (last == -1) { + return new Transform(); + } else { + Transform ret = recycled.elementAt(last); + recycled.removeElementAt(last); + return ret; + } + } + + public void recycle() { + if (recycled.size() < 100) { + this.makeIdentity(); + recycled.addElement(this); + } + } + + protected Transform() { + this.makeIdentity(); + } + + public native float getX(); + + public native float getY(); + + public native float getZ(); + + public Point3Temp getPosition() { + return Point3Temp.make(this.getX(), this.getY(), this.getZ()); + } + + public void setZ(float z) { + this.moveTo(this.getX(), this.getY(), z); + } + + public float getScaleX() { + return this.xScale; + } + + public float getScaleY() { + return this.yScale; + } + + public float getScaleZ() { + return this.zScale; + } + + public Point3Temp getScale() { + return Point3Temp.make(this.getScaleX(), this.getScaleY(), this.getScaleZ()); + } + + public float getTotalScale() { + return (this.getScaleX() + this.getScaleY() + this.getScaleZ()) / 3.0F; + } + + public native float getYaw(); + + public native float getPitch(); + + public native float getSpin(Point3Temp var1); + + protected void noteTransformChange() { + } + + public Transform raise(float z) { + return this.moveBy(0.0F, 0.0F, z); + } + + public Transform lower(float z) { + return this.moveBy(0.0F, 0.0F, -z); + } + + public Transform yaw(float a) { + return this.spin(0.0F, 0.0F, 1.0F, a); + } + + public Transform roll(float a) { + return this.spin(0.0F, 1.0F, 0.0F, a); + } + + public Transform pitch(float a) { + return this.spin(1.0F, 0.0F, 0.0F, a); + } + + public Transform scale(float s) { + return this.scale(s, s, s); + } + + @Override + protected void finalize() { + this.nativeFinalize(); + super.finalize(); + } + + public native Transform pre(Transform var1); + + public Transform post(Transform t) { + Point3Temp v = t.getScale(); + if (!this.checkPostScale(v)) { + return this; + } else { + this.xScale = this.xScale * v.x; + this.yScale = this.yScale * v.y; + this.zScale = this.zScale * v.z; + return this.postHelper(t); + } + } + + private boolean checkPostScale(Point3Temp v) { + if (this.getSpin(Point3Temp.make()) != 0.0F && (v.x != v.y || v.y != v.z)) { + Console.println(Console.message("non-uniform")); + return false; + } else { + return true; + } + } + + private native Transform postHelper(Transform var1); + + public native Transform makeIdentity(); + + public Transform moveBy(Point3Temp p) { + return this.moveBy(p.x, p.y, p.z); + } + + public native Transform moveBy(float var1, float var2, float var3); + + public Transform moveTo(Point3Temp p) { + return this.moveTo(p.x, p.y, p.z); + } + + public native Transform moveTo(float var1, float var2, float var3); + + public native Transform premoveBy(float var1, float var2, float var3); + + public native Transform scale(float var1, float var2, float var3); + + public Transform scale(Point3Temp s) { + return this.scale(s.x, s.y, s.z); + } + + public void setScale(float x, float y, float z) { + this.scale(x / this.xScale, y / this.yScale, z / this.zScale); + } + + public void setScale(Point3Temp s) { + this.setScale(s.x, s.y, s.z); + } + + public Transform postscale(float x, float y, float z) { + return this.postscale(Point3Temp.make(x, y, z)); + } + + public Transform postscale(Point3Temp s) { + if (!this.checkPostScale(s)) { + return this; + } else { + this.xScale = this.xScale * s.x; + this.yScale = this.yScale * s.y; + this.zScale = this.zScale * s.z; + return this.postscaleHelper(s.x, s.y, s.z); + } + } + + private native Transform postscaleHelper(float var1, float var2, float var3); + + public Transform worldScale(float x, float y, float z) { + return this.worldScale(Point3Temp.make(x, y, z)); + } + + public Transform worldScale(Point3Temp s) { + return !this.checkPostScale(s) ? this : this.scale(s); + } + + public native Transform spin(float var1, float var2, float var3, float var4); + + public Transform spin(Point3Temp p, float a) { + return this.spin(p.x, p.y, p.z, a); + } + + public Transform postspin(Point3Temp axis, float a) { + return this.postspin(axis.x, axis.y, axis.z, a); + } + + public native Transform postspin(float var1, float var2, float var3, float var4); + + public Transform worldSpin(float x, float y, float z, float a) { + return this.spin(this.worldVecToObjectVec(Point3Temp.make(x, y, z)), a); + } + + private native void nativeFinalize(); + + public Transform getTransform() { + Transform t = make(); + t.setTransform(this); + return t; + } + + public native void setTransform(Transform var1); + + public native Transform invert(); + + public Transform getObjectToWorldMatrix() { + return this.getTransform(); + } + + private Point3Temp worldVecToObjectVec(Point3Temp worldVec) { + Transform inv = this.getObjectToWorldMatrix().invert(); + Point3Temp p = Point3Temp.make(worldVec).vectorTimes(inv).times(this.getScale()); + inv.recycle(); + return p; + } + + @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 = TransformPropertyEditor.make(new Property(this, index, "Transform")); + } else if (mode == 1) { + ret = this.getTransform(); + } else if (mode == 2) { + this.setTransform((Transform)value); + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(2, classCookie); + super.saveState(s); + s.saveFloat(this.xScale); + s.saveFloat(this.yScale); + s.saveFloat(this.zScale); + float[] guts = this.getGuts(); + + for (int i = 0; i < 16; i++) { + s.saveFloat(guts[i]); + } + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 1: + super.restoreState(r); + case 0: + this.xScale = this.yScale = this.zScale = r.restoreFloat(); + float[] guts = new float[16]; + + for (int i = 0; i < 16; i++) { + guts[i] = r.restoreFloat(); + } + + this.setGuts(guts); + break; + case 2: + super.restoreState(r); + this.xScale = r.restoreFloat(); + this.yScale = r.restoreFloat(); + this.zScale = r.restoreFloat(); + float[] guts = new float[16]; + + for (int i = 0; i < 16; i++) { + guts[i] = r.restoreFloat(); + } + + this.setGuts(guts); + break; + default: + throw new TooNewException(); + } + } + + private native float[] getGuts(); + + public native boolean isTransformEqual(Transform var1); + + private native void setGuts(float[] var1); + + public String toTransformSubstring() { + Point3Temp axis = Point3Temp.make(); + float angle = this.getSpin(axis); + Point3Temp pos = this.getPosition(); + return angle == 0.0F && this.xScale == 1.0F && this.yScale == 1.0F && this.zScale == 1.0F && pos.x == 0.0F && pos.y == 0.0F && pos.z == 0.0F + ? "[identity]" + : "[pos (" + + pos + + "), scale (" + + (this.xScale == this.yScale && this.yScale == this.zScale ? "" + this.xScale : this.xScale + "," + this.yScale + "," + this.zScale) + + "), rot (" + + axis + + "@" + + angle + + ")]"; + } + + @Override + public String toString() { + return this.getName() + this.toTransformSubstring(); + } + + public Transform printGuts() { + float[] arr = this.getGuts(); + + assert arr.length == 16; + + String[] strs = new String[16]; + int maxStr = 0; + + for (int i = 0; i < 16; i++) { + strs[i] = Float.toString(arr[i]); + maxStr = Math.max(maxStr, strs[i].length()); + } + + for (int j = 0; j < 4; j++) { + for (int k = 0; k < 4; k++) { + String s = strs[j * 4 + k]; + int pad = maxStr - s.length() + 1; + System.out.print(s); + + while (pad-- != 0) { + System.out.print(" "); + } + } + + System.out.println(""); + } + + return this; + } +} diff --git a/NET/worlds/scape/TransformEditorDialog.java b/NET/worlds/scape/TransformEditorDialog.java new file mode 100644 index 0000000..d7b5a21 --- /dev/null +++ b/NET/worlds/scape/TransformEditorDialog.java @@ -0,0 +1,341 @@ +package NET.worlds.scape; + +import NET.worlds.console.ConfirmDialog; +import NET.worlds.console.Console; +import NET.worlds.console.DialogReceiver; +import NET.worlds.console.PolledDialog; +import java.awt.Button; +import java.awt.Component; +import java.awt.Font; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.Label; +import java.awt.TextField; +import java.text.MessageFormat; +import java.util.StringTokenizer; +import java.util.Vector; + +class TransformEditorDialog extends PolledDialog implements DialogReceiver { + Property property; + Transform transform; + int undoCount; + Button undoButton = new Button(Console.message("Undo")); + Button okButton = new Button(Console.message("OK")); + Button cancelButton = new Button(Console.message("Cancel")); + Button pitch = new MyButton(Console.message("Pitch-N"), 0, 1); + Button roll = new MyButton(Console.message("Roll-N"), 0, 1); + Button yaw = new MyButton(Console.message("Yaw-N"), 0, 1); + Button spin = new MyButton(Console.message("Spin-by-XYZN"), 3, 1); + Button spinTo = new MyButton(Console.message("Spin-to-XYZN"), 3, 1); + Button moveX = new MyButton(Console.message("Move-x-by-N"), 0, 1); + Button moveY = new MyButton(Console.message("Move-y-by-N"), 0, 1); + Button moveZ = new MyButton(Console.message("Move-z-by-N"), 0, 1); + Button moveBy = new MyButton(Console.message("Move-by-XYZ"), 3, 0); + Button moveTo = new MyButton(Console.message("Move-to-XYZ"), 3, 0); + Button scaleX = new MyButton(Console.message("Scale-x-by-N"), 0, 1); + Button scaleY = new MyButton(Console.message("Scale-y-by-N"), 0, 1); + Button scaleZ = new MyButton(Console.message("Scale-z-by-N"), 0, 1); + Button scaleBy = new MyButton(Console.message("Scale-by-N"), 0, 1); + Button scaleTo = new MyButton(Console.message("Scale-to-N"), 0, 1); + Label position = new Label(); + Label rotation = new Label(); + Label scale = new Label(); + TextField editXYZ = new TextField(); + TextField editN = new TextField(); + GridBagLayout gbag = new GridBagLayout(); + GridBagConstraints c = new GridBagConstraints(); + Font normalFont; + Font selectedFont; + Button selectedButton; + TextField lastEdit; + EditTile parent; + Object queuedFunc; + private static Object lastPosAndSize; + + TransformEditorDialog(EditTile parent, String title, Property property) { + super(Console.getFrame(), parent, title, false); + this.property = property; + this.parent = parent; + this.ready(); + } + + @Override + protected void build() { + this.transform = (Transform)this.property.get(); + this.setLayout(this.gbag); + this.add2(new Label("(X,Y,Z):"), this.editXYZ); + this.add2(new Label("(N):"), this.editN); + this.add3(this.moveX, this.pitch, this.scaleX); + this.add3(this.moveY, this.roll, this.scaleY); + this.add3(this.moveZ, this.yaw, this.scaleZ); + this.add3(this.moveBy, this.spin, this.scaleBy); + this.add3(this.moveTo, this.spinTo, this.scaleTo); + this.add2(new Label(Console.message("Position")), this.position); + this.add2(new Label(Console.message("Rotation:")), this.rotation); + this.add2(new Label(Console.message("Scale:")), this.scale); + this.addButtons(this.undoButton, this.okButton, this.cancelButton); + this.normalFont = this.pitch.getFont(); + this.selectedFont = new Font(this.normalFont.getName(), this.normalFont.isBold() ? 0 : 1, this.normalFont.getSize()); + this.updateInfo(); + } + + private void add2(Component c1, Component c2) { + this.c.fill = 0; + this.c.anchor = 13; + this.c.gridheight = 1; + this.c.weightx = 1.0; + this.c.weighty = 1.0; + this.c.gridwidth = 1; + this.add(this.gbag, c1, this.c); + this.c.anchor = 17; + this.c.fill = 2; + this.c.gridwidth = 0; + this.add(this.gbag, c2, this.c); + } + + private void add3(Component c1, Component c2, Component c3) { + this.c.fill = 2; + this.c.anchor = 17; + this.c.gridheight = 1; + this.c.gridwidth = 3; + this.c.weightx = 1.0; + this.c.weighty = 1.0; + this.add(this.gbag, c1, this.c); + this.c.weightx = 0.0; + this.c.weighty = 0.0; + this.add(this.gbag, c2, this.c); + this.c.gridwidth = 0; + this.add(this.gbag, c3, this.c); + } + + private void addButtons(Component c1, Component c2, Component c3) { + this.c.fill = 0; + this.c.anchor = 13; + this.c.gridheight = 1; + this.c.gridwidth = 3; + this.c.weightx = 1.0; + this.c.weighty = 1.0; + this.add(this.gbag, c1, this.c); + this.c.anchor = 10; + this.add(this.gbag, c2, this.c); + this.c.anchor = 17; + this.add(this.gbag, c3, this.c); + } + + private void selectButton(Button button) { + if (this.selectedButton != null) { + this.selectedButton.setFont(this.normalFont); + } + + this.selectedButton = button; + this.selectedButton.setFont(this.selectedFont); + } + + private void updateInfo() { + this.position.setText(this.transform.getPosition().toString()); + this.scale.setText(this.transform.getScale().toString()); + Point3Temp axis = Point3Temp.make(); + float angle = this.transform.getSpin(axis); + Object[] arguments = new Object[]{new String("" + axis), new String("" + angle)}; + this.rotation.setText(MessageFormat.format(Console.message("angle"), arguments)); + this.undoButton.enable(this.undoCount != 0); + } + + private void set(Transform t) { + this.parent.addUndoableSet(this.property, t); + this.undoCount++; + this.transform = (Transform)this.property.get(); + } + + @Override + protected synchronized void activeCallback() { + if (this.queuedFunc == this.undoButton) { + if (this.undoCount != 0) { + this.parent.undo(); + this.undoCount--; + this.transform = (Transform)this.property.get(); + this.updateInfo(); + } + } else if (this.queuedFunc instanceof MyButton) { + this.apply((MyButton)this.queuedFunc); + } + + this.queuedFunc = null; + } + + public boolean undoAll() { + if (this.undoCount == 0) { + return this.done(false); + } else { + new ConfirmDialog(this, Console.message("Cancel-Transform"), Console.message("undo-changes")); + return true; + } + } + + @Override + public synchronized void dialogDone(Object who, boolean confirmed) { + if (confirmed) { + while (this.undoCount != 0) { + this.parent.undo(); + this.undoCount--; + } + + this.done(false); + } + } + + @Override + public synchronized boolean action(java.awt.Event event, Object what) { + Object target = event.target; + if (target == this.okButton) { + return this.done(true); + } else if (target == this.cancelButton) { + return this.undoAll(); + } else if ((target == this.undoButton || target instanceof MyButton) && this.queuedFunc == null) { + this.queuedFunc = target; + return true; + } else { + return false; + } + } + + private float[] parseNumbers(TextField edit) { + Vector vec = new Vector(); + StringTokenizer e = new StringTokenizer(edit.getText().trim(), ", \t", false); + + while (e.hasMoreElements()) { + try { + vec.addElement(Float.valueOf(e.nextToken())); + } catch (NumberFormatException var6) { + vec.removeAllElements(); + break; + } + } + + float[] ret = new float[vec.size()]; + + for (int i = 0; i < ret.length; i++) { + ret[i] = (Float)vec.elementAt(i); + } + + return ret; + } + + private boolean apply(MyButton func) { + float[] n = this.parseNumbers(this.editN); + float[] xyz = this.parseNumbers(this.editXYZ); + if (func.numParamsXYZ != 0 && func.numParamsXYZ != xyz.length) { + return this.setEdit(this.editXYZ); + } else if (func.numParamsN != 0 && func.numParamsN != n.length) { + return this.setEdit(this.editN); + } else { + if (func == this.pitch) { + this.transform.worldSpin(1.0F, 0.0F, 0.0F, n[0]); + } else if (func == this.roll) { + this.transform.worldSpin(0.0F, 1.0F, 0.0F, n[0]); + } else if (func == this.yaw) { + this.transform.worldSpin(0.0F, 0.0F, 1.0F, n[0]); + } else if (func == this.spin) { + this.transform.worldSpin(xyz[0], xyz[1], xyz[2], n[0]); + } else if (func == this.spinTo) { + Point3Temp scale = this.transform.getScale(); + Point3Temp pos = this.transform.getPosition(); + this.transform.makeIdentity(); + this.transform.scale(scale); + this.transform.worldSpin(xyz[0], xyz[1], xyz[2], n[0]); + this.transform.moveTo(pos.x, pos.y, pos.z); + } else if (func == this.moveX) { + this.transform.moveBy(n[0], 0.0F, 0.0F); + } else if (func == this.moveY) { + this.transform.moveBy(0.0F, n[0], 0.0F); + } else if (func == this.moveZ) { + this.transform.moveBy(0.0F, 0.0F, n[0]); + } else if (func == this.moveBy) { + this.transform.moveBy(xyz[0], xyz[1], xyz[2]); + } else if (func == this.moveTo) { + this.transform.moveTo(xyz[0], xyz[1], xyz[2]); + } else if (func == this.scaleX && n[0] != 0.0F && this.checkScale(n[0], this.transform.getScaleX())) { + this.transform.scale(n[0], 1.0F, 1.0F); + } else if (func == this.scaleY && n[0] != 0.0F && this.checkScale(n[0], this.transform.getScaleY())) { + this.transform.scale(1.0F, n[0], 1.0F); + } else if (func == this.scaleZ && n[0] != 0.0F && this.checkScale(n[0], this.transform.getScaleZ())) { + this.transform.scale(1.0F, 1.0F, n[0]); + } else if (func == this.scaleBy + && n[0] != 0.0F + && this.checkScale(n[0], this.transform.getScaleX()) + && this.checkScale(n[0], this.transform.getScaleY()) + && this.checkScale(n[0], this.transform.getScaleZ())) { + this.transform.scale(n[0]); + } else { + if (func != this.scaleTo || n[0] == 0.0F) { + return true; + } + + Point3Temp scale = this.transform.getScale(); + this.transform.scale(n[0] / scale.x, n[0] / scale.y, n[0] / scale.z); + } + + this.set(this.transform); + this.selectButton(func); + this.updateInfo(); + return this.setEdit(this.lastEdit); + } + } + + private boolean checkScale(float oldScale, float factor) { + double newScale = (double)oldScale * factor; + if (newScale < 2.938736052218037E-39) { + Console.println(Console.message("exceed-minimum")); + } else { + if (!(newScale > Float.MAX_VALUE)) { + return true; + } + + Console.println(Console.message("exceed-maximum")); + } + + return false; + } + + private boolean toggleEdit() { + return this.lastEdit == this.editN ? this.setEdit(this.editXYZ) : this.setEdit(this.editN); + } + + private boolean setEdit(TextField edit) { + edit.requestFocus(); + edit.selectAll(); + this.lastEdit = edit; + return true; + } + + @Override + public boolean keyDown(java.awt.Event event, int key) { + if (event.target == this.editXYZ || event.target == this.editN) { + this.lastEdit = (TextField)event.target; + } + + if (key == 27) { + return this.undoAll(); + } else if (key == 10) { + return this.done(true); + } else { + return key == 9 ? this.toggleEdit() : super.keyDown(event, key); + } + } + + @Override + public void show() { + super.show(); + this.setEdit(this.editXYZ); + } + + @Override + public void savePosAndSize(Object state) { + lastPosAndSize = state; + } + + @Override + public Object restorePosAndSize() { + return lastPosAndSize; + } +} diff --git a/NET/worlds/scape/TransformPropertyEditor.java b/NET/worlds/scape/TransformPropertyEditor.java new file mode 100644 index 0000000..22ec6ef --- /dev/null +++ b/NET/worlds/scape/TransformPropertyEditor.java @@ -0,0 +1,19 @@ +package NET.worlds.scape; + +import NET.worlds.console.PolledDialog; + +public class TransformPropertyEditor extends PropEditor { + private TransformPropertyEditor(Property property) { + super(property); + } + + @Override + public PolledDialog edit(EditTile parent, String title) { + return new TransformEditorDialog(parent, title, this.property); + } + + public static Property make(Property property) { + property.setPropertyType(9); + return property.setEditor(new TransformPropertyEditor(property)); + } +} diff --git a/NET/worlds/scape/Trigger.java b/NET/worlds/scape/Trigger.java new file mode 100644 index 0000000..a056535 --- /dev/null +++ b/NET/worlds/scape/Trigger.java @@ -0,0 +1,199 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import java.io.IOException; +import java.text.MessageFormat; + +public class Trigger extends SwitchableBehavior implements FrameHandler, Persister, MouseDownHandler, BumpHandler { + public static TriggeredSwitchableBehavior[] TriggeredSwitchableBehaviorList = new TriggeredSwitchableBehavior[1000]; + public static int TriggeredSwitchableBehaviorListCount = 0; + public String trigger = new String("none"); + public String targetTriggerTag = new String(""); + public String[][] targetTriggerTagArray = new String[20][10]; + public int targetTriggerTagCount = 0; + public int[] finishedTriggerTagSequenceNo = new int[50]; + public int[] finishedTriggerTagEventNo = new int[50]; + public int finishedTriggerTagCount = 0; + + private void addTargetTriggerTagArray(String[] sequentialTargetTriggerTagArray, String targetTriggerTag) { + int currentIndex = 1; + int currentSeparator = 0; + int nextSeparator = 0; + int lastSeparator = targetTriggerTag.lastIndexOf("+"); + if (lastSeparator == -1 && targetTriggerTag.length() == 0) { + int var8 = 0; + sequentialTargetTriggerTagArray[0] = String.valueOf((int)var8); + } else if (lastSeparator == -1) { + sequentialTargetTriggerTagArray[currentIndex] = targetTriggerTag; + sequentialTargetTriggerTagArray[0] = String.valueOf(currentIndex); + } else { + nextSeparator = targetTriggerTag.indexOf("+"); + sequentialTargetTriggerTagArray[currentIndex] = targetTriggerTag.substring(0, nextSeparator); + currentIndex++; + + while (nextSeparator != lastSeparator) { + currentSeparator = nextSeparator; + nextSeparator = targetTriggerTag.indexOf("+", nextSeparator + 1); + sequentialTargetTriggerTagArray[currentIndex] = targetTriggerTag.substring(currentSeparator + 1, nextSeparator); + currentIndex++; + } + + sequentialTargetTriggerTagArray[currentIndex] = targetTriggerTag.substring(nextSeparator + 1); + sequentialTargetTriggerTagArray[0] = String.valueOf(currentIndex); + } + } + + public void preprocessTargetTriggerTag(String targetTriggerTag) { + int currentIndex = 1; + int currentSeparator = 0; + int nextSeparator = 0; + int lastSeparator = targetTriggerTag.lastIndexOf(" "); + if (lastSeparator != -1 || targetTriggerTag.length() != 0) { + if (lastSeparator == -1) { + this.addTargetTriggerTagArray(this.targetTriggerTagArray[currentIndex], targetTriggerTag); + this.targetTriggerTagCount = currentIndex; + } else { + nextSeparator = targetTriggerTag.indexOf(" "); + this.addTargetTriggerTagArray(this.targetTriggerTagArray[currentIndex], targetTriggerTag.substring(0, nextSeparator)); + currentIndex++; + + while (nextSeparator != lastSeparator) { + currentSeparator = nextSeparator; + nextSeparator = targetTriggerTag.indexOf(" ", nextSeparator + 1); + this.addTargetTriggerTagArray(this.targetTriggerTagArray[currentIndex], targetTriggerTag.substring(currentSeparator + 1, nextSeparator)); + currentIndex++; + } + + this.addTargetTriggerTagArray(this.targetTriggerTagArray[currentIndex], targetTriggerTag.substring(nextSeparator + 1)); + this.targetTriggerTagCount = currentIndex; + } + } + } + + public void activateTrigger() { + for (int j = 1; j <= this.targetTriggerTagCount; j++) { + boolean match = false; + + for (int i = 0; !match && i < TriggeredSwitchableBehaviorListCount; i++) { + if (this.targetTriggerTagArray[j][1].equals(TriggeredSwitchableBehaviorList[i].externalTriggerTag) && TriggeredSwitchableBehaviorList[i] != null) { + TriggeredSwitchableBehaviorList[i].ExternalTrigger(this, j, 1); + } + } + } + } + + public void activateSequenceTrigger() { + for (int j = this.finishedTriggerTagCount; j > 0; j--) { + int sequence_no = this.finishedTriggerTagSequenceNo[j]; + int event_no = this.finishedTriggerTagEventNo[j]; + if (Integer.valueOf(this.targetTriggerTagArray[sequence_no][0]) > event_no) { + boolean match = false; + + for (int i = 0; !match && i < TriggeredSwitchableBehaviorListCount; i++) { + if (this.targetTriggerTagArray[sequence_no][event_no + 1].equals(TriggeredSwitchableBehaviorList[i].externalTriggerTag) + && TriggeredSwitchableBehaviorList[i] != null) { + TriggeredSwitchableBehaviorList[i].ExternalTrigger(this, sequence_no, event_no + 1); + } + } + } + } + + this.finishedTriggerTagCount = 0; + } + + public synchronized void registerFinishedTriggerTag(int sequence_no, int event_no) { + this.finishedTriggerTagCount++; + this.finishedTriggerTagSequenceNo[this.finishedTriggerTagCount] = sequence_no; + this.finishedTriggerTagEventNo[this.finishedTriggerTagCount] = event_no; + } + + @Override + public boolean handle(FrameEvent e) { + if (this.enabled && this.finishedTriggerTagCount > 0) { + this.activateSequenceTrigger(); + } + + return true; + } + + @Override + public boolean handle(MouseDownEvent e) { + if (this.enabled && this.trigger.equals("click")) { + this.activateTrigger(); + } + + return true; + } + + @Override + public boolean handle(BumpEventTemp e) { + if (this.enabled && this.trigger.equals("bump")) { + this.activateTrigger(); + } + + return true; + } + + @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 = StringPropertyEditor.make(new Property(this, index, "Trigger")); + } else if (mode == 1) { + ret = new String(this.trigger); + } else if (mode == 2) { + this.trigger = ((String)value).toString().trim(); + } + break; + case 1: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Target Trigger Tag")); + } else if (mode == 1) { + ret = new String(this.targetTriggerTag); + } else if (mode == 2) { + this.targetTriggerTag = ((String)value).toString().trim(); + this.preprocessTargetTriggerTag(this.targetTriggerTag); + } + break; + default: + ret = super.properties(index, offset + 2, mode, value); + } + + return ret; + } + + @Override + public String toString() { + return super.toString() + "[enabled " + this.enabled + ", trigger " + this.trigger + ", targetTriggerTag " + this.targetTriggerTag + "]"; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveString(this.trigger); + s.saveString(this.targetTriggerTag); + } + + @Override + public void restoreState(Restorer r) throws IOException { + this.trigger = r.restoreString(); + this.targetTriggerTag = r.restoreString(); + this.preprocessTargetTriggerTag(this.targetTriggerTag); + } + + @Override + public void postRestore(int version) { + String name = this.getName(); + String arg1 = name == null ? "<null>" : name; + SuperRoot owner = this.getOwner(); + String oname = ""; + if (owner != null) { + oname = owner.getName(); + } + + String arg2 = oname == null ? "<null>" : oname; + Object[] arguments = new Object[]{new String(arg1), new String(arg2)}; + Console.println(MessageFormat.format(Console.message("Trigger-obs"), arguments)); + } +} diff --git a/NET/worlds/scape/TriggeredSwitchableBehavior.java b/NET/worlds/scape/TriggeredSwitchableBehavior.java new file mode 100644 index 0000000..07d73b8 --- /dev/null +++ b/NET/worlds/scape/TriggeredSwitchableBehavior.java @@ -0,0 +1,11 @@ +package NET.worlds.scape; + +public abstract class TriggeredSwitchableBehavior extends SwitchableBehavior { + public String trigger; + public String externalTriggerTag; + public int sequence_no; + public int event_no; + Trigger trigger_source = null; + + public abstract void ExternalTrigger(Trigger var1, int var2, int var3); +} diff --git a/NET/worlds/scape/TwoWayPortal.java b/NET/worlds/scape/TwoWayPortal.java new file mode 100644 index 0000000..c9c3b0c --- /dev/null +++ b/NET/worlds/scape/TwoWayPortal.java @@ -0,0 +1,64 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class TwoWayPortal extends Portal { + private static Object classCookie = new Object(); + + public TwoWayPortal(String targetRoom, float llx, float lly, float llz, float urx, float ury, float urz) { + super(llx, lly, llz, urx, ury, urz); + this.setFarSideInfo(null, targetRoom, null); + } + + public TwoWayPortal() { + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + int vers = r.restoreVersion(classCookie); + switch (vers) { + case 0: + super.restoreState(r); + return; + default: + throw new TooNewException(); + } + } + + @Override + public void detach() throws ClassCastException { + super.detach(); + Portal p = this.farSide(); + if (p != null) { + p.detach(); + } + } + + @Override + public void reset(boolean showmessage) { + super.reset(showmessage); + if (this.farSideRoom() != null) { + Portal p = this.farSide(); + if (p != null) { + if (p.isActive()) { + return; + } + + p.detach(); + this.bidisconnect(); + } + + Point3Temp left = this.getWorldPosition(); + Point3Temp right = this.getFarCorner(); + p = new Portal(right.x, right.y, left.z, left.x, left.y, right.z); + this.farSideRoom().add(p); + this.biconnect(p); + } + } +} diff --git a/NET/worlds/scape/URLEditorDialog.java b/NET/worlds/scape/URLEditorDialog.java new file mode 100644 index 0000000..034ccdd --- /dev/null +++ b/NET/worlds/scape/URLEditorDialog.java @@ -0,0 +1,54 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.network.URL; +import java.net.MalformedURLException; +import java.util.Vector; + +class URLEditorDialog extends FieldWithListEditorDialog { + Property property; + FileList extChecker; + + URLEditorDialog(EditTile parent, String title, Property property, Vector files, FileList extChecker) { + super(parent, title + " dir: " + URL.getBestContainer((SuperRoot)property.getOwner()), files); + this.property = property; + this.extChecker = extChecker; + this.ready(); + } + + @Override + protected String getValue() { + SuperRoot context = (SuperRoot)this.property.getOwner(); + if (context != null && this.property.getName().equals("Source URL")) { + context = context.getOwner(); + } + + String s = URL.getRelativeTo((URL)this.property.get(), context); + return s == null ? "" : s; + } + + @Override + protected boolean setValue(String text) { + URL url = null; + if (text.length() == 0) { + if (!this.property.canSetNull()) { + return false; + } + } else { + if (this.extChecker != null && !this.extChecker.extMatches(text)) { + Console.println(Console.message("extension-match") + this.extChecker.getExtList()); + return false; + } + + try { + url = new URL((SuperRoot)this.property.getOwner(), text); + } catch (MalformedURLException var4) { + Console.println(Console.message("Illegal-URL") + var4); + return false; + } + } + + this.parent.addUndoableSet(this.property, url); + return true; + } +} diff --git a/NET/worlds/scape/URLPropertyEditor.java b/NET/worlds/scape/URLPropertyEditor.java new file mode 100644 index 0000000..2a346c1 --- /dev/null +++ b/NET/worlds/scape/URLPropertyEditor.java @@ -0,0 +1,73 @@ +package NET.worlds.scape; + +import NET.worlds.console.PolledDialog; +import NET.worlds.network.URL; +import java.util.Enumeration; +import java.util.Vector; + +public class URLPropertyEditor extends PropEditor { + private FileList files; + private Enumeration additions; + private boolean acceptAnyExt = false; + private boolean acceptDrops; + + private URLPropertyEditor(Property property, String extList, Enumeration additions, boolean acceptDrops) { + super(property); + this.acceptDrops = acceptDrops; + URL dir = URL.getContainingOrCurDir((SuperRoot)property.getOwner()); + if (extList == null) { + this.acceptAnyExt = true; + } else { + if (extList.startsWith("*")) { + extList = extList.substring(1); + this.acceptAnyExt = true; + } + + this.files = new FileList(dir.unalias(), extList); + } + + this.additions = additions; + } + + @Override + public PolledDialog edit(EditTile parent, String title) { + Vector v = this.files == null ? new Vector() : this.files.getList(); + if (this.additions != null) { + while (this.additions.hasMoreElements()) { + v.addElement(this.additions.nextElement().toString()); + } + } + + return new URLEditorDialog(parent, title, this.property, v, this.acceptAnyExt ? null : this.files); + } + + public static Property make(Property property, String extList) { + return make(property, extList, null, true); + } + + public static Property make(Property property, String extList, boolean acceptDrops) { + return make(property, extList, null, acceptDrops); + } + + public static Property make(Property property, String extList, Enumeration additions) { + return make(property, extList, additions, true); + } + + public static Property make(Property property, String extList, Enumeration additions, boolean acceptDrops) { + property.setPropertyType(10); + return property.setEditor(new URLPropertyEditor(property, extList, additions, acceptDrops)); + } + + @Override + public boolean libraryDrop(EditTile target, Object obj, boolean isPaste, boolean doDrop) { + if (!isPaste && this.acceptDrops && obj instanceof URL && (this.acceptAnyExt || this.files.extMatches(((URL)obj).getExt()))) { + if (doDrop) { + target.addUndoableSet(this.property, obj); + } + + return true; + } else { + return false; + } + } +} diff --git a/NET/worlds/scape/URLSelf.java b/NET/worlds/scape/URLSelf.java new file mode 100644 index 0000000..f4c8183 --- /dev/null +++ b/NET/worlds/scape/URLSelf.java @@ -0,0 +1,13 @@ +package NET.worlds.scape; + +import NET.worlds.network.URL; + +public interface URLSelf extends Persister { + void incRef(); + + void decRef(); + + URL getSourceURL(); + + void setSourceURL(URL var1); +} diff --git a/NET/worlds/scape/URLSelfLoader.java b/NET/worlds/scape/URLSelfLoader.java new file mode 100644 index 0000000..6020fde --- /dev/null +++ b/NET/worlds/scape/URLSelfLoader.java @@ -0,0 +1,182 @@ +package NET.worlds.scape; + +import NET.worlds.core.FastDataInput; +import NET.worlds.network.URL; +import java.io.IOException; +import java.util.Hashtable; +import java.util.Vector; + +public class URLSelfLoader implements BGLoaded { + private static Hashtable loaded = new Hashtable(); + private static Hashtable loading = new Hashtable(); + private URL url; + private Vector callbacks = new Vector(); + private static final int INIT = 0; + private static final int DONE = -1; + private int state = 0; + private FastDataInput inFile; + private Restorer restorer; + private URLSelf loadedObj; + public Object otemp1; + public Object otemp2; + public int itemp1; + public int itemp2; + + public static void load(URL url, LoadedURLSelf callback) { + load(url, callback, false); + } + + public static void load(URL url, LoadedURLSelf callback, boolean isHighPriority) { + URLSelf o = (URLSelf)loaded.get(url); + if (o != null) { + o.incRef(); + callback.loadedURLSelf(o, url, null); + } else { + URLSelfLoader cl = (URLSelfLoader)loading.get(url); + if (cl != null) { + cl.callbacks.addElement(callback); + } else { + new URLSelfLoader(url, callback, isHighPriority); + } + } + } + + public static void unload(URLSelf self) { + loaded.remove(self.getSourceURL()); + } + + public static void immediateLoad(IncrementalRestorer o, Restorer r) throws IOException, TooNewException { + new URLSelfLoader(o, r); + } + + private URLSelfLoader(IncrementalRestorer o, Restorer r) throws IOException, TooNewException { + this.url = null; + + while (this.state != -1) { + try { + this.state = o.incRestore(this.state, r, this); + } catch (Exception var4) { + var4.printStackTrace(System.out); + + assert false; + } + } + } + + public URL getURL() { + return this.url; + } + + private URLSelfLoader(URL url, LoadedURLSelf callback, boolean isHighPriority) { + loading.put(url, this); + this.url = url; + this.callbacks.addElement(callback); + BackgroundLoader.get(this, url, isHighPriority); + } + + @Override + public Object asyncBackgroundLoad(String localName, URL remoteName) { + if (localName == null) { + return "Can't find file " + this.url; + } else { + try { + return new FastDataInput(localName); + } catch (IOException var4) { + return "Can't load file " + this.url; + } + } + } + + @Override + public boolean syncBackgroundLoad(Object obj, URL remoteURL) { + if (obj instanceof String) { + this.doneLoading(null, (String)obj); + return false; + } else { + assert this.state != -1; + + if (this.state == 0) { + this.inFile = (FastDataInput)obj; + Object o = null; + + try { + this.restorer = new Restorer(this.inFile, this.url); + o = this.restorer.restore(false); + this.loadedObj = (URLSelf)o; + this.loadedObj.setSourceURL(this.getURL()); + if (!(this.loadedObj instanceof IncrementalRestorer)) { + this.loadedObj.restoreState(this.restorer); + this.restorer.done(); + return this.doneLoading(this.loadedObj, null); + } + } catch (Exception var7) { + var7.printStackTrace(System.out); + return this.doneLoading(null, "Can't restore from file " + this.url + ": " + var7.toString()); + } + } + + try { + this.state = ((IncrementalRestorer)this.loadedObj).incRestore(this.state, this.restorer, this); + } catch (Exception var6) { + var6.printStackTrace(System.out); + return this.doneLoading(null, var6.toString()); + } + + if (this.state == -1) { + try { + this.restorer.done(); + } catch (IOException var5) { + var5.printStackTrace(System.out); + return this.doneLoading(null, var5.toString()); + } + + if (this.restorer.version() < 3 && this.loadedObj instanceof Camera) { + Camera cam = (Camera)this.loadedObj; + World w = cam.getWorld(); + w.setSourceURL(cam.getSourceURL()); + } + + return this.doneLoading(this.loadedObj, null); + } else { + return true; + } + } + } + + private boolean doneLoading(URLSelf o, String err) { + if (this.inFile != null) { + this.inFile.close(); + this.inFile = null; + } + + loading.remove(this.url); + if (o != null) { + if (this.restorer.version() < 4 && o instanceof Camera) { + Camera c = (Camera)o; + o = c.getWorld(); + c.detach(); + } + + loaded.put(this.url, o); + } + + int end = this.callbacks.size(); + + for (int i = 0; i < end; i++) { + LoadedURLSelf callback = (LoadedURLSelf)this.callbacks.elementAt(i); + if (o != null) { + o.incRef(); + } + + callback.loadedURLSelf(o, this.url, err); + } + + this.state = -1; + return false; + } + + @Override + public Room getBackgroundLoadRoom() { + return null; + } +} diff --git a/NET/worlds/scape/UndoStack.java b/NET/worlds/scape/UndoStack.java new file mode 100644 index 0000000..5c325db --- /dev/null +++ b/NET/worlds/scape/UndoStack.java @@ -0,0 +1,41 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; + +class UndoStack { + private Undoable[] stack = new Undoable[100]; + private int stackPtr; + + Undoable peek() { + return this.stackPtr - 1 >= 0 ? this.stack[this.stackPtr - 1] : this.stack[this.stack.length - 1]; + } + + void push(Undoable undo) { + while (true) { + try { + this.stack[this.stackPtr++] = undo; + return; + } catch (IndexOutOfBoundsException var3) { + this.stackPtr = 0; + } + } + } + + boolean undo() { + while (true) { + try { + Undoable u = this.stack[--this.stackPtr]; + if (u != null) { + u.undo(); + this.stack[this.stackPtr] = null; + return true; + } + + Console.println(Console.message("No-undo")); + return false; + } catch (IndexOutOfBoundsException var2) { + this.stackPtr = this.stack.length; + } + } + } +} diff --git a/NET/worlds/scape/UndoWidget.java b/NET/worlds/scape/UndoWidget.java new file mode 100644 index 0000000..bb4d140 --- /dev/null +++ b/NET/worlds/scape/UndoWidget.java @@ -0,0 +1,14 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; + +class UndoWidget extends ClickWidget { + public UndoWidget(ToolBar toolbar) { + super(toolbar, "undo.gif", Console.message("Undo")); + } + + @Override + public void perform() { + Console.getFrame().getEditTile().undo(); + } +} diff --git a/NET/worlds/scape/UndoabCopy.java b/NET/worlds/scape/UndoabCopy.java new file mode 100644 index 0000000..606a622 --- /dev/null +++ b/NET/worlds/scape/UndoabCopy.java @@ -0,0 +1,14 @@ +package NET.worlds.scape; + +class UndoabCopy implements Undoable { + private ClipboardEntry prevClipboard = EditTile.getClipboard(); + + UndoabCopy(ClipboardEntry newClipboard) { + EditTile.setClipboard(newClipboard); + } + + @Override + public void undo() { + EditTile.setClipboard(this.prevClipboard); + } +} diff --git a/NET/worlds/scape/UndoablAdd.java b/NET/worlds/scape/UndoablAdd.java new file mode 100644 index 0000000..6de4650 --- /dev/null +++ b/NET/worlds/scape/UndoablAdd.java @@ -0,0 +1,21 @@ +package NET.worlds.scape; + +class UndoablAdd implements Undoable { + protected VectorProperty prop; + protected Object obj; + + UndoablAdd(VectorProperty prop, Object obj) { + this.prop = prop; + this.obj = obj; + prop.add(obj); + } + + @Override + public void undo() { + this.prop.delete(this.obj); + } + + public Object getObject() { + return this.obj; + } +} diff --git a/NET/worlds/scape/UndoablCut.java b/NET/worlds/scape/UndoablCut.java new file mode 100644 index 0000000..1bf4ad2 --- /dev/null +++ b/NET/worlds/scape/UndoablCut.java @@ -0,0 +1,23 @@ +package NET.worlds.scape; + +class UndoablCut extends UndoablDelete { + private ClipboardEntry prevClipboard = EditTile.getClipboard(); + private boolean clipValid; + + UndoablCut(VectorProperty prop, int index) { + super(prop, index); + ClipboardEntry newEnt = new ClipboardEntry(); + if (newEnt.cut((SuperRoot)this.obj)) { + EditTile.setClipboard(newEnt); + this.clipValid = true; + } + } + + @Override + public void undo() { + super.undo(); + if (this.clipValid) { + EditTile.setClipboard(this.prevClipboard); + } + } +} diff --git a/NET/worlds/scape/UndoablDelete.java b/NET/worlds/scape/UndoablDelete.java new file mode 100644 index 0000000..64146b8 --- /dev/null +++ b/NET/worlds/scape/UndoablDelete.java @@ -0,0 +1,19 @@ +package NET.worlds.scape; + +import java.util.Vector; + +class UndoablDelete implements Undoable { + protected VectorProperty prop; + protected Object obj; + + UndoablDelete(VectorProperty prop, int index) { + this.prop = prop; + this.obj = ((Vector)prop.get()).elementAt(index); + prop.delete(this.obj); + } + + @Override + public void undo() { + this.prop.add(this.obj); + } +} diff --git a/NET/worlds/scape/UndoablPaste.java b/NET/worlds/scape/UndoablPaste.java new file mode 100644 index 0000000..f4a1c54 --- /dev/null +++ b/NET/worlds/scape/UndoablPaste.java @@ -0,0 +1,16 @@ +package NET.worlds.scape; + +class UndoablPaste extends UndoablAdd { + private ClipboardEntry clipboard; + + UndoablPaste(VectorProperty prop, ClipboardEntry clipboard, Object obj) { + super(prop, obj); + this.clipboard = clipboard; + } + + @Override + public void undo() { + super.undo(); + this.clipboard.unPaste((SuperRoot)this.obj); + } +} diff --git a/NET/worlds/scape/UndoablSet.java b/NET/worlds/scape/UndoablSet.java new file mode 100644 index 0000000..424386f --- /dev/null +++ b/NET/worlds/scape/UndoablSet.java @@ -0,0 +1,17 @@ +package NET.worlds.scape; + +class UndoablSet implements Undoable { + private Property prop; + private Object obj; + + UndoablSet(Property prop, Object newObj) { + this.prop = prop; + this.obj = prop.get(); + prop.set(newObj); + } + + @Override + public void undo() { + this.prop.set(this.obj); + } +} diff --git a/NET/worlds/scape/UndoablTransform.java b/NET/worlds/scape/UndoablTransform.java new file mode 100644 index 0000000..3e316d2 --- /dev/null +++ b/NET/worlds/scape/UndoablTransform.java @@ -0,0 +1,16 @@ +package NET.worlds.scape; + +class UndoablTransform implements Undoable { + private WObject wob; + private Transform transform; + + UndoablTransform(WObject wob) { + this.wob = wob; + this.transform = wob.getTransform(); + } + + @Override + public void undo() { + this.wob.setTransform(this.transform); + } +} diff --git a/NET/worlds/scape/Undoable.java b/NET/worlds/scape/Undoable.java new file mode 100644 index 0000000..b640035 --- /dev/null +++ b/NET/worlds/scape/Undoable.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface Undoable { + void undo(); +} diff --git a/NET/worlds/scape/UniqueHasher.java b/NET/worlds/scape/UniqueHasher.java new file mode 100644 index 0000000..193a145 --- /dev/null +++ b/NET/worlds/scape/UniqueHasher.java @@ -0,0 +1,31 @@ +package NET.worlds.scape; + +import java.util.Hashtable; + +public class UniqueHasher { + private int currentHash = 0; + private static UniqueHasher uh_; + private Hashtable ht = new Hashtable(); + + private UniqueHasher() { + } + + public static UniqueHasher uh() { + if (uh_ == null) { + uh_ = new UniqueHasher(); + } + + return uh_; + } + + public int hash(Object toHash) { + Integer value = (Integer)this.ht.get(toHash); + if (value == null) { + this.currentHash++; + value = new Integer(this.currentHash); + this.ht.put(toHash, value); + } + + return value; + } +} diff --git a/NET/worlds/scape/UnitEnumeration.java b/NET/worlds/scape/UnitEnumeration.java new file mode 100644 index 0000000..8702ebd --- /dev/null +++ b/NET/worlds/scape/UnitEnumeration.java @@ -0,0 +1,23 @@ +package NET.worlds.scape; + +import java.util.Enumeration; + +public class UnitEnumeration implements Enumeration { + private Object o; + + UnitEnumeration(Object o) { + this.o = o; + } + + @Override + public boolean hasMoreElements() { + return this.o != null; + } + + @Override + public Object nextElement() { + Object t = this.o; + this.o = null; + return t; + } +} diff --git a/NET/worlds/scape/UniverseHandler.java b/NET/worlds/scape/UniverseHandler.java new file mode 100644 index 0000000..b0e05cf --- /dev/null +++ b/NET/worlds/scape/UniverseHandler.java @@ -0,0 +1,66 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.DefaultConsole; +import NET.worlds.console.UniversePanel; + +public class UniverseHandler { + public static boolean handle(MouseDeltaEvent e) { + if (e.dx != 0 || e.dy != 0) { + Console cons = Console.getActive(); + UniversePanel universe = null; + if (cons instanceof DefaultConsole) { + universe = ((DefaultConsole)cons).getUniverse(); + } + + if (universe != null) { + universe.addOffset(-e.dx, -e.dy); + return true; + } + } + + return false; + } + + public static boolean handle(KeyDownEvent e) { + Console cons = Console.getActive(); + UniversePanel universe = null; + if (cons instanceof DefaultConsole) { + universe = ((DefaultConsole)cons).getUniverse(); + } + + if (universe != null) { + switch (e.key) { + case '\ue325': + universe.keyDown(null, 1006); + return true; + case '\ue326': + universe.keyDown(null, 1004); + return true; + case '\ue327': + universe.keyDown(null, 1007); + return true; + case '\ue328': + universe.keyDown(null, 1005); + return true; + } + } + + return false; + } + + public static boolean handle(KeyUpEvent e) { + Console cons = Console.getActive(); + UniversePanel universe = null; + if (cons instanceof DefaultConsole) { + universe = ((DefaultConsole)cons).getUniverse(); + } + + if (universe != null) { + universe.keyUp(null, 1004); + return true; + } else { + return false; + } + } +} diff --git a/NET/worlds/scape/UserEvent.java b/NET/worlds/scape/UserEvent.java new file mode 100644 index 0000000..17f9759 --- /dev/null +++ b/NET/worlds/scape/UserEvent.java @@ -0,0 +1,12 @@ +package NET.worlds.scape; + +public class UserEvent extends Event { + public UserEvent(int time, Object source, WObject target) { + super(time, source, target); + } + + @Override + public boolean deliver(Object o) { + return o instanceof UserHandler && ((UserHandler)o).handle(this); + } +} diff --git a/NET/worlds/scape/UserHandler.java b/NET/worlds/scape/UserHandler.java new file mode 100644 index 0000000..96f2bf8 --- /dev/null +++ b/NET/worlds/scape/UserHandler.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface UserHandler { + boolean handle(UserEvent var1); +} diff --git a/NET/worlds/scape/VTransWidget.java b/NET/worlds/scape/VTransWidget.java new file mode 100644 index 0000000..be35785 --- /dev/null +++ b/NET/worlds/scape/VTransWidget.java @@ -0,0 +1,19 @@ +package NET.worlds.scape; + +import NET.worlds.console.SnapTool; + +class VTransWidget extends WidgetButton { + public VTransWidget(ToolBar toolbar) { + super(toolbar, "vtrans.gif", "Move vertically"); + } + + @Override + public String drag(boolean initialDrag, float deltax, float deltay) { + Transform t = Transform.make(); + this.applyWorldTransform( + initialDrag, t.moveBy(SnapTool.snapTool().snapTo(this.getWorldAxis(1, 0, 0).times(deltax).plus(this.getWorldAxis(0, 0, 1).times(deltay)))) + ); + t.recycle(); + return "" + this.getWObject().getPosition(); + } +} diff --git a/NET/worlds/scape/ValueEvent.java b/NET/worlds/scape/ValueEvent.java new file mode 100644 index 0000000..1b89c1e --- /dev/null +++ b/NET/worlds/scape/ValueEvent.java @@ -0,0 +1,15 @@ +package NET.worlds.scape; + +public class ValueEvent extends Event { + public Object whoChanged; + + public ValueEvent(int time, Object source, WObject target, Object whoChanged) { + super(time, source, target); + this.whoChanged = whoChanged; + } + + @Override + public boolean deliver(Object o) { + return o instanceof ValueHandler && ((ValueHandler)o).handle(this); + } +} diff --git a/NET/worlds/scape/ValueHandler.java b/NET/worlds/scape/ValueHandler.java new file mode 100644 index 0000000..637ce11 --- /dev/null +++ b/NET/worlds/scape/ValueHandler.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface ValueHandler { + boolean handle(ValueEvent var1); +} diff --git a/NET/worlds/scape/VectorProperty.java b/NET/worlds/scape/VectorProperty.java new file mode 100644 index 0000000..cbd9573 --- /dev/null +++ b/NET/worlds/scape/VectorProperty.java @@ -0,0 +1,76 @@ +package NET.worlds.scape; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +public class VectorProperty extends Property { + private PropAdder adder; + private boolean allowSorting = true; + + public VectorProperty(Properties owner, int index, String propName) { + super(owner, index, propName); + } + + public static Vector toVector(Object[] arr) { + Vector v = new Vector(arr.length); + + for (int i = 0; i < arr.length; i++) { + v.addElement(arr[i]); + } + + return v; + } + + public static Vector toVector(Hashtable hash) { + Vector v = new Vector(hash.size()); + Enumeration e = hash.elements(); + + while (e.hasMoreElements()) { + v.addElement(e.nextElement()); + } + + return v; + } + + public Object delete(Object obj) { + assert obj != null; + + assert this.adder != null; + + return this.operate(4, obj); + } + + public Object add(Object obj) { + assert obj != null; + + assert this.adder != null; + + return this.operate(3, obj); + } + + public boolean addTest(Object obj) { + assert obj != null; + + assert this.adder != null; + + return this.operate(5, obj) != null; + } + + public VectorProperty setAdder(PropAdder adder) { + this.adder = adder; + return this; + } + + public PropAdder getAdder() { + return this.adder; + } + + public void allowSorting(boolean allow) { + this.allowSorting = allow; + } + + public boolean shouldSort() { + return this.allowSorting; + } +} diff --git a/NET/worlds/scape/VehicleDriver.java b/NET/worlds/scape/VehicleDriver.java new file mode 100644 index 0000000..10daf6c --- /dev/null +++ b/NET/worlds/scape/VehicleDriver.java @@ -0,0 +1,653 @@ +package NET.worlds.scape; + +public class VehicleDriver extends SwitchableBehavior implements MouseDeltaHandler, KeyUpHandler, KeyDownHandler, MouseDownHandler, MouseUpHandler, FrameHandler { + protected VehicleShape vehicle; + static final boolean debug = true; + static final float gravity = 32.1F; + static final float densityOfAir = 0.0801F; + static final float dragCoefficient = 0.3F; + static final float feetToWorld = 30.48F; + static final float worldToFeet = 0.0328084F; + static final float epsilon = 0.001F; + static final float maxCamber = 0.4F; + static final float rotationalDampener = 0.5F; + static final int asphalt = 0; + static final int grass = 1; + static final int numTerrainTypes = 2; + float acceleratorDepression = 0.0F; + float brakesDepression = 0.0F; + int currentGear = 1; + float steeringWheelPosition = 0.0F; + boolean gasKeyDown = false; + boolean brakeKeyDown = false; + boolean leftKeyDown = false; + boolean rightKeyDown = false; + Point3 velocityVector = new Point3(0.0F, 0.0F, 0.0F); + Point3 velocityVectorCarFrame = new Point3(0.0F, 0.0F, 0.0F); + float velocity = 0.0F; + Point3 angularVelocity = new Point3(0.0F, 0.0F, 0.0F); + Point3 angularVelocityCarFrame = new Point3(0.0F, 0.0F, 0.0F); + Point3 worldCenterOfMass = new Point3(0.0F, 0.0F, 0.0F); + float engineRPM = 0.0F; + Point3 integratedForce = new Point3(0.0F, 0.0F, 0.0F); + Point3 integratedTorque = new Point3(0.0F, 0.0F, 0.0F); + boolean disabled = false; + float[] minRPMs; + VehicleDriver.Tire[] tires; + protected Room room; + protected Pilot pilot; + static float lastTime = 0.0F; + static final int lateralForceIncrements = 1000; + static float[][] muTable; + static boolean lateralForceTableInited = false; + static final int torqueIncrements = 500; + static final float maxRPM = 7000.0F; + static final float minRPM = 1500.0F; + static final float rpmInc = 500.0F; + static final int numRPMs = 12; + static float[] torqueTable; + static boolean torqueTableInited = false; + static float[] rawTorqueData = new float[]{80.0F, 82.0F, 91.0F, 92.0F, 89.0F, 90.0F, 98.0F, 93.0F, 94.0F, 78.0F, 83.0F, 75.0F}; + static final float torqueMax = 98.0F; + + public VehicleDriver(VehicleShape p_Vehicle) { + this.vehicle = p_Vehicle; + this.initLateralForceTable(); + this.initTorqueTable(); + this.initRPMTable(); + this.tires = new VehicleDriver.Tire[4]; + + for (int tire = 0; tire < 4; tire++) { + this.tires[tire] = new VehicleDriver.Tire(); + this.tires[tire].relativePos.copy(this.vehicle.tirePositions[tire]); + } + } + + @Override + public boolean handle(MouseDeltaEvent e) { + return UniverseHandler.handle(e); + } + + @Override + public boolean handle(KeyDownEvent e) { + if (UniverseHandler.handle(e)) { + return true; + } else { + switch (e.key) { + case '1': + if (this.vehicle.stickShift) { + this.currentGear = 1; + } + break; + case '2': + if (this.vehicle.stickShift) { + this.currentGear = 2; + } + break; + case '3': + if (this.vehicle.stickShift) { + this.currentGear = 3; + } + break; + case '4': + if (this.vehicle.stickShift) { + this.currentGear = 4; + } + break; + case '5': + if (this.vehicle.stickShift) { + this.currentGear = 5; + } + break; + case 'R': + case 'r': + this.currentGear = 0; + break; + case '\ue325': + this.leftKeyDown = true; + break; + case '\ue326': + this.gasKeyDown = true; + break; + case '\ue327': + this.rightKeyDown = true; + break; + case '\ue328': + this.brakeKeyDown = true; + } + + return true; + } + } + + @Override + public boolean handle(KeyUpEvent e) { + if (UniverseHandler.handle(e)) { + return true; + } else { + switch (e.key) { + case '\ue325': + this.leftKeyDown = false; + break; + case '\ue326': + this.gasKeyDown = false; + break; + case '\ue327': + this.rightKeyDown = false; + break; + case '\ue328': + this.brakeKeyDown = false; + } + + return true; + } + } + + @Override + public boolean handle(MouseDownEvent e) { + return false; + } + + @Override + public boolean handle(MouseUpEvent e) { + return false; + } + + @Override + public boolean handle(FrameEvent e) { + if (!(e.receiver instanceof Pilot)) { + return true; + } else { + this.pilot = (Pilot)e.receiver; + if (!this.pilot.isActive()) { + return true; + } else { + Point3Temp com = Point3Temp.make(this.vehicle.centerOfGravity); + com.times(30.48F); + com.times(this.pilot.getObjectToWorldMatrix()); + com.times(0.0328084F); + this.worldCenterOfMass.set(com.x, com.y, com.z); + this.room = this.pilot.getRoom(); + int now = e.time; + float dt = (now - lastTime) / 1000.0F; + lastTime = now; + if (dt <= 0.0F) { + return true; + } else { + if (dt > 0.33F) { + dt = 0.33F; + } + + if (this.gasKeyDown) { + this.acceleratorDepression = (float)(this.acceleratorDepression + 1.2 * dt); + } else { + this.acceleratorDepression = 0.0F; + } + + if (this.acceleratorDepression > 1.0) { + this.acceleratorDepression = 1.0F; + } + + if (this.brakeKeyDown) { + this.brakesDepression = (float)(this.brakesDepression + 1.2 * dt); + } else { + this.brakesDepression = 0.0F; + } + + if (this.brakesDepression > 1.0) { + this.brakesDepression = 1.0F; + } + + float wheelDelta = 0.282F * dt; + if (Math.abs(this.velocityVectorCarFrame.y) < 10.0F) { + wheelDelta = (float)(wheelDelta * 0.5); + } + + if (this.leftKeyDown) { + this.steeringWheelPosition -= wheelDelta; + } else if (this.rightKeyDown) { + this.steeringWheelPosition += wheelDelta; + } else { + this.steeringWheelPosition = 0.0F; + } + + if (this.steeringWheelPosition > 0.5) { + this.steeringWheelPosition = 0.5F; + } + + if (this.steeringWheelPosition < -0.5) { + this.steeringWheelPosition = -0.5F; + } + + this.DoPhysics(dt); + return true; + } + } + } + } + + protected void DoPhysics(float dt) { + System.out.println("-----------------------------"); + float engineTorque = this.vehicle.maxEngineTorque * this.acceleratorDepression * this.getTorque(this.engineRPM); + + assert this.vehicle.wheelDiameter != 0.0F; + + float gearRatio = this.getGearRatio(this.currentGear); + float wheelForce = engineTorque * this.vehicle.rearEndRatio * gearRatio / (this.vehicle.wheelDiameter * 0.5F); + if (Math.abs(this.velocityVectorCarFrame.y) > 2.0) { + wheelForce -= this.brakesDepression * this.vehicle.mass * 100.0F; + } else if (this.brakesDepression > 0.0F) { + this.velocityVectorCarFrame.y = 0.0F; + } + + if (gearRatio == 0.0F) { + wheelForce *= -1.0F; + } + + if (this.disabled) { + wheelForce = 0.0F; + } + + switch (this.vehicle.driveType) { + case 0: + wheelForce = (float)(wheelForce * 0.25); + this.tires[0].driveForce = this.tires[1].driveForce = wheelForce; + this.tires[2].driveForce = this.tires[3].driveForce = wheelForce; + break; + case 1: + wheelForce = (float)(wheelForce * 0.5); + this.tires[0].driveForce = this.tires[1].driveForce = wheelForce; + this.tires[2].driveForce = this.tires[3].driveForce = 0.0; + break; + case 2: + default: + wheelForce = (float)(wheelForce * 0.5); + this.tires[0].driveForce = this.tires[1].driveForce = 0.0; + this.tires[2].driveForce = this.tires[3].driveForce = wheelForce; + } + + float wheelAngle = this.steeringWheelPosition * 1.57F; + this.tires[0].wheelAngle = this.tires[1].wheelAngle = -wheelAngle; + float wheelRPM = 60.0F * this.velocityVectorCarFrame.y / ((float) Math.PI * this.vehicle.wheelDiameter); + this.engineRPM = wheelRPM * this.vehicle.rearEndRatio * gearRatio; + if (this.engineRPM < this.vehicle.idleRPM) { + this.engineRPM = this.vehicle.idleRPM; + } + + if (!this.vehicle.stickShift) { + if (this.engineRPM > this.vehicle.rpmTorquePeak && this.currentGear < 5) { + this.currentGear++; + } + + if (this.engineRPM < this.minRPMs[this.currentGear] && this.currentGear > 1) { + this.currentGear--; + } + } + + Point3Temp netForce = Point3Temp.make(0.0F, 0.0F, 0.0F); + Point3Temp netTorque = Point3Temp.make(0.0F, 0.0F, 0.0F); + + for (int wheel = 0; wheel < 4; wheel++) { + this.calculateForces(this.tires[wheel]); + netForce.plus(this.tires[wheel].force); + netTorque.plus(this.tires[wheel].torque); + } + + Point3Temp airFriction = Point3Temp.make(this.velocityVectorCarFrame); + airFriction.negate(); + airFriction.normalize(); + float drag = 0.15F * this.vehicle.frontalArea * 0.0801F * this.velocity * this.velocity / 32.1F; + airFriction.times(drag); + netForce.plus(airFriction); + netForce.vectorTimes(this.pilot.getObjectToWorldMatrix()); + System.out.println("Net force " + netForce.x + " " + netForce.y + " " + netForce.z); + System.out.println("Net torque " + netTorque.x + " " + netTorque.y + " " + netTorque.z); + Point3Temp gravityForce = Point3Temp.make(0.0F, 0.0F, -this.vehicle.mass * 32.1F); + netForce.plus(gravityForce); + Point3Temp inertialDampener = Point3Temp.make(0.5F, 0.5F, 0.5F); + inertialDampener.times(this.angularVelocityCarFrame); + inertialDampener.times(this.vehicle.momentsOfInertia); + inertialDampener.times(1.0F / dt); + netTorque.minus(inertialDampener); + this.integratedForce.plus(netForce); + this.integratedForce.times(0.5F); + this.integratedTorque.plus(netTorque); + this.integratedTorque.times(0.5F); + inertialDampener = Point3Temp.make(this.integratedForce); + inertialDampener.times(1.0F / this.vehicle.mass); + Point3Temp dV = Point3Temp.make(inertialDampener); + dV.times(dt); + Point3Temp lastV = Point3Temp.make(this.velocityVector); + Point3Temp lastW = Point3Temp.make(this.angularVelocityCarFrame); + this.velocityVector.plus(dV); + this.velocityVector.plus(lastV); + this.velocityVector.times(0.5F); + this.velocity = this.velocityVector.length(); + this.velocityVectorCarFrame.copy(this.velocityVector); + this.velocityVectorCarFrame.vectorTimes(this.pilot.getObjectToWorldMatrix().invert()); + Point3Temp dw = Point3Temp.make(this.integratedTorque); + dw.times(dt); + dw.dividedBy(this.vehicle.momentsOfInertia); + this.angularVelocityCarFrame.plus(dw); + this.angularVelocityCarFrame.plus(lastW); + this.angularVelocityCarFrame.times(0.5F); + this.angularVelocity.copy(this.angularVelocityCarFrame); + this.angularVelocity.vectorTimes(this.pilot.getObjectToWorldMatrix()); + Point3Temp dx = Point3Temp.make(this.velocityVector); + dx.times(dt); + float maxUnderground = 0.0F; + + for (int tire = 0; tire < 4; tire++) { + float diff = -this.tires[tire].underGround; + if (diff > maxUnderground) { + maxUnderground = diff; + } + } + + dx.z += maxUnderground; + dx.times(30.48F); + Point3Temp da = Point3Temp.make(this.angularVelocity); + da.times(dt); + this.pilot.premoveThrough(dx); + float convert = 180.0F / (float)Math.PI; + this.pilot.pitch(da.x * convert); + this.pilot.roll(da.y * convert); + this.pilot.yaw(da.z * convert); + System.out.println("dx " + dx.x + " " + dx.y + " " + dx.z); + System.out.println("da " + da.x + " " + da.y + " " + da.z); + System.out.println("pos" + this.pilot.getX() + " " + this.pilot.getY() + " " + this.pilot.getZ()); + } + + protected void calculateForces(VehicleDriver.Tire tire) { + tire.force.set(0.0F, 0.0F, 0.0F); + tire.torque.set(0.0F, 0.0F, 0.0F); + Transform o2w = this.pilot.getObjectToWorldMatrix(); + Transform w2o = this.pilot.getObjectToWorldMatrix().invert(); + Point3Temp worldPos = Point3Temp.make(tire.relativePos); + worldPos.plus(this.vehicle.centerOfGravity); + worldPos.times(30.48F); + worldPos.times(o2w); + double groundZ = this.room.floorHeight(worldPos.x, worldPos.y, worldPos.z); + Point3 N = this.room.surfaceNormal(worldPos.x, worldPos.y, worldPos.z); + groundZ *= 0.0328084F; + worldPos.times(0.0328084F); + tire.underGround = (float)(worldPos.z - groundZ); + if (!(tire.underGround > this.vehicle.shockLength)) { + Point3Temp R = Point3Temp.make(tire.relativePos); + R.vectorTimes(o2w); + Point3Temp w = Point3Temp.make(this.angularVelocity); + w.cross(R); + w.plus(this.velocityVector); + Point3Temp Vp = Point3Temp.make(w); + System.out.println("R " + R.x + " " + R.y + " " + R.z); + System.out.println("Vp " + Vp.x + " " + Vp.y + " " + Vp.z); + double normalSpeed = Vp.dot(N); + Point3Temp No = Point3Temp.make(N); + No.vectorTimes(w2o); + Point3Temp tmp = Point3Temp.make(No); + double scalarInertialMoment = tmp.dot(this.vehicle.momentsOfInertia); + scalarInertialMoment = Math.abs(scalarInertialMoment); + Point3Temp orthoNormal = Point3Temp.make(R); + orthoNormal.cross(N); + double r = orthoNormal.length(); + double denominator = r * this.vehicle.mass + scalarInertialMoment; + + assert denominator != 0.0; + + double myMass = this.vehicle.mass * 0.25; + double weight = scalarInertialMoment * myMass / denominator; + if (weight < 0.0) { + weight = 0.0; + } + + if (weight > this.vehicle.mass) { + weight = myMass; + } + + assert this.vehicle.shockLength != 0.0F; + + double k = weight * 32.1F / this.vehicle.shockLength; + double springLength = worldPos.z - (groundZ + this.vehicle.shockLength); + if (springLength < -this.vehicle.shockLength) { + springLength = -this.vehicle.shockLength; + } + + if (springLength > this.vehicle.shockLength) { + springLength = this.vehicle.shockLength; + } + + double groundForce = -k * springLength; + double term = k * weight; + + assert term >= 0.0; + + double damp = -Math.sqrt(term) * normalSpeed * this.vehicle.shockDampingCoeff; + groundForce += damp; + Point3Temp groundForceVector = Point3Temp.make(No); + groundForceVector.normalize(); + groundForceVector.times((float)groundForce); + tire.force.plus(groundForceVector); + Point3Temp VpCarFrame = Point3Temp.make(Vp); + VpCarFrame.vectorTimes(w2o); + Point3Temp normalVelocity = Point3Temp.make(VpCarFrame); + normalVelocity.z = 0.0F; + Point3Temp intendedForce = Point3Temp.make(0.0F, 0.0F, 0.0F); + Transform wheelXform = Transform.make(); + wheelXform.yaw(tire.wheelAngle * 229.1831F); + float mu; + if (normalVelocity.length() < 0.001F) { + mu = 0.0F; + } else if (Math.abs(No.x) > 0.4F) { + mu = 0.0F; + } else { + normalVelocity.normalize(); + Point3Temp wheelDirection = Point3Temp.make(0.0F, 1.0F, 0.0F); + wheelDirection.vectorTimes(wheelXform); + wheelDirection.normalize(); + float cosSlipAngle = normalVelocity.dot(wheelDirection); + System.out.println("wheel direction " + wheelDirection.x + " " + wheelDirection.y + " " + wheelDirection.z); + System.out.println("normal velocity " + normalVelocity.x + " " + normalVelocity.y + " " + normalVelocity.z); + System.out.println("cos of slip angle " + cosSlipAngle); + mu = this.getLateralForceCoef(cosSlipAngle, 0); + float crossZ = normalVelocity.x * wheelDirection.y - normalVelocity.y * wheelDirection.x; + if (crossZ > 0.0F) { + mu *= -1.0F; + } + } + + intendedForce.x = mu * (float)groundForce; + intendedForce.y = (float)tire.driveForce; + System.out.println("Lateral forces " + intendedForce.x + ", " + intendedForce.y); + float forceMag = intendedForce.length(); + float maxForce = (float)groundForce * this.vehicle.tireAdhesiveLimit; + if (forceMag > maxForce) { + intendedForce.normalize(); + intendedForce.times(maxForce); + tire.slipping = true; + } else { + tire.slipping = false; + } + + intendedForce.vectorTimes(wheelXform); + tire.force.plus(intendedForce); + Point3Temp rollingFriction = Point3Temp.make(0.0F, 0.0F, 0.0F); + float S = 1.0F; + float magV = Vp.length(); + rollingFriction.y = (float)groundForce * 0.001F * (5.7F + 0.036F * magV * 0.6818182F) * S; + if (this.velocityVectorCarFrame.y > 0.0F) { + rollingFriction.y *= -1.0F; + } + + rollingFriction.vectorTimes(wheelXform); + System.out.println("Rolling friction " + rollingFriction.x + " " + rollingFriction.y + " " + rollingFriction.z); + wheelXform.recycle(); + Point3Temp rCopy = Point3Temp.make(tire.relativePos); + rCopy.negate(); + tire.torque.copy(tire.force); + tire.torque.cross(rCopy); + System.out.println("Underground " + springLength + " damping " + damp); + System.out.println("Force " + tire.force.x + " " + tire.force.y + " " + tire.force.z); + System.out.println("Torque " + tire.torque.x + " " + tire.torque.y + " " + tire.torque.z); + System.out.println(); + } + } + + private float getGearRatio(int gearNumber) { + float gearRatio; + switch (gearNumber) { + case 0: + gearRatio = this.vehicle.gearRatio1; + break; + case 1: + gearRatio = this.vehicle.gearRatio1; + break; + case 2: + gearRatio = this.vehicle.gearRatio2; + break; + case 3: + gearRatio = this.vehicle.gearRatio3; + break; + case 4: + gearRatio = this.vehicle.gearRatio4; + break; + case 5: + gearRatio = this.vehicle.gearRatio5; + break; + default: + System.out.println("Illegal gear " + this.currentGear); + gearRatio = 1.0F; + } + + return gearRatio; + } + + protected float getLateralForceCoef(float cosSlipAngle, int terrainType) { + if (cosSlipAngle > 1.0) { + cosSlipAngle = 1.0F; + } + + if (cosSlipAngle < -1.0) { + cosSlipAngle = -1.0F; + } + + float index = (float)Math.ceil(Math.abs(cosSlipAngle) * 1000.0F / 1.0F); + return muTable[terrainType][(int)index]; + } + + protected void initLateralForceTable() { + if (!lateralForceTableInited) { + lateralForceTableInited = true; + muTable = new float[2][1001]; + + for (int type = 0; type < 2; type++) { + for (int i = 0; i <= 1000; i++) { + float degrees = (float)Math.acos(i / 1000.0F); + degrees = degrees * 360.0F / (float) (Math.PI * 2); + switch (type) { + case 0: + if (degrees > 45.0F) { + degrees = 45.0F; + } + + muTable[type][i] = -0.084496F + + 0.1241739F * degrees + - 0.003676377F * (float)Math.pow(degrees, 2.0) + - 5.5137E-6F * (float)Math.pow(degrees, 3.0) + + 6.461E-7F * (float)Math.pow(degrees, 4.0); + break; + case 1: + muTable[type][i] = 0.055731F + 0.069871F * degrees - 0.002175398F * degrees * degrees; + } + + if (muTable[type][i] < 0.0F) { + muTable[type][i] = 0.0F; + } + } + } + } + } + + float getTorque(float rpm) { + if (rpm > 7000.0F) { + rpm = 7000.0F; + } + + if (rpm < 1500.0F) { + rpm = 1500.0F; + } + + int index = (int)(rpm / 7000.0F); + return torqueTable[index]; + } + + void initTorqueTable() { + if (!torqueTableInited) { + torqueTableInited = true; + torqueTable = new float[501]; + + for (int i = 0; i <= 500; i++) { + float rpm = i / 500.0F * 7000.0F; + if (rpm < 1500.0F) { + rpm = 1500.0F; + } + + int closest = 0; + + for (int j = 0; j < 12; j++) { + float thisRpm = j * 500.0F + 1500.0F; + if (thisRpm >= rpm) { + closest = j; + break; + } + } + + if (closest == 0) { + torqueTable[i] = rawTorqueData[0] / 98.0F; + } else { + Point2 low = new Point2(); + Point2 high = new Point2(); + Point2 result = new Point2(); + low.x = (closest - 1) * 500.0F + 1500.0F; + low.y = rawTorqueData[closest - 1]; + high.x = low.x + 500.0F; + high.y = rawTorqueData[closest]; + float alpha = (rpm - low.x) / 500.0F; + result.x = low.x * alpha + high.x * (1.0F - alpha); + result.y = low.y * alpha + high.y * (1.0F - alpha); + torqueTable[i] = result.y / 98.0F; + } + } + } + } + + private void initRPMTable() { + this.minRPMs = new float[6]; + float[] maxVel = new float[5]; + + for (int x = 0; x < 5; x++) { + maxVel[x] = this.vehicle.rpmTorquePeak * (float) Math.PI * this.vehicle.wheelDiameter / (60.0F * this.vehicle.rearEndRatio * this.getGearRatio(x)); + } + + this.minRPMs[0] = 0.0F; + + for (int x = 1; x <= 5; x++) { + this.minRPMs[x] = 60.0F * maxVel[x - 1] * this.vehicle.rearEndRatio * this.getGearRatio(x) / ((float) Math.PI * this.vehicle.wheelDiameter); + } + } + + protected class Tire { + Point3 force = new Point3(); + Point3 torque = new Point3(); + Point3 relativePos = new Point3(); + float underGround; + double driveForce = 0.0; + float wheelAngle; + boolean slipping; + + public Tire() { + this.underGround = 0.0F; + this.wheelAngle = 0.0F; + this.slipping = false; + } + } +} diff --git a/NET/worlds/scape/VehicleShape.java b/NET/worlds/scape/VehicleShape.java new file mode 100644 index 0000000..2196448 --- /dev/null +++ b/NET/worlds/scape/VehicleShape.java @@ -0,0 +1,571 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.DialogReceiver; +import NET.worlds.console.OkCancelDialog; +import NET.worlds.core.IniFile; +import NET.worlds.network.URL; +import java.io.IOException; + +public class VehicleShape extends PosableShape implements MouseDownHandler, DialogReceiver { + static final int fourWheelDrive = 0; + static final int frontWheelDrive = 1; + static final int rearWheelDrive = 2; + private String promptString = "Take her for a spin?"; + public float rearEndRatio = 3.07F; + public float frontalArea = 42.5F; + public float wheelDiameter = 2.167F; + public float coeffKineticFriction = 0.05F; + public float coeffStaticFriction = 0.2F; + public float mass = 100.0F; + public float gearRatio1 = 2.88F; + public float gearRatio2 = 1.91F; + public float gearRatio3 = 1.33F; + public float gearRatio4 = 1.0F; + public float gearRatio5 = 0.7F; + public float maxEngineTorque = 300.0F; + public float tireAdhesiveLimit = 1.1F; + public float shockDampingCoeff = 3.0F; + public float shockLength = 0.15F; + public float rpmTorquePeak = 4200.0F; + public float idleRPM = 1000.0F; + public boolean stickShift = false; + public float initialGas = -1.0F; + public float adjustCogX = 0.0F; + public float adjustCogY = 0.0F; + public float adjustCogZ = 0.0F; + public int driveType = 2; + public boolean fixedCamera = true; + public float camX = 0.0F; + public float camY = -80.0F; + public float camZ = -120.0F; + public float camRoll = -10.0F; + public float camPitch = 0.0F; + public float camYaw = 0.0F; + public float camAimX = 15.0F; + public float camAimY = 0.0F; + public float camAimZ = 10.0F; + public float eyeHeight = 150.0F; + public String lastURL = ""; + public Point3 centerOfGravity; + public Point3 momentsOfInertia; + public Point3[] tirePositions; + private boolean avatarSwitchPending = false; + private static String[] vehicleShapeNames = new String[]{"dash"}; + private static Object classCookie = new Object(); + + VehicleShape() { + } + + VehicleShape(URL url) { + super(url); + } + + public static boolean isVehicle(URL url) { + if (IniFile.gamma().getIniInt("enableVehicleShapes", 0) == 0) { + return false; + } else { + String s = url.toString(); + + for (int i = 0; i < vehicleShapeNames.length; i++) { + if (url.toString().indexOf(vehicleShapeNames[i]) != -1) { + return true; + } + } + + return false; + } + } + + @Override + public boolean handle(MouseDownEvent event) { + if ((event.key & 1) == 1) { + new OkCancelDialog(Console.getFrame(), this, "Change Avatar", "No", "Yes", this.promptString, true); + } + + return true; + } + + @Override + public void dialogDone(Object who, boolean confirmed) { + if (who instanceof OkCancelDialog && confirmed) { + this.avatarSwitchPending = true; + boolean oldVIP = Console.getActive().getVIP(); + Console.getActive().setVIP(true); + Console.getActive().setAvatar(this.url); + Console.getActive().setVIP(oldVIP); + } + } + + protected native void nativeAnalyzeShape(int var1, float var2); + + protected native float nativeGetTirePosX(int var1); + + protected native float nativeGetTirePosY(int var1); + + protected native float nativeGetTirePosZ(int var1); + + protected native float nativeGetCogX(); + + protected native float nativeGetCogY(); + + protected native float nativeGetCogZ(); + + protected native float nativeGetMoiX(); + + protected native float nativeGetMoiY(); + + protected native float nativeGetMoiZ(); + + @Override + public void prerender(Camera cam) { + if (!this.lastURL.equals(this.url.toString()) || this.avatarSwitchPending) { + this.lastURL = new String(this.url.toString()); + System.out.println("Analyze shape " + this.lastURL); + this.nativeAnalyzeShape(this.clumpID, this.mass); + this.tirePositions = new Point3[4]; + + for (int i = 0; i < 4; i++) { + this.tirePositions[i] = new Point3(this.nativeGetTirePosX(i), this.nativeGetTirePosY(i), this.nativeGetTirePosZ(i)); + } + + this.centerOfGravity = new Point3(this.nativeGetCogX(), this.nativeGetCogY(), this.nativeGetCogZ()); + this.centerOfGravity.x = this.centerOfGravity.x + this.adjustCogX; + this.centerOfGravity.y = this.centerOfGravity.y + this.adjustCogY; + this.centerOfGravity.z = this.centerOfGravity.z + this.adjustCogZ; + this.momentsOfInertia = new Point3(this.nativeGetMoiX(), this.nativeGetMoiY(), this.nativeGetMoiZ()); + if (this.avatarSwitchPending) { + Pilot p = Console.getActive().getPilot(); + if (p instanceof HoloPilot) { + HoloPilot hp = (HoloPilot)p; + Drone d = hp.getInternalDrone(); + if (d != null && d instanceof PosableDrone) { + PosableDrone pd = (PosableDrone)d; + PosableShape ps = pd.getInternalPosableShape(); + if (ps != null && ps instanceof VehicleShape) { + VehicleShape vs = (VehicleShape)ps; + vs.fixedCamera = this.fixedCamera; + vs.camX = this.camX; + vs.camY = this.camY; + vs.camZ = this.camZ; + vs.camRoll = this.camRoll; + vs.camPitch = this.camPitch; + vs.camYaw = this.camYaw; + vs.camAimX = this.camAimX; + vs.camAimY = this.camAimY; + vs.camAimZ = this.camAimZ; + vs.eyeHeight = this.eyeHeight; + hp.setOutsideCameraMode(99, 4); + } + } + } + + this.avatarSwitchPending = false; + } + } + } + + @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 = StringPropertyEditor.make(new Property(this, index, "Prompt String")); + } else if (mode == 1) { + ret = new String(this.promptString); + } else if (mode == 2) { + this.promptString = new String((String)value); + } + break; + case 1: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Rear End Ratio")); + } else if (mode == 1) { + ret = new Float(this.rearEndRatio); + } else if (mode == 2) { + this.rearEndRatio = (Float)value; + } + break; + case 2: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Frontal Area (sq.ft.)")); + } else if (mode == 1) { + ret = new Float(this.frontalArea); + } else if (mode == 2) { + this.frontalArea = (Float)value; + } + break; + case 3: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Wheel Diameter (ft.)")); + } else if (mode == 1) { + ret = new Float(this.wheelDiameter); + } else if (mode == 2) { + this.wheelDiameter = (Float)value; + } + break; + case 4: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Coefficient of Kinetic Friction")); + } else if (mode == 1) { + ret = new Float(this.coeffKineticFriction); + } else if (mode == 2) { + this.coeffKineticFriction = (Float)value; + } + break; + case 5: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Coefficient of Static Friction")); + } else if (mode == 1) { + ret = new Float(this.coeffStaticFriction); + } else if (mode == 2) { + this.coeffStaticFriction = (Float)value; + } + break; + case 6: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Mass (slugs)")); + } else if (mode == 1) { + ret = new Float(this.mass); + } else if (mode == 2) { + this.mass = (Float)value; + } + break; + case 7: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "1st Gear Ratio")); + } else if (mode == 1) { + ret = new Float(this.gearRatio1); + } else if (mode == 2) { + this.gearRatio1 = (Float)value; + } + break; + case 8: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "2nd Gear Ratio")); + } else if (mode == 1) { + ret = new Float(this.gearRatio2); + } else if (mode == 2) { + this.gearRatio2 = (Float)value; + } + break; + case 9: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "3rd Gear Ratio")); + } else if (mode == 1) { + ret = new Float(this.gearRatio3); + } else if (mode == 2) { + this.gearRatio3 = (Float)value; + } + break; + case 10: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "4th Gear Ratio")); + } else if (mode == 1) { + ret = new Float(this.gearRatio4); + } else if (mode == 2) { + this.gearRatio4 = (Float)value; + } + break; + case 11: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "5th Gear Ratio")); + } else if (mode == 1) { + ret = new Float(this.gearRatio5); + } else if (mode == 2) { + this.gearRatio5 = (Float)value; + } + break; + case 12: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Max. Engine Torque (ft-lbs)")); + } else if (mode == 1) { + ret = new Float(this.maxEngineTorque); + } else if (mode == 2) { + this.maxEngineTorque = (Float)value; + } + break; + case 13: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Tire Adhesive Limit")); + } else if (mode == 1) { + ret = new Float(this.tireAdhesiveLimit); + } else if (mode == 2) { + this.tireAdhesiveLimit = (Float)value; + } + break; + case 14: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Shocks Damping Coefficient")); + } else if (mode == 1) { + ret = new Float(this.shockDampingCoeff); + } else if (mode == 2) { + this.shockDampingCoeff = (Float)value; + } + break; + case 15: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Shock Length (ft)")); + } else if (mode == 1) { + ret = new Float(this.shockLength); + } else if (mode == 2) { + this.shockLength = (Float)value; + } + break; + case 16: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Torque Peak (RPM)")); + } else if (mode == 1) { + ret = new Float(this.rpmTorquePeak); + } else if (mode == 2) { + this.rpmTorquePeak = (Float)value; + } + break; + case 17: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Idle RPM")); + } else if (mode == 1) { + ret = new Float(this.idleRPM); + } else if (mode == 2) { + this.idleRPM = (Float)value; + } + break; + case 18: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Transmission Type"), "Automatic", "Manual"); + } else if (mode == 1) { + ret = new Boolean(this.stickShift); + } else if (mode == 2) { + this.stickShift = (Boolean)value; + } + break; + case 19: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Gas (Gall., -1 for infinite)")); + } else if (mode == 1) { + ret = new Float(this.initialGas); + } else if (mode == 2) { + this.initialGas = (Float)value; + } + break; + case 20: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Center of gravity X adjust")); + } else if (mode == 1) { + ret = new Float(this.adjustCogX); + } else if (mode == 2) { + this.adjustCogX = (Float)value; + } + break; + case 21: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Center of gravity Y adjust")); + } else if (mode == 1) { + ret = new Float(this.adjustCogY); + } else if (mode == 2) { + this.adjustCogY = (Float)value; + } + break; + case 22: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Center of gravity Z adjust")); + } else if (mode == 1) { + ret = new Float(this.adjustCogZ); + } else if (mode == 2) { + this.adjustCogZ = (Float)value; + } + break; + case 23: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Use fixed camera"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.fixedCamera); + } else if (mode == 2) { + this.fixedCamera = (Boolean)value; + } + break; + case 24: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Camera X offset")); + } else if (mode == 1) { + ret = new Float(this.camX); + } else if (mode == 2) { + this.camX = (Float)value; + } + break; + case 25: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Camera Y offset")); + } else if (mode == 1) { + ret = new Float(this.camY); + } else if (mode == 2) { + this.camY = (Float)value; + } + break; + case 26: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Camera Z offset")); + } else if (mode == 1) { + ret = new Float(this.camZ); + } else if (mode == 2) { + this.camZ = (Float)value; + } + break; + case 27: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Camera Roll")); + } else if (mode == 1) { + ret = new Float(this.camRoll); + } else if (mode == 2) { + this.camRoll = (Float)value; + } + break; + case 28: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Camera Pitch")); + } else if (mode == 1) { + ret = new Float(this.camPitch); + } else if (mode == 2) { + this.camPitch = (Float)value; + } + break; + case 29: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Camera Yaw")); + } else if (mode == 1) { + ret = new Float(this.camYaw); + } else if (mode == 2) { + this.camYaw = (Float)value; + } + break; + case 30: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Camera Aim X")); + } else if (mode == 1) { + ret = new Float(this.camAimX); + } else if (mode == 2) { + this.camAimX = (Float)value; + } + break; + case 31: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Camera Aim Y")); + } else if (mode == 1) { + ret = new Float(this.camAimY); + } else if (mode == 2) { + this.camAimY = (Float)value; + } + break; + case 32: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Camera Aim Z")); + } else if (mode == 1) { + ret = new Float(this.camAimZ); + } else if (mode == 2) { + this.camAimZ = (Float)value; + } + break; + case 33: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Camera Eye Height")); + } else if (mode == 1) { + ret = new Float(this.eyeHeight); + } else if (mode == 2) { + this.eyeHeight = (Float)value; + } + break; + default: + ret = super.properties(index, offset + 34, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(2, classCookie); + s.saveBoolean(this.fixedCamera); + s.saveFloat(this.camX); + s.saveFloat(this.camY); + s.saveFloat(this.camZ); + s.saveFloat(this.camRoll); + s.saveFloat(this.camPitch); + s.saveFloat(this.camYaw); + s.saveFloat(this.camAimX); + s.saveFloat(this.camAimY); + s.saveFloat(this.camAimZ); + s.saveFloat(this.eyeHeight); + s.saveString(this.promptString); + s.saveFloat(this.rearEndRatio); + s.saveFloat(this.frontalArea); + s.saveFloat(this.wheelDiameter); + s.saveFloat(this.coeffKineticFriction); + s.saveFloat(this.coeffStaticFriction); + s.saveFloat(this.mass); + s.saveFloat(this.gearRatio1); + s.saveFloat(this.gearRatio2); + s.saveFloat(this.gearRatio3); + s.saveFloat(this.gearRatio4); + s.saveFloat(this.gearRatio5); + s.saveFloat(this.maxEngineTorque); + s.saveFloat(this.tireAdhesiveLimit); + s.saveFloat(this.shockDampingCoeff); + s.saveFloat(this.shockLength); + s.saveFloat(this.rpmTorquePeak); + s.saveFloat(this.idleRPM); + s.saveBoolean(this.stickShift); + s.saveFloat(this.initialGas); + s.saveFloat(this.adjustCogX); + s.saveFloat(this.adjustCogY); + s.saveFloat(this.adjustCogZ); + super.saveState(s); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 2: + this.fixedCamera = r.restoreBoolean(); + this.camX = r.restoreFloat(); + this.camY = r.restoreFloat(); + this.camZ = r.restoreFloat(); + this.camRoll = r.restoreFloat(); + this.camPitch = r.restoreFloat(); + this.camYaw = r.restoreFloat(); + this.camAimX = r.restoreFloat(); + this.camAimY = r.restoreFloat(); + this.camAimZ = r.restoreFloat(); + this.eyeHeight = r.restoreFloat(); + case 1: + this.promptString = r.restoreString(); + this.rearEndRatio = r.restoreFloat(); + this.frontalArea = r.restoreFloat(); + this.wheelDiameter = r.restoreFloat(); + this.coeffKineticFriction = r.restoreFloat(); + this.coeffStaticFriction = r.restoreFloat(); + this.mass = r.restoreFloat(); + this.gearRatio1 = r.restoreFloat(); + this.gearRatio2 = r.restoreFloat(); + this.gearRatio3 = r.restoreFloat(); + this.gearRatio4 = r.restoreFloat(); + this.gearRatio5 = r.restoreFloat(); + this.maxEngineTorque = r.restoreFloat(); + this.tireAdhesiveLimit = r.restoreFloat(); + this.shockDampingCoeff = r.restoreFloat(); + this.shockLength = r.restoreFloat(); + this.rpmTorquePeak = r.restoreFloat(); + this.idleRPM = r.restoreFloat(); + this.stickShift = r.restoreBoolean(); + this.initialGas = r.restoreFloat(); + this.adjustCogX = r.restoreFloat(); + this.adjustCogY = r.restoreFloat(); + this.adjustCogZ = r.restoreFloat(); + case 0: + super.restoreState(r); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/VelocityBehavior.java b/NET/worlds/scape/VelocityBehavior.java new file mode 100644 index 0000000..9858355 --- /dev/null +++ b/NET/worlds/scape/VelocityBehavior.java @@ -0,0 +1,260 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class VelocityBehavior extends SwitchableBehavior implements FrameHandler, BumpHandler { + private RollingAttribute attr; + private long lastTime; + public float linearVel; + public float linearDamp; + protected Point3 dir; + public float angularVel; + public float angularDamp; + public Point3 axis; + private boolean bumplock = false; + private static Object classCookie = new Object(); + + public VelocityBehavior( + Point3Temp linearVectorPerSecond, float linearDampingPerSecond, Point3Temp angularAxis, float angularDegPerSecond, float angularDampingPerSecond + ) { + this.dir = new Point3(); + this.linearVel = 0.0F; + this.linearDamp = linearDampingPerSecond; + this.addVelocity(linearVectorPerSecond); + this.axis = new Point3(angularAxis); + this.axis.normalize(); + this.angularVel = angularDegPerSecond; + this.angularDamp = angularDampingPerSecond; + } + + public VelocityBehavior() { + this(Point3Temp.make(0.0F, 0.0F, 0.0F)); + } + + public VelocityBehavior(Point3Temp vel) { + this(vel, 0.0F, Point3Temp.make(0.0F, 0.0F, 1.0F), 0.0F, 0.0F); + } + + public void setDir(Point3Temp d) { + double len = Math.sqrt(d.x * d.x + d.y * d.y + d.z * d.z); + if (len == 0.0) { + this.dir.x = 0.0F; + this.dir.y = 0.0F; + this.dir.z = 0.0F; + } else { + this.dir.x = (float)(d.x / len); + this.dir.y = (float)(d.y / len); + this.dir.z = (float)(d.z / len); + } + } + + public VelocityBehavior addVelocity(Point3Temp vector) { + this.dir.times(this.linearVel).plus(vector); + float len = this.dir.length(); + if (len > 0.0F) { + this.dir.dividedBy(len); + } + + this.linearVel = len; + return this; + } + + public void setNotifyAttribute(RollingAttribute attr) { + this.attr = attr; + } + + @Override + public boolean handle(FrameEvent e) { + this.bumplock = false; + WObject o = e.receiver; + float dT = (float)(e.time - this.lastTime) / 1000.0F; + if (this.lastTime == 0L) { + this.lastTime = e.time; + return true; + } else { + this.lastTime = e.time; + if (this.linearVel != 0.0F) { + Point3Temp dist = Point3Temp.make(this.dir).times(dT * this.linearVel); + o.moveThrough(dist); + if (this.linearDamp != 0.0F) { + this.linearVel = (float)(this.linearVel * Math.exp(-this.linearDamp * dT)); + if (Math.abs(this.linearVel) < this.linearDamp * 16.0F) { + this.linearVel = 0.0F; + if (this.attr != null) { + this.attr.notifyStopped(); + } + } + } + } + + if (this.angularVel != 0.0F) { + o.spin(this.axis.x, this.axis.y, this.axis.z, this.angularVel * dT); + if (this.angularDamp != 0.0F) { + this.angularVel = (float)(this.angularVel * Math.exp(-this.angularDamp * dT)); + if (Math.abs(this.angularVel) < this.angularDamp * 0.6F) { + this.angularVel = 0.0F; + } + } + } + + return true; + } + } + + @Override + public boolean handle(BumpEventTemp b) { + if (this.bumplock) { + return true; + } else { + if (this.attr != null) { + this.attr.handle(b); + } else { + this.processBumpEvent(b); + } + + this.bumplock = true; + return true; + } + } + + public void processBumpEvent(BumpEventTemp b) { + b.postBumpPath.minus(b.postBumpPath); + if (this.dir.x != 0.0F || this.dir.y != 0.0F || this.dir.z != 0.0F) { + WObject bumper = b.receiver == b.target ? (WObject)b.source : b.target; + Point3Temp norm; + if (!(bumper instanceof Camera) && !(bumper instanceof Hologram)) { + norm = Point3Temp.make(b.bumpNormal); + } else { + float orientation = (float)((360.0F - bumper.getYaw() + 90.0F) * Math.PI / 180.0); + norm = Point3Temp.make((float)Math.cos(orientation), (float)Math.sin(orientation), 0.0F); + } + + float lb = (float)Math.sqrt(norm.x * norm.x + norm.y * norm.y + norm.z * norm.z); + norm.x /= lb; + norm.y /= lb; + norm.z /= lb; + float projection = Math.abs(this.dir.x * norm.x + this.dir.y * norm.y + this.dir.z * norm.z); + this.dir.x = this.dir.x + norm.x * 2.0F * projection; + this.dir.y = this.dir.y + norm.y * 2.0F * projection; + this.dir.z = this.dir.z + norm.z * 2.0F * projection; + double n = Math.sqrt(this.dir.x * this.dir.x + this.dir.y * this.dir.y + this.dir.z * this.dir.z); + if (n != 0.0) { + this.dir.x = (float)(this.dir.x / n); + this.dir.y = (float)(this.dir.y / n); + this.dir.z = (float)(this.dir.z / n); + } + } + } + + @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 = FloatPropertyEditor.make(new Property(this, index, "Linear Velocity")); + } else if (mode == 1) { + ret = new Float(this.linearVel); + } else if (mode == 2) { + this.linearVel = (Float)value; + } + break; + case 1: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Linear Damping")); + } else if (mode == 1) { + ret = new Float(this.linearDamp); + } else if (mode == 2) { + this.linearDamp = (Float)value; + } + break; + case 2: + if (mode == 0) { + ret = Point3PropertyEditor.make(new Property(this, index, "Direction")); + } else if (mode == 1) { + ret = new Point3(this.dir); + } else if (mode == 2) { + this.dir = (Point3)value; + } + break; + case 3: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Angular Velocity")); + } else if (mode == 1) { + ret = new Float(this.angularVel); + } else if (mode == 2) { + this.angularVel = (Float)value; + } + break; + case 4: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Angular Damping")); + } else if (mode == 1) { + ret = new Float(this.angularDamp); + } else if (mode == 2) { + this.angularDamp = (Float)value; + } + break; + case 5: + if (mode == 0) { + ret = Point3PropertyEditor.make(new Property(this, index, "Axis")); + } else if (mode == 1) { + ret = new Point3(this.axis); + } else if (mode == 2) { + this.axis = (Point3)value; + } + break; + default: + ret = super.properties(index, offset + 6, mode, value); + } + + return ret; + } + + @Override + public String toString() { + return super.toString() + + "[lin. velocity " + + this.linearVel + + ", lin. damp " + + this.linearDamp + + ", direction " + + this.dir + + ", ang. vel " + + this.angularVel + + ", ang. damp " + + this.angularDamp + + ", axis " + + this.axis + + "]"; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + s.saveFloat(this.linearVel); + s.saveFloat(this.linearDamp); + s.save(this.dir); + s.saveFloat(this.angularVel); + s.saveFloat(this.angularDamp); + s.save(this.axis); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this.linearVel = r.restoreFloat(); + this.linearDamp = r.restoreFloat(); + this.dir = (Point3)r.restore(); + this.angularVel = r.restoreFloat(); + this.angularDamp = r.restoreFloat(); + this.axis = (Point3)r.restore(); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/VideoControlAction.java b/NET/worlds/scape/VideoControlAction.java new file mode 100644 index 0000000..e0e79f3 --- /dev/null +++ b/NET/worlds/scape/VideoControlAction.java @@ -0,0 +1,115 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class VideoControlAction extends Action { + private final int play = 1; + private final int stop = 2; + private int mode = 1; + private int repeat = 1; + private VideoTexture videoTexture = null; + private VideoWall videoWall = null; + private static Object classCookie = new Object(); + + VideoControlAction() { + } + + @Override + public Persister trigger(Event e, Persister seqID) { + if (!this.getVideoTexture()) { + System.out.println("ERROR! Tried to attach VideoControlAction to something other than a Rect with a VideoTexture. or a VideoWall object."); + return null; + } else { + switch (this.mode) { + case 1: + if (this.videoTexture == null) { + this.videoWall.getVideoSurface().play(this.repeat); + } else { + this.videoTexture.getDirectShow().nPlay(this.repeat); + } + break; + case 2: + if (this.videoTexture == null) { + this.videoWall.getVideoSurface().stop(); + } else { + this.videoTexture.getDirectShow().nStop(); + } + } + + return null; + } + } + + private boolean getVideoTexture() { + if (this.videoTexture != null) { + return true; + } else { + Object owner = this.getOwner(); + if (owner != null && owner instanceof Rect) { + Rect r = (Rect)owner; + this.videoTexture = r.getVideoAttribute(); + if (this.videoTexture != null) { + return true; + } else if (owner instanceof VideoWall) { + this.videoWall = (VideoWall)owner; + return true; + } else { + return false; + } + } else { + return false; + } + } + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + super.saveState(s); + s.saveInt(this.mode); + s.saveInt(this.repeat); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this.mode = r.restoreInt(); + break; + case 1: + super.restoreState(r); + this.mode = r.restoreInt(); + this.repeat = r.restoreInt(); + } + } + + @Override + public Object properties(int index, int offset, int pmode, Object value) throws NoSuchPropertyException { + Object ret = null; + switch (index - offset) { + case 0: + if (pmode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "1=Play, 2=Stop")); + } else if (pmode == 1) { + ret = new Integer(this.mode); + } else if (pmode == 2) { + this.mode = (Integer)value; + } + break; + case 1: + if (pmode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Repeat count (-1 for infinite)")); + } else if (pmode == 1) { + ret = new Integer(this.repeat); + } else if (pmode == 2) { + this.repeat = (Integer)value; + } + break; + default: + ret = super.properties(index, offset + 2, pmode, value); + } + + return ret; + } +} diff --git a/NET/worlds/scape/VideoManager.java b/NET/worlds/scape/VideoManager.java new file mode 100644 index 0000000..b69cfc4 --- /dev/null +++ b/NET/worlds/scape/VideoManager.java @@ -0,0 +1,29 @@ +package NET.worlds.scape; + +import java.util.Hashtable; + +public class VideoManager { + static Hashtable streams = new Hashtable(); + + public static VideoSurface get(String url, int rows, int w, int h) { + Object ob = streams.get(url); + VideoSurface stream; + if (ob == null) { + stream = new VideoSurface(null, rows, w, h); + streams.put(url, stream); + } else { + stream = (VideoSurface)ob; + } + + stream.incReferenceCount(); + stream.open(url); + return stream; + } + + public static void release(VideoSurface stream) { + stream.decReferenceCount(); + if (stream.getReferenceCount() == 0) { + streams.remove(stream.getVideoUrl()); + } + } +} diff --git a/NET/worlds/scape/VideoSurface.java b/NET/worlds/scape/VideoSurface.java new file mode 100644 index 0000000..0bf2528 --- /dev/null +++ b/NET/worlds/scape/VideoSurface.java @@ -0,0 +1,53 @@ +package NET.worlds.scape; + +public class VideoSurface extends TextureSurface { + protected DirectShow _ds; + protected String _currentURL; + protected int referenceCount = 0; + + public VideoSurface(Texture[] texList, int rows, int w, int h) { + super(texList, rows, w, h); + this._ds = new DirectShow(this.getHwnd()); + } + + public void incReferenceCount() { + this.referenceCount++; + } + + public void decReferenceCount() { + this.referenceCount--; + } + + public int getReferenceCount() { + return this.referenceCount; + } + + public int tick() { + return this._ds.nTick(); + } + + public String getVideoUrl() { + return this._currentURL; + } + + public void open(String url) { + if (this._currentURL == null || !this._currentURL.equals(url)) { + this._ds.nStop(); + this._ds.nOpen(url); + this._currentURL = url; + } + } + + public void stop() { + this._ds.nStop(); + } + + public void play(int repeat) { + this._ds.nPlay(repeat); + } + + public synchronized void draw(Texture[] texList, int rows) { + this.setTextures(texList, rows); + this.draw(this._ds); + } +} diff --git a/NET/worlds/scape/VideoTexture.java b/NET/worlds/scape/VideoTexture.java new file mode 100644 index 0000000..cfa07f9 --- /dev/null +++ b/NET/worlds/scape/VideoTexture.java @@ -0,0 +1,232 @@ +package NET.worlds.scape; + +import NET.worlds.core.IniFile; +import NET.worlds.network.URL; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class VideoTexture extends Attribute { + DirectShow _ds = null; + TextureSurface _surface; + Texture[] _textures; + Material _material = null; + String _textureURL = "http://dev.worlds.net/rr-worlds/video/eminem.asf"; + String _defTextureURL = IniFile.override().getIniString("defaultAd", "adworlds.cmp"); + int _xSurface = 128; + int _ySurface = 128; + boolean _autoPlay = true; + int _rows = 1; + private static Object classCookie = new Object(); + + public VideoTexture(int attrID) { + super(attrID); + } + + public VideoTexture() { + } + + @Override + protected void noteAddingTo(SuperRoot owner) { + Rect s = (Rect)((Sharer)owner).getOwner(); + s._videoAttribute = this; + this.assignMaterial(s); + } + + private void assignMaterial(Rect s) { + int xTex = this._xSurface / 128; + if (xTex < 1) { + xTex = 1; + } + + int yTex = this._ySurface / 128; + if (yTex < 1) { + yTex = 1; + } + + this._surface = null; + this._ds = null; + this._rows = yTex; + this._material = new Material(URL.make(this._defTextureURL), xTex, yTex); + s.setMaterial(this._material); + this._textures = this._material.getTextures(); + this._surface = new TextureSurface(this._textures, yTex, this._xSurface, this._ySurface); + this._ds = new DirectShow(this._surface.getHwnd()); + this._ds.nOpen(this._textureURL); + if (this._autoPlay) { + this._ds.nPlay(1); + } + } + + private void setTexture() { + Sharer sh = (Sharer)this.getOwner(); + if (sh != null) { + Rect s = (Rect)sh.getOwner(); + this.assignMaterial(s); + } + } + + @Override + public void detach() { + Rect s = (Rect)((Sharer)this.getOwner()).getOwner(); + s._videoAttribute = null; + if (this._ds != null) { + this._ds.nStop(); + this._ds = null; + } + + super.detach(); + } + + @Override + public void finalize() { + this.releaseAuxilaryData(); + super.finalize(); + } + + public DirectShow getDirectShow() { + return this._ds; + } + + public void videoFrame(FrameEvent f) { + this.draw(); + } + + @Override + public final void noteChange() { + } + + public synchronized void draw() { + if (this._surface != null && this._ds != null) { + this._surface.setTextures(this._material.getTextures(), this._rows); + this._surface.draw(this._ds); + } + } + + @Override + public void generateNetData(DataOutputStream s) throws IOException { + s.writeUTF(this._textureURL); + s.writeInt(this._xSurface); + s.writeInt(this._ySurface); + } + + @Override + public void setFromNetData(DataInputStream ds, int len) throws IOException { + this._textureURL = ds.readUTF(); + this._xSurface = ds.readInt(); + this._ySurface = ds.readInt(); + this.noteChange(); + this.setTexture(); + } + + @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 = StringPropertyEditor.make(new Property(this, index, "Texture URL")); + } else if (mode == 1) { + ret = this._textureURL; + } else if (mode == 2) { + this._textureURL = (String)value; + this.setTexture(); + } + break; + case 1: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Texture Width"), 0, 1024); + } else if (mode == 1) { + ret = new Integer(this._xSurface); + } else if (mode == 2) { + this._xSurface = (Integer)value; + this.setTexture(); + } + break; + case 2: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Texture Height"), 0, 1024); + } else if (mode == 1) { + ret = new Integer(this._ySurface); + } else if (mode == 2) { + this._ySurface = (Integer)value; + this.setTexture(); + } + break; + case 3: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Auto-play?"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this._autoPlay); + } else if (mode == 2) { + this._autoPlay = (Boolean)value; + this.setTexture(); + } + break; + default: + ret = super.properties(index, offset + 4, mode, value); + } + + if (mode == 2) { + this.noteChange(); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + super.saveState(s); + s.saveString(this._textureURL); + s.saveInt(this._xSurface); + s.saveInt(this._ySurface); + s.saveBoolean(this._autoPlay); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this._textureURL = r.restoreString(); + this._xSurface = r.restoreInt(); + this._ySurface = r.restoreInt(); + this.noteChange(); + break; + case 1: + super.restoreState(r); + this._textureURL = r.restoreString(); + this._xSurface = r.restoreInt(); + this._ySurface = r.restoreInt(); + this._autoPlay = r.restoreBoolean(); + this.noteChange(); + break; + default: + throw new TooNewException(); + } + + this.setTexture(); + } + + @Override + public void releaseAuxilaryData() { + if (this._ds != null) { + this._ds.nStop(); + this._ds = null; + } + + if (this._surface != null) { + this._surface.finalize(); + this._surface = null; + } + + if (this._material != null) { + this._material.detach(); + this._material.finalize(); + this._material = null; + } + + this._textures = null; + } +} diff --git a/NET/worlds/scape/VideoWall.java b/NET/worlds/scape/VideoWall.java new file mode 100644 index 0000000..9969c71 --- /dev/null +++ b/NET/worlds/scape/VideoWall.java @@ -0,0 +1,191 @@ +package NET.worlds.scape; + +import NET.worlds.core.IniFile; +import NET.worlds.network.URL; +import java.io.IOException; + +public class VideoWall extends Rect { + VideoSurface _surface = null; + Texture[] _textures; + Material _material = null; + String _textureURL = "http://dev.worlds.net/rr-worlds/video/fatboy.asf"; + String _defTextureURL = IniFile.override().getIniString("defaultAd", "adworlds.cmp"); + int _xSurface = 140; + int _ySurface = 104; + boolean _autoPlay = true; + int _autoPlayRepeats = 1; + int _rows = 1; + private static Object classCookie = new Object(); + + private void rebuild() { + this.unbuild(); + int xTex = this._xSurface / 128 + 1; + int yTex = this._ySurface / 128 + 1; + this._surface = null; + this._rows = yTex; + this._material = new Material(URL.make(this._defTextureURL), xTex, yTex); + this.setMaterial(this._material); + this._textures = this._material.getTextures(); + this._surface = VideoManager.get(this._textureURL, yTex, this._xSurface, this._ySurface); + if (this._autoPlay) { + this._surface.play(1); + } + } + + @Override + public void finalize() { + this.unbuild(); + super.finalize(); + } + + @Override + public void detach() { + this.unbuild(); + super.detach(); + } + + private void unbuild() { + if (this._surface != null) { + this._surface.stop(); + VideoManager.release(this._surface); + this._surface = null; + } + } + + public void changeURL(String newURL, int width, int height) { + this._textureURL = new String(newURL); + this._xSurface = width; + this._ySurface = height; + this.rebuild(); + } + + @Override + public boolean handle(FrameEvent f) { + this.getState(); + if (this.visible) { + this.draw(); + } + + return false; + } + + @Override + public void prerender(Camera cam) { + Point3Temp p = this.inCamSpace(cam); + boolean v = p != null && p.z > 1.0F && p.x < p.z && -p.x < p.z; + if (v) { + this.visible = true; + } + } + + public VideoSurface getVideoSurface() { + return this._surface; + } + + public synchronized void draw() { + if (this._surface != null) { + this._surface.draw(this._material.getTextures(), this._rows); + } + } + + public int getState() { + return this._surface != null ? this._surface.tick() : 0; + } + + @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 = StringPropertyEditor.make(new Property(this, index, "Video URL")); + } else if (mode == 1) { + ret = this._textureURL; + } else if (mode == 2) { + this._textureURL = (String)value; + this.rebuild(); + } + break; + case 1: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Video Width (pixels)"), 0, 1024); + } else if (mode == 1) { + ret = new Integer(this._xSurface); + } else if (mode == 2) { + this._xSurface = (Integer)value; + this.rebuild(); + } + break; + case 2: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Video Height (pixels)"), 0, 1024); + } else if (mode == 1) { + ret = new Integer(this._ySurface); + } else if (mode == 2) { + this._ySurface = (Integer)value; + this.rebuild(); + } + break; + case 3: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Auto-play?"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this._autoPlay); + } else if (mode == 2) { + this._autoPlay = (Boolean)value; + this.rebuild(); + } + break; + case 4: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Repeats for Autoplay (-1 = infinite)"), -1, 1024); + } else if (mode == 1) { + ret = new Integer(this._autoPlayRepeats); + } else if (mode == 2) { + this._autoPlayRepeats = (Integer)value; + this.rebuild(); + } + break; + default: + ret = super.properties(index, offset + 5, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + super.saveState(s); + s.saveString(this._textureURL); + s.saveInt(this._xSurface); + s.saveInt(this._ySurface); + s.saveBoolean(this._autoPlay); + s.saveInt(this._autoPlayRepeats); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this._textureURL = r.restoreString(); + this._xSurface = r.restoreInt(); + this._ySurface = r.restoreInt(); + this._autoPlay = r.restoreBoolean(); + break; + case 1: + super.restoreState(r); + this._textureURL = r.restoreString(); + this._xSurface = r.restoreInt(); + this._ySurface = r.restoreInt(); + this._autoPlay = r.restoreBoolean(); + this._autoPlayRepeats = r.restoreInt(); + break; + default: + throw new TooNewException(); + } + + this.rebuild(); + } +} diff --git a/NET/worlds/scape/VisiAttribute.java b/NET/worlds/scape/VisiAttribute.java new file mode 100644 index 0000000..60c9fdb --- /dev/null +++ b/NET/worlds/scape/VisiAttribute.java @@ -0,0 +1,56 @@ +package NET.worlds.scape; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class VisiAttribute extends Attribute { + private static Object classCookie = new Object(); + + public VisiAttribute(int attrID) { + super(attrID); + } + + public VisiAttribute() { + } + + @Override + protected void noteAddingTo(SuperRoot owner) { + WObject w = (WObject)((Sharer)owner).getOwner(); + w._visibilityAttribute = this; + } + + @Override + public void detach() { + WObject w = (WObject)((Sharer)this.getOwner()).getOwner(); + w._visibilityAttribute = null; + super.detach(); + } + + @Override + public void generateNetData(DataOutputStream s) throws IOException { + s.writeBoolean(((WObject)this.getOwner().getOwner()).getVisible()); + } + + @Override + public void setFromNetData(DataInputStream ds, int len) throws IOException { + ((WObject)this.getOwner().getOwner()).setVisible(ds.readBoolean()); + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/WMPSoundPlayer.java b/NET/worlds/scape/WMPSoundPlayer.java new file mode 100644 index 0000000..9f5fadf --- /dev/null +++ b/NET/worlds/scape/WMPSoundPlayer.java @@ -0,0 +1,65 @@ +package NET.worlds.scape; + +import NET.worlds.console.WebControlImp; +import NET.worlds.network.URL; + +public class WMPSoundPlayer extends SoundPlayer { + protected DirectShow ds; + protected boolean disabled; + static int activeCount = 0; + boolean playing = false; + + public WMPSoundPlayer(Sound owner) { + super(owner); + this.ds = new DirectShow(); + } + + public static boolean isActive() { + return activeCount > 0; + } + + @Override + public boolean open(float volume, float stopDist, boolean atten, boolean pan) { + return true; + } + + @Override + public void start(int repeat) { + String megaURL = this.owner.getURL().toString(); + megaURL = WebControlImp.processURL(megaURL); + this.ds.nOpen(URL.make(megaURL).unalias()); + activeCount++; + this.ds.nPlay(repeat); + this.playing = true; + } + + @Override + public boolean position(Point3Temp cam, Point3Temp obj, Point3Temp out, Point3Temp up) { + return true; + } + + @Override + public int getState() { + int nativeState = this.ds.nTick(); + return nativeState == 3 ? 0 : 1; + } + + @Override + public void stop() { + this.ds.nStop(); + activeCount--; + this.playing = false; + } + + @Override + public void close() { + if (this.playing) { + this.stop(); + } + } + + @Override + public boolean setVolume(float v) { + return true; + } +} diff --git a/NET/worlds/scape/WObject.java b/NET/worlds/scape/WObject.java new file mode 100644 index 0000000..dd2d26f --- /dev/null +++ b/NET/worlds/scape/WObject.java @@ -0,0 +1,1450 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.Gamma; +import NET.worlds.console.RightMenu; +import NET.worlds.core.IniFile; +import NET.worlds.core.Std; +import NET.worlds.network.NetworkObject; +import NET.worlds.network.URL; +import NET.worlds.network.WorldServer; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Vector; + +public class WObject extends Transform implements Prerenderable { + private boolean mouseOver = false; + private String _toolTipText; + private Vector<WObject> contents = null; + private Shadow shadow; + public static boolean shadowsOn = IniFile.gamma().getIniInt("shadows", 0) != 0; + protected boolean discarded = false; + protected int clumpID; + protected int highlightID = 0; + protected static final int isVisibleMask = 1; + protected static final int isBumpableMask = 2; + protected static final int isHologramRoughCutMask = 4; + protected static final int isMirrored = 4; + protected static final int isOptimizableMask = 8; + protected static final int isDrawFirstOnIntersectionMask = 16; + protected static final int isDrawOrderUnimportantMask = 32; + protected static final int isMaterialVisible = 64; + protected static final int isHighlitMask = 128; + protected static final int isAutoGapMask = 256; + protected static final int isAutoGapFromLocalMask = 512; + protected static final int isDisablePixelDoublingMask = 1024; + protected static final int isSharerMode0 = 2048; + protected static final int isSharerMode1 = 4096; + protected static final int isSharerMode2 = 8192; + protected static final int duringRestore = 16384; + protected static final int isShadowedLocally = 32768; + protected static final int isShadowed = 65536; + protected static final int isAutobuiltMask = 131072; + protected static final int isHologramViewplaneAlignedMask = 262144; + protected static final int isDontConnect = 262144; + protected static final int isSurfaceUFlippedMask = 524288; + protected static final int isSurfaceVFlippedMask = 1048576; + protected static final int isReclumpingMask = 2097152; + protected static final int isHologramAutosize = 4194304; + protected int flags = 3; + Vector<Object> eventHandlers; + protected Vector<Action> actions = null; + protected BumpCalc bumpCalc = null; + static BumpCalc standardBoxBumpCalc = new BoxBumpCalc(); + private static Object classCookie = new Object(); + public static boolean replaceWithMontyDoor = IniFile.gamma().getIniInt("replaceWithMontyDoor", 0) != 0; + private Sharer _sharer = null; + public VisiAttribute _visibilityAttribute; + public TransAttribute _transformAttribute; + public BumpAttribute _bumpableAttribute; + + static { + nativeInit(); + standardBoxBumpCalc.setName("defaultBoxBumpCalc"); + } + + public static native void nativeInit(); + + public boolean getMouseOver() { + if (this.mouseOver) { + return true; + } else { + WObject obj; + try { + obj = (WObject)this.getOwner(); + } catch (ClassCastException var3) { + return false; + } + + return obj == null ? false : obj.getMouseOver(); + } + } + + public void setMouseOver(boolean m) { + this.mouseOver = m; + } + + public String getToolTipText() { + if (this._toolTipText != null) { + return this._toolTipText; + } else { + WObject obj; + try { + obj = (WObject)this.getOwner(); + } catch (ClassCastException var3) { + return null; + } + + return obj == null ? null : obj.getToolTipText(); + } + } + + public void setToolTipText(String newText) { + this._toolTipText = newText; + } + + @Override + public void setName(String v) { + super.setName(this.getBangName(v)); + } + + private String getBangName(String s) { + boolean hasBang = s.startsWith("!"); + if (hasBang != this.isDynamic()) { + return hasBang ? s.substring(1) : "!" + s; + } else { + return s; + } + } + + @Override + public void markEdited() { + if (!this.isDynamic()) { + super.markEdited(); + } + } + + @Override + public void getChildren(DeepEnumeration d) { + if (this.contents != null) { + d.addChildVector(this.contents); + } + + if (this.eventHandlers != null) { + d.addChildVector(this.eventHandlers); + } + + if (this.actions != null) { + d.addChildVectorAction(this.actions); + } + + if (this._sharer != null) { + d.addChildElement(this._sharer); + } + } + + public void add(WObject child) { + super.add(child); + if (this.hasClump()) { + child.recursiveAddRwChildren(this); + } + + if (child._sharer != null) { + child._sharer.adjustShare(); + } + + if (this.contents == null) { + this.contents = new Vector<WObject>(); + } + + this.contents.addElement(child); + } + + public Enumeration<?> getContents() { + return this.contents == null ? new Vector().elements() : this.contents.elements(); + } + + public boolean hasContents() { + return this.contents != null; + } + + public boolean contentsContain(WObject w) { + return this.contents == null ? false : this.contents.contains(w); + } + + @Override + protected void noteUnadding(SuperRoot child) { + if (this.contents != null && this.contents.removeElement(child) && this.contents.size() == 0) { + this.contents = null; + } + } + + public void makeShadow() { + assert this.shadow == null; + + this.shadow = new DiskShadow(this); + } + + @Override + public void detach() { + if (this.clumpID != 0) { + this.markVoid(); + } + + super.detach(); + if (this._sharer != null) { + this._sharer.adjustShare(); + } + + if (this.shadow != null) { + this.shadow.adjustShadow(this); + this.shadow = null; + } + } + + @Override + public void discard() { + super.discard(); + this.discarded = true; + if (this.contents != null) { + int i = this.contents.size(); + + while (--i >= 0) { + this.contents.elementAt(i).discard(); + } + } + + if (this.eventHandlers != null) { + int i = this.eventHandlers.size(); + + while (--i >= 0) { + this.removeHandler((SuperRoot)this.eventHandlers.elementAt(i)); + } + } + + if (this.actions != null) { + int i = this.actions.size(); + + while (--i >= 0) { + this.removeAction(this.actions.elementAt(i)); + } + } + + this.releaseAuxilaryData(); + } + + @Override + protected void finalize() { + if (!this.discarded) { + this.releaseAuxilaryData(); + } + + super.finalize(); + } + + public void reclump() { + if (this.clumpID != 0) { + assert (this.flags & 2097152) == 0; + + this.flags |= 2097152; + this.markVoid(); + this.recursiveAddRwChildren((WObject)this.getOwner()); + + assert (this.flags & 2097152) != 0; + + this.flags &= -2097153; + } + } + + public boolean isReclumping() { + return (this.flags & 2097152) != 0; + } + + @Override + protected void noteTransformChange() { + this.setClumpMatrix(); + this.updateHighlight(); + if (this.shadow != null) { + this.shadow.adjustShadow(this); + } + + if (this._transformAttribute != null) { + this._transformAttribute.noteChange(); + } + } + + protected void markVoid() { + if (this.contents != null) { + int i = this.contents.size(); + + while (--i >= 0) { + this.contents.elementAt(i).markVoid(); + } + } + + Room r = this.getRoomFromClump(); + if (this instanceof FrameHandler) { + r.removeFrameHandler((FrameHandler)this, this); + } + + if (this.eventHandlers != null) { + int i = this.eventHandlers.size(); + + while (--i >= 0) { + Object f = this.eventHandlers.elementAt(i); + if (f instanceof FrameHandler) { + r.removeFrameHandler((FrameHandler)f, this); + } + } + } + + this.voidClump(); + if (this.shadow != null) { + this.shadow.adjustShadow(this); + } + } + + protected void addRwChildren(WObject parent) { + this.addNewRwChild(parent); + } + + public void recursiveAddRwChildren(WObject parent) { + this.addRwChildren(parent); + if (this.contents != null) { + int end = this.contents.size(); + + for (int i = 0; i < end; i++) { + this.contents.elementAt(i).recursiveAddRwChildren(this); + } + } + } + + protected final void addNewRwChild(WObject container) { + assert this.clumpID == 0; + + this.createClump(); + this.newRwClumpChildHelper(container); + } + + protected void newRwClumpChildHelper(WObject container) { + assert container != null; + + this.addChildToClump(container); + this.newRwChildHelper(); + if (!this.getVisible()) { + this.updateVisible(); + } + + if (this.shadow != null) { + this.shadow.adjustShadow(this); + } else { + if (this.getShadowedLocally() ? !this.getLocalShadowed() : !shadowsOn) { + return; + } + + if (this.inRoomContents() && this.getOwner() instanceof Room) { + this.makeShadow(); + } + } + } + + protected void newRwChildHelper() { + this.initClumpData(); + this.setClumpMatrix(); + Room r = this.getRoom(); + if (this instanceof FrameHandler) { + r.addFrameHandler((FrameHandler)this, this); + } + + if (this.eventHandlers != null) { + for (int i = 0; i < this.eventHandlers.size(); i++) { + Object f = this.eventHandlers.elementAt(i); + if (f instanceof FrameHandler) { + r.addFrameHandler((FrameHandler)f, this); + } + } + } + } + + native void createClump(); + + public final boolean hasClump() { + return this.clumpID != 0; + } + + public final int getID() { + return this.clumpID; + } + + public native boolean nativeInCamSpace(Camera var1, Point3Temp var2); + + public Point3Temp inCamSpace(Camera cam) { + Point3Temp p = Point3Temp.make(); + return this.nativeInCamSpace(cam, p) ? p : null; + } + + protected native void voidClump(); + + protected native int extractClump(); + + native void addChildToClump(WObject var1); + + native void setClumpMatrix(); + + private native void initClumpData(); + + native void doneWithEditing(); + + native int getNumVerts(); + + @Override + public Transform getObjectToWorldMatrix() { + if (this.hasClump()) { + return this.getObjectToWorldMatrix(Transform.make()); + } else { + Transform t = this.getTransform(); + SuperRoot o = this.getOwner(); + if (o instanceof WObject) { + Transform ot = ((WObject)o).getObjectToWorldMatrix(); + t.post(ot); + ot.recycle(); + } + + return t; + } + } + + private native Transform getObjectToWorldMatrix(Transform var1); + + protected native Transform getJointedObjectToWorldMatrix(Transform var1); + + public Point3Temp getWorldPosition() { + Transform t = this.getObjectToWorldMatrix(); + Point3Temp ret = t.getPosition(); + t.recycle(); + return ret; + } + + public native void updateHighlight(); + + public native void getClumpBBox(Point3Temp var1, Point3Temp var2); + + public BoundBoxTemp getClumpBBox() { + Point3Temp start = Point3Temp.make(); + Point3Temp right = Point3Temp.make(); + this.getClumpBBox(start, right); + return BoundBoxTemp.make(start, right); + } + + public WObject setHighlit(boolean b) { + if (b) { + this.flags |= 128; + } else { + this.flags &= -129; + } + + this.updateHighlight(); + return this; + } + + public final boolean getHighlit() { + return (this.flags & 128) != 0; + } + + public void setAutobuilt(boolean b) { + if (b) { + this.flags |= 131072; + } else { + this.flags &= -131073; + } + } + + public final boolean getAutobuilt() { + return (this.flags & 131072) != 0; + } + + public WObject setOptimizable(boolean b) { + if (b) { + this.flags |= 8; + } else { + this.flags &= -9; + } + + return this; + } + + public final boolean getOptimizable() { + return (this.flags & 8) != 0; + } + + final void setSharerMode(int mode) { + assert mode >= 0 && mode < 8; + + this.flags &= -14337; + this.flags |= mode << 11; + this.setName(this.getName()); + } + + final int getSharerMode() { + return this.flags >>> 11 & 7; + } + + public final boolean isDynamic() { + return (this.getSharerMode() & 4) != 0; + } + + public WObject setLocalAutoGap(boolean b) { + if (b) { + this.flags |= 256; + } else { + this.flags &= -257; + } + + if (this instanceof Room) { + Enumeration<Object> e = this.getDeepOwned(); + + while (e.hasMoreElements()) { + Object o = e.nextElement(); + if (o instanceof WObject) { + ((WObject)o).noteTransformChange(); + } + } + } + + return this; + } + + public final boolean getLocalAutoGap() { + return (this.flags & 256) != 0; + } + + public WObject setAutoGapFromRoom(boolean b) { + if (b) { + this.flags &= -513; + } else { + this.flags |= 512; + } + + this.noteTransformChange(); + return this; + } + + public final boolean getAutoGapFromRoom() { + return (this.flags & 512) == 0; + } + + public boolean getAutoGap() { + return ((WObject)(this.getAutoGapFromRoom() ? this.getRoom() : this)).getLocalAutoGap(); + } + + public void setVisible(boolean b) { + if (b != this.getVisible()) { + if (b) { + this.flags |= 1; + } else { + this.flags &= -2; + } + + this.updateVisible(); + if (this.shadow != null) { + this.shadow.adjustShadow(this); + } + + if (this._visibilityAttribute != null) { + this._visibilityAttribute.noteChange(); + } + } + } + + public boolean getLocalShadowed() { + return (this.flags & 65536) != 0; + } + + public void setLocalShadowed(boolean b) { + if (b) { + this.flags |= 65536; + } else { + this.flags &= -65537; + } + } + + public boolean getShadowedLocally() { + return (this.flags & 32768) != 0; + } + + public void setShadowedLocally(boolean b) { + if (b) { + this.flags |= 32768; + } else { + this.flags &= -32769; + } + } + + protected native void updateVisible(); + + public final boolean getVisible() { + return (this.flags & 1) != 0; + } + + public WObject setBumpable(boolean b) { + if (b) { + this.flags |= 2; + } else { + this.flags &= -3; + } + + if (this._bumpableAttribute != null) { + this._bumpableAttribute.noteChange(); + } + + return this; + } + + public final boolean getBumpable() { + return (this.flags & 2) != 0; + } + + public boolean deliver(Event event) { + event.receiver = this; + boolean delivered = event.deliver(this); + if (this.eventHandlers != null) { + Enumeration<Object> e = this.eventHandlers.elements(); + + while (e.hasMoreElements()) { + event.receiver = this; + if (event.deliver(e.nextElement())) { + delivered = true; + } + } + } + + if (delivered) { + return true; + } else { + if (event instanceof UserEvent) { + Object o = this.getOwner(); + if (o instanceof WObject) { + return ((WObject)o).deliver(event); + } + } + + return false; + } + } + + public Enumeration<Object> getHandlers() { + return this.eventHandlers == null ? new Vector<Object>().elements() : this.eventHandlers.elements(); + } + + public boolean hasHandler(SuperRoot h) { + return this.eventHandlers != null && this.eventHandlers.indexOf(h) != -1; + } + + public WObject addHandler(SuperRoot h) { + if (this.eventHandlers == null) { + this.eventHandlers = new Vector<Object>(); + } + + this.eventHandlers.addElement(h); + if (this.clumpID != 0 && h instanceof FrameHandler) { + this.getRoomFromClump().addFrameHandler((FrameHandler)h, this); + } + + super.add(h); + return this; + } + + @Override + public Room getRoom() { + return this.clumpID != 0 ? this.getRoomFromClump() : this.getRoomNotFromClump(); + } + + public Room getRoomNotFromClump() { + SuperRoot o = this.getOwner(); + return o instanceof WObject ? ((WObject)o).getRoomNotFromClump() : null; + } + + public native Room getRoomFromClump(); + + public native boolean inRoomContents(); + + @Override + public World getWorld() { + if (this.clumpID != 0) { + return this.getRoomFromClump().getWorld(); + } else { + Room r = this.getRoomNotFromClump(); + return r == null ? null : r.getWorld(); + } + } + + @Override + public boolean isActive() { + return this.clumpID != 0 ? true : super.isActive(); + } + + public void removeHandler(SuperRoot h) { + if (this.eventHandlers.contains(h)) { + h.detach(); + this.eventHandlers.removeElement(h); + if (this.eventHandlers.size() == 0) { + this.eventHandlers = null; + } + + if (this.clumpID != 0 && h instanceof FrameHandler) { + this.getRoomFromClump().removeFrameHandler((FrameHandler)h, this); + } + } + } + + public Enumeration<Action> getActions() { + return this.actions == null ? new Vector<Action>().elements() : this.actions.elements(); + } + + public boolean hasActions() { + return this.actions != null; + } + + public WObject addAction(Action a) { + if (this.actions == null) { + this.actions = new Vector<Action>(); + } + + this.actions.addElement(a); + super.add(a); + return this; + } + + public void removeAction(Action a) { + assert a.getOwner() == this; + + a.detach(); + this.actions.removeElement(a); + if (this.actions.size() == 0) { + this.actions = null; + } + } + + public void rightMenu() { + new RightMenu(this, this.getActions()); + } + + public void doAction(String actionLabel, Event evt) { + if (actionLabel != null && !actionLabel.equals("")) { + if (Gamma.getShaper() != null && actionLabel.equals("Edit Properties...")) { + Console.getFrame().getEditTile().viewProperties(this); + } else if (this.actions != null) { + int i = 0; + + while (i < this.actions.size()) { + Action candidate = this.actions.elementAt(i); + i++; + if (actionLabel.equals(candidate.rightMenuLabel)) { + RunningActionHandler.trigger(candidate, this.getWorld(), evt); + } + } + } + } + } + + public WObject setBumpCalc(BumpCalc b) { + if (this.bumpCalc != null) { + this.bumpCalc.detach(); + } + + this.bumpCalc = b; + if (this.bumpCalc != null) { + super.add(this.bumpCalc); + } + + return this; + } + + public BumpCalc getBumpCalc(BumpEventTemp b) { + return this.bumpCalc == null ? standardBoxBumpCalc : this.bumpCalc; + } + + public Point3Temp getPlaneExtent() { + return Point3Temp.make(); + } + + public BoundBoxTemp getBoundBox() { + if (this.getVisible()) { + return this.getClumpBBox(); + } else { + Transform xfrm = this.getObjectToWorldMatrix(); + BoundBoxTemp ret = BoundBoxTemp.make(xfrm.getPosition(), this.getPlaneExtent().times(xfrm)); + xfrm.recycle(); + return ret; + } + } + + public float getMinXYExtent() { + if (this.getVisible()) { + return this.getClumpMinXYExtent(); + } else { + BoundBoxTemp box = this.getBoundBox(); + float x = box.hi.x - box.lo.x; + float y = box.hi.y - box.lo.y; + return x < y ? x : y; + } + } + + public native float getClumpMinXYExtent(); + + public void detectBump(BumpEventTemp b) { + BoundBoxTemp box = this.getBoundBox(); + if (!box.isEmpty() && b.bound.overlaps(box)) { + this.getBumpCalc(b).detectBump(b, this); + } + + if (this.contents != null) { + int i = this.contents.size(); + + while (--i >= 0) { + WObject w = this.contents.elementAt(i); + if (w.getBumpable() && b.source != w) { + w.detectBump(b); + } + } + } + } + + public void premoveThrough(Point3Temp motion) { + Point3Temp pos = this.getPosition(); + this.moveThrough(Point3Temp.make(motion).times(this).minus(pos)); + } + + public void moveThrough(Point3Temp motion) { + if (this.getRoom() == null || !this.getBumpable()) { + this.moveBy(motion); + } else if (this.getRoom().hasClump()) { + int now = Std.getRealTime(); + WObject me = this; + + for (int loopCount = 4; loopCount > 0; loopCount--) { + BumpEventTemp be = BumpEventTemp.make(now, me, motion); + + try { + if (be.target == null) { + me.moveBy(be.fullPath); + break; + } + + be.postBumpRoom = me.getRoom(); + be.postBumpPosition = me.getObjectToWorldMatrix().moveBy(be.path); + be.postBumpPath = Point3Temp.make(be.fullPath).times(1.0F - be.fraction); + Transform t = me.getTransform(); + + try { + Room r = this.getRoom(); + be.target.deliver(be); + me.deliver(be); + if (!me.isTransformEqual(t) || r != this.getRoom()) { + break; + } + } finally { + t.recycle(); + } + + Transform invPos = be.postBumpRoom.getObjectToWorldMatrix(); + invPos.invert(); + if (me.getRoom() != be.postBumpRoom) { + invPos.pre(be.postBumpPosition); + me = me.changeRoom(be.postBumpRoom, invPos); + if (me == null) { + break; + } + } else { + me.makeIdentity(); + me.pre(invPos); + me.pre(be.postBumpPosition); + } + + be.postBumpPosition.recycle(); + be.postBumpPosition = null; + invPos.recycle(); + motion = be.postBumpPath; + } finally { + be.recycle(); + } + } + } + } + + protected WObject changeRoom(Room newRoom, Transform invPos) { + this.detach(); + newRoom.add(this); + this.makeIdentity(); + this.pre(invPos); + return this; + } + + @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 = PropAdder.make(new VectorProperty(this, index, "Contents")); + } else if (mode == 1) { + if (this.contents != null) { + ret = this.contents.clone(); + } + } else if (mode == 4) { + ((WObject)value).detach(); + } else if (mode == 3) { + this.add((WObject)value); + } else if (mode == 5 && value instanceof WObject && !(value instanceof Room)) { + ret = value; + } + break; + case 1: + if (mode == 0) { + ret = PropAdder.make(new VectorProperty(this, index, "Event Handlers")); + } else if (mode == 1) { + if (this.eventHandlers != null) { + ret = this.eventHandlers.clone(); + } + } else if (mode == 4) { + this.removeHandler((SuperRoot)value); + } else if (mode == 3) { + this.addHandler((SuperRoot)value); + } else if (mode == 5 && (value instanceof SwitchableBehavior || value instanceof Sensor)) { + ret = value; + } + break; + case 2: + if (mode == 0) { + ret = PropAdder.make(new VectorProperty(this, index, "Actions")); + } else if (mode == 1) { + if (this.actions != null) { + ret = this.actions.clone(); + } + } else if (mode == 4) { + this.removeAction((Action)value); + } else if (mode == 3) { + this.addAction((Action)value); + } else if (mode == 5 && value instanceof Action) { + ret = value; + } + break; + case 3: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Bumpable"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.getBumpable()); + } else if (mode == 2) { + this.setBumpable((Boolean)value); + } + break; + case 4: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Visible"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.getVisible()); + } else if (mode == 2) { + this.setVisible((Boolean)value); + } + break; + case 5: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Sharing Mode (100 for help)", true)); + } else if (mode == 1) { + ret = new Integer(this.getSharerMode()); + } else if (mode == 2) { + int val = (Integer)value; + if (this instanceof Room && val >= 0 && val <= 5) { + Console.println("A Room's sharing mode\nmust be 2, and is\nautomatically set by the shaper."); + } else if (val != 0 && val != 3 && val != 5) { + Console.println("0 = default (chooses 2 or 3 for you)"); + Console.println("2 = static (stored in .world)"); + Console.println("3 = forwarded static"); + Console.println("4 = dynamic (stored only on server)"); + Console.println("5 = forwarded dynamic"); + Console.println("Modes 2, and 4, are not generally\nsupported, except that mode 2\nis required for Rooms"); + } else if (val == 5 && this.getSourceURL() == null) { + Console.println("Only WObjects read from files may be forwarded dynamic."); + } else { + this.getSharer().setMode(val); + } + } + break; + case 6: + if (mode == 0) { + ret = PropAdder.make(new VectorProperty(this, index, "Shared Attributes")); + } else if (mode == 1) { + if (this._sharer != null) { + ret = this._sharer.getAttributesList(); + } else { + ret = new Vector(); + } + } else if (mode == 4) { + this.removeShareableAttribute((Attribute)value); + } else if (mode == 3) { + this.addShareableAttribute((Attribute)value); + } else if (mode == 5 && value instanceof Attribute) { + ret = value; + } + break; + case 7: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Tool Tip Text")); + } else if (mode == 1) { + ret = this.getToolTipText(); + } else if (mode == 2) { + this.setToolTipText((String)value); + } + break; + case 8: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Mouse Change"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.getMouseOver()); + } else if (mode == 2) { + this.setMouseOver((Boolean)value); + } + break; + default: + ret = super.properties(index, offset + 9, mode, value); + } + + return ret; + } + + public static void saveUnsharedWObjects(Saver s, Vector<WObject> v) throws IOException { + int length = 0; + Enumeration<WObject> en = v.elements(); + + while (en.hasMoreElements()) { + WObject w = en.nextElement(); + if (w instanceof Persister && !(w instanceof NonPersister) && !w.isDynamic()) { + length++; + } + } + + s.saveInt(length); + en = v.elements(); + + while (en.hasMoreElements()) { + WObject w = en.nextElement(); + if (w instanceof Persister && !(w instanceof NonPersister) && !w.isDynamic()) { + s.save(w); + } + } + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(10, classCookie); + super.saveState(s); + s.saveInt(this.flags & -129); + if (this.contents == null) { + s.saveBoolean(false); + } else { + s.saveBoolean(true); + saveUnsharedWObjects(s, this.contents); + } + + s.saveVectorMaybeNull(this.eventHandlers); + s.saveVectorMaybeNull(this.actions); + s.saveMaybeNull(this.bumpCalc); + if (this._sharer != null && this._sharer.isEmpty()) { + s.saveMaybeNull(null); + } else { + s.saveMaybeNull(this._sharer); + } + + s.saveString(this.getToolTipText()); + s.saveBoolean(this.getMouseOver()); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + this.restoreWObjectState(r); + } + + public void restoreWObjectState(Restorer r) throws IOException, TooNewException { + Vector<Object> newContents = null; + Vector<Object> newActions = null; + Vector<Object> newHandlers = null; + int vers = r.restoreVersion(classCookie); + switch (vers) { + case 0: + r.setOldFlag(); + super.restoreState(r); + this.flags = r.restoreInt(); + r.restoreMaybeNull(); + this.flags |= 16384; + newContents = r.restoreVectorMaybeNull(); + newHandlers = r.restoreVectorMaybeNull(); + newActions = new Vector<Object>(); + break; + case 1: + r.setOldFlag(); + super.restoreState(r); + this.flags = r.restoreInt(); + r.restoreMaybeNull(); + this.flags |= 16384; + newContents = r.restoreVectorMaybeNull(); + newHandlers = r.restoreVectorMaybeNull(); + newActions = r.restoreVectorMaybeNull(); + break; + case 2: + r.setOldFlag(); + super.restoreState(r); + this.flags = r.restoreInt() | 16384; + newContents = r.restoreVectorMaybeNull(); + newHandlers = r.restoreVectorMaybeNull(); + newActions = r.restoreVectorMaybeNull(); + break; + case 3: + super.restoreState(r); + this.flags = r.restoreInt() | 16384; + newContents = r.restoreVectorMaybeNull(); + newHandlers = r.restoreVectorMaybeNull(); + newActions = r.restoreVectorMaybeNull(); + r.restore(); + break; + case 4: + super.restoreState(r); + this.flags = r.restoreInt() | 16384; + newContents = r.restoreVectorMaybeNull(); + newHandlers = r.restoreVectorMaybeNull(); + newActions = r.restoreVectorMaybeNull(); + r.restore(); + this._sharer = (Sharer)r.restoreMaybeNull(); + break; + case 5: + case 7: + case 8: + super.restoreState(r); + this.flags = r.restoreInt() | 16384; + newContents = r.restoreVectorMaybeNull(); + newHandlers = r.restoreVectorMaybeNull(); + newActions = r.restoreVectorMaybeNull(); + this.setBumpCalc((BumpCalc)r.restoreMaybeNull()); + this._sharer = (Sharer)r.restoreMaybeNull(); + break; + case 6: + super.restoreState(r); + this.flags = r.restoreInt() | 16384; + newContents = r.restoreVectorMaybeNull(); + newHandlers = r.restoreVectorMaybeNull(); + newActions = r.restoreVectorMaybeNull(); + this.setBumpCalc((BumpCalc)r.restoreMaybeNull()); + this._sharer = (Sharer)r.restoreMaybeNull(); + r.restoreString(); + break; + case 9: + super.restoreState(r); + this.flags = r.restoreInt() | 16384; + newContents = r.restoreVectorMaybeNull(); + newHandlers = r.restoreVectorMaybeNull(); + newActions = r.restoreVectorMaybeNull(); + this.setBumpCalc((BumpCalc)r.restoreMaybeNull()); + this._sharer = (Sharer)r.restoreMaybeNull(); + this.setToolTipText(r.restoreString()); + break; + case 10: + super.restoreState(r); + this.flags = r.restoreInt() | 16384; + newContents = r.restoreVectorMaybeNull(); + newHandlers = r.restoreVectorMaybeNull(); + newActions = r.restoreVectorMaybeNull(); + this.setBumpCalc((BumpCalc)r.restoreMaybeNull()); + this._sharer = (Sharer)r.restoreMaybeNull(); + this.setToolTipText(r.restoreString()); + this.setMouseOver(r.restoreBoolean()); + break; + default: + throw new TooNewException(); + } + + if (vers < 8) { + this.flags &= -65; + } + + if (newContents != null) { + for (int i = 0; i < newContents.size(); i++) { + this.add((WObject)newContents.elementAt(i)); + } + } + + if (newActions != null) { + for (int i = 0; i < newActions.size(); i++) { + this.addAction((Action)newActions.elementAt(i)); + } + } + + if (newHandlers != null) { + for (int i = 0; i < newHandlers.size(); i++) { + this.addHandler((SuperRoot)newHandlers.elementAt(i)); + } + } + + if (this._sharer != null) { + super.add(this._sharer); + } + } + + @Override + public void postRestore(int version) { + super.postRestore(version); + if (version < 7) { + Enumeration<Object> en = this.getHandlers(); + + while (en.hasMoreElements()) { + SuperRoot h = (SuperRoot)en.nextElement(); + if (h.getOwner() != this) { + SuperRoot newH = (SuperRoot)h.clone(); + this.eventHandlers.removeElement(h); + if (this.eventHandlers.size() == 0) { + this.eventHandlers = null; + } + + if (this.clumpID != 0 && h instanceof FrameHandler) { + this.getRoomFromClump().removeFrameHandler((FrameHandler)h, this); + } + + this.addHandler(newH); + } + } + } + + if (replaceWithMontyDoor && this.getClass() == WObject.class) { + this.replaceMonty(); + } + + if (this._sharer != null) { + this._sharer.ownerPostRestore(); + } + + this.flags &= -16385; + if (this.isDynamic()) { + this.getSharer(); + } + } + + private void replaceMonty() { + if (this.actions != null && this.actions.size() == 3 && this.getOwner() instanceof WObject) { + int stage = 0; + + try { + if (this.actions.elementAt(0) instanceof SetURLAction) { + SetURLAction sua = (SetURLAction)this.actions.elementAt(0); + if (sua._propName.equals("File") && sua._roomName != null) { + stage = 1; + Object db = this.actions.elementAt(1); + Object cancel = this.actions.elementAt(2); + if (db instanceof DialogAction && cancel.getClass() == db.getClass() && ((DialogAction)cancel).cancelOnly != ((DialogAction)db).cancelOnly) { + if (((DialogAction)db).cancelOnly) { + db = cancel; + } + + stage = 2; + if (this.actions.elementAt(0) instanceof SetURLAction) { + stage = 3; + if (this.contents != null + && this.contents.size() >= 2 + && this.contents.size() <= 3 + && this.contents.elementAt(0).getClass() == Rect.class + && this.contents.elementAt(1).getClass() == Portal.class) { + stage = 4; + boolean isTwoPart = this.contents.size() == 3; + Rect top = (Rect)this.contents.elementAt(0); + Portal port = (Portal)this.contents.elementAt(1); + Rect bottom = null; + if (isTwoPart) { + if (this.contents.elementAt(2).getClass() != Rect.class) { + return; + } + + bottom = (Rect)this.contents.elementAt(2); + } + + stage = 5; + if (top.eventHandlers != null && top.eventHandlers.size() == 1 && top.eventHandlers.elementAt(0).getClass() == ClickSensor.class) { + stage = 6; + ClickSensor cs = (ClickSensor)top.eventHandlers.elementAt(0); + if (cs.countActions() == 1) { + stage = 7; + if (top.actions != null && top.actions.size() == 3 && top.actions.elementAt(2).getClass() == SequenceAction.class) { + stage = 8; + SequenceAction seq = (SequenceAction)top.actions.elementAt(2); + if (seq.actions != null && seq.actions.size() == (isTwoPart ? 9 : 7)) { + stage = 9; + if (port.actions != null && port.actions.size() == 2 && port._farSideRoomName != null && port._farSidePortalName != null + ) + { + stage = 10; + URL texture = (isTwoPart ? bottom : top).getMaterial().textureName; + if (texture != null) { + stage = 11; + MontyDoor md = new MontyDoor(); + md.setsAvatar = db instanceof SelectAvatarAction; + if (!md.setsAvatar) { + if (!(db instanceof SendURLAction)) { + return; + } + + md.description = ((SendURLAction)db).description; + md.url = ((SendURLAction)db).destination; + } else { + md.url = ((SelectAvatarAction)db).url; + } + + stage = 12; + md.viewURL = sua._value; + md.viewName = sua._targetName; + md.setFarSideInfo(null, sua._roomName, port._farSidePortalName); + md.post(port); + md.post(this); + String texName = texture.getInternal(); + if (isTwoPart) { + if (!texName.endsWith("b.cmp")) { + Console.println("Texture: " + texName); + return; + } + + int len = texName.length(); + texName = texName.substring(0, len - 5) + "m2v*.mov"; + } + + stage = 13; + md.setMaterial(new Material(URL.make(texName))); + ((WObject)this.getOwner()).add(md); + this.detach(); + port.detach(); + md.reset(); + stage = 100; + } + } + } + } + } + } + } + } + } + } + } + } finally { + if (stage != 100) { + Console.println("Failed MontyDoor conversion of " + this.getName() + " in stage " + stage + ".\n"); + } + } + } + } + + @Override + public String toString() { + String base = this.getName(); + if (!this.isActive()) { + base = base + "(inactive)"; + } + + base = base + this.toTransformSubstring(); + return this.contents == null ? base : base + this.contents.toString(); + } + + public static String getSaveExtension() { + return "wob"; + } + + public WObject getServed() { + int mode = this.getSharerMode(); + if (mode == 0) { + Sharer s = this.getSharer(); + if (s != null) { + mode = s.getMode(); + } + } + + if ((mode & 1) == 0) { + return this; + } else { + SuperRoot r = this.getOwner(); + return r != null && r instanceof WObject ? ((WObject)r).getServed() : null; + } + } + + @Override + public void prerender(Camera cam) { + WorldScriptManager.getInstance().onPrerender(this, cam); + } + + public WorldServer getServer() { + WObject wo = this.getServed(); + NetworkObject no; + if (wo instanceof Room) { + no = ((Room)wo).getNetworkRoom(); + } else { + no = (NetworkObject)wo; + } + + if (no == null) { + return null; + } else { + assert no != this; + + return no.getServer(); + } + } + + public Enumeration<Attribute> getAttributes() { + return this.getSharer().getAttributes(); + } + + public Sharer getSharer() { + if (this._sharer == null) { + assert (this.flags & 16384) == 0; + + this._sharer = new Sharer(); + super.add(this._sharer); + } + + return this._sharer; + } + + public boolean hasSharer() { + return this._sharer != null; + } + + public Attribute getAttribute(int attrID) { + return this.getSharer().getAttribute(attrID); + } + + public int addAttribute(Attribute a) { + return this.getSharer().addAttribute(a); + } + + public int addShareableAttribute(Attribute a) { + return this.addAttribute(a); + } + + public void removeAttribute(Attribute a) { + this.getSharer().removeAttribute(a); + } + + public void removeShareableAttribute(Attribute a) { + this.removeAttribute(a); + } + + public boolean isShared() { + return this._sharer != null; + } + + public void notifyRegister(int wid) { + } + + public boolean acceptsLeftClicks() { + return this.getMouseOver(); + } + + public void releaseAuxilaryData() { + if (this._sharer != null) { + this._sharer.releaseAuxilaryData(); + } + } +} diff --git a/NET/worlds/scape/WObjectHighlighter.java b/NET/worlds/scape/WObjectHighlighter.java new file mode 100644 index 0000000..8a94f02 --- /dev/null +++ b/NET/worlds/scape/WObjectHighlighter.java @@ -0,0 +1,52 @@ +package NET.worlds.scape; + +import NET.worlds.console.Main; +import NET.worlds.console.MainCallback; + +class WObjectHighlighter implements MainCallback { + private WObject target; + private Room room; + private boolean newState; + private boolean registered; + + public WObjectHighlighter(WObject target) { + this.target = target; + this.start(); + } + + @Override + public synchronized void mainCallback() { + if (this.newState != this.target.getHighlit()) { + this.target.setHighlit(this.newState); + if (this.newState) { + this.room = this.target.getRoom(); + if (this.room != null) { + this.room.highlightTarget = this.target; + } + } else if (this.room != null) { + this.room.highlightTarget = null; + this.room = null; + } + } + + Main.unregister(this); + this.registered = false; + } + + public synchronized void start() { + this.newState = true; + this.registerMe(); + } + + public synchronized void stop() { + this.newState = false; + this.registerMe(); + } + + private synchronized void registerMe() { + if (!this.registered) { + Main.register(this); + this.registered = true; + } + } +} diff --git a/NET/worlds/scape/WaitAction.java b/NET/worlds/scape/WaitAction.java new file mode 100644 index 0000000..376c36f --- /dev/null +++ b/NET/worlds/scape/WaitAction.java @@ -0,0 +1,91 @@ +package NET.worlds.scape; + +import NET.worlds.core.Std; +import java.io.IOException; + +public class WaitAction extends Action { + float duration = 1.0F; + private static Object classCookie = new Object(); + + public WaitAction() { + } + + public WaitAction(float duration) { + this.duration = duration; + } + + @Override + public Persister trigger(Event evt, Persister seqID) { + long evttime = 0L; + if (evt == null) { + evttime = Std.getFastTime(); + } else { + evttime = evt.time; + } + + if (seqID == null) { + seqID = new WaitActionState(evttime + (long)(1000.0F * this.duration)); + } + + if (!((WaitActionState)seqID).run(evttime)) { + seqID = null; + } + + return seqID; + } + + @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 = FloatPropertyEditor.make(new Property(this, index, "Duration (s)")); + } else if (mode == 1) { + ret = new Float(this.duration); + } else if (mode == 2) { + this.duration = (Float)value; + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(2, classCookie); + super.saveState(s); + s.saveFloat(this.duration); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + r.setOldFlag(); + super.restoreState(r); + this.duration = r.restoreInt(); + break; + case 1: + r.setOldFlag(); + super.restoreState(r); + this.duration = r.restoreFloat(); + r.restoreLong(); + break; + case 2: + super.restoreState(r); + this.duration = r.restoreFloat(); + break; + default: + throw new TooNewException(); + } + } + + @Override + public String toString() { + return super.toString() + "[" + this.duration + " s]"; + } +} diff --git a/NET/worlds/scape/WaitActionState.java b/NET/worlds/scape/WaitActionState.java new file mode 100644 index 0000000..70d6d7f --- /dev/null +++ b/NET/worlds/scape/WaitActionState.java @@ -0,0 +1,41 @@ +package NET.worlds.scape; + +import NET.worlds.core.Std; +import java.io.IOException; + +class WaitActionState implements Persister { + long endTime; + private static Object classCookie = new Object(); + + WaitActionState() { + } + + WaitActionState(long endTime) { + this.endTime = endTime; + } + + public boolean run(long time) { + return time < this.endTime; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + s.saveLong(this.endTime - Std.getFastTime()); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + this.endTime = r.restoreLong() + Std.getFastTime(); + return; + default: + throw new TooNewException(); + } + } + + @Override + public void postRestore(int version) { + } +} diff --git a/NET/worlds/scape/WavSoundPlayer.java b/NET/worlds/scape/WavSoundPlayer.java new file mode 100644 index 0000000..c1bff8a --- /dev/null +++ b/NET/worlds/scape/WavSoundPlayer.java @@ -0,0 +1,275 @@ +package NET.worlds.scape; + +import NET.worlds.core.IniFile; +import NET.worlds.network.URL; +import java.util.Vector; + +public class WavSoundPlayer extends SoundPlayer implements Runnable { + float ang; + float dist; + float vol; + private String playingSoundFile = ""; + private URL url; + private static Vector soundStack = new Vector(); + private static Thread activeThread; + int repeatsLeft; + private static int playingThreads; + private static int systemPaused; + static boolean ignoreVolumeChanges = IniFile.gamma().getIniInt("ignoreVolumeChanges", 1) != 0; + private static WavSoundTerminator terminator = new WavSoundTerminator(); + private static float lastLeftVol; + private static float lastRightVol; + + static { + nativeInit(); + } + + public WavSoundPlayer(Sound owner) { + super(owner); + } + + public static native void nativeInit(); + + @Override + public boolean open(float volume, float stopDist, boolean atten, boolean pan) { + return true; + } + + @Override + public void close() { + this.stop(); + } + + @Override + public boolean position(Point3Temp cam, Point3Temp obj, Point3Temp out, Point3Temp up) { + Point3Temp toObj = Point3Temp.make(obj).minus(cam); + Point3Temp right = Point3Temp.make(out).cross(up); + float y = toObj.dot(out); + float x = toObj.dot(right); + this.ang = (float)(Math.atan2(y, x) / Math.PI); + this.dist = toObj.length(); + return this.setVolume(this.vol); + } + + @Override + public boolean setVolume(float v) { + this.vol = v; + float leftFrac = 0.5F; + if (this.owner != null && this.owner.getPanning()) { + leftFrac = Math.abs(this.ang); + if (this.ang < 0.0F) { + v = this.vol * (float)(0.5 + Math.abs(0.5 + this.ang)); + } + } + + if (this.owner != null && this.owner.getAttenuate()) { + float stopDist = this.owner.getStopDistance(); + if (this.dist > stopDist) { + this.volume(0.0F, 0.0F); + return false; + } + + v *= (stopDist - this.dist) / stopDist; + } + + this.volume(v * leftFrac, v * (1.0F - leftFrac)); + return true; + } + + @Override + public int getState() { + return soundStack.contains(this) ? 0 : 1; + } + + public void start(URL u) { + this.url = u; + this.start(1); + } + + private static WavSoundPlayer getActive() { + return !soundStack.isEmpty() ? (WavSoundPlayer)soundStack.lastElement() : null; + } + + public static boolean isActive() { + return !soundStack.isEmpty(); + } + + private void play(int repeatCount, boolean reuseLoop) { + this.playingSoundFile = this.url.unalias(); + soundStack.removeElement(this); + soundStack.addElement(this); + this.repeatsLeft = repeatCount; + if (this.repeatsLeft < 0) { + if (!reuseLoop && systemPaused == 0) { + this.nativePlay(true); + } + + activeThread = null; + } else { + activeThread = new Thread(this); + activeThread.start(); + } + } + + @Override + public void start(int repeatCount) { + synchronized (soundStack) { + WavSoundPlayer active = getActive(); + + assert this.repeatsLeft == 0 && active != this; + + if (this.owner != null) { + this.url = this.owner.getURL(); + } + + boolean activeWasLoop = activeThread == null; + boolean reuseLoop = active != null && activeWasLoop && repeatCount < 0 && active.playingSoundFile.equals(this.url.unalias()); + if (active != null) { + active.stop(reuseLoop); + if (activeWasLoop) { + soundStack.addElement(active); + } + } + + this.play(repeatCount, reuseLoop); + } + } + + @Override + public void run() { + synchronized (soundStack) { + if (systemPaused > 0) { + this.repeatsLeft = 0; + return; + } + + playingThreads++; + } + + while (this.repeatsLeft > 0) { + synchronized (soundStack) { + if (activeThread != Thread.currentThread()) { + break; + } + + if (this.repeatsLeft > 0) { + this.repeatsLeft--; + } + } + + this.nativePlay(false); + } + + synchronized (soundStack) { + if (activeThread == Thread.currentThread()) { + assert getActive() == this; + + soundStack.removeElement(this); + activeThread = null; + WavSoundPlayer active = getActive(); + if (active != null) { + active.play(-1, false); + } + } + + playingThreads--; + soundStack.notifyAll(); + } + } + + private void stop(boolean leaveLoopRunning) { + if (getActive() == this) { + boolean isLoop = activeThread == null; + + assert this.repeatsLeft < 0 && isLoop || !leaveLoopRunning; + + this.repeatsLeft = 0; + if (!leaveLoopRunning && isLoop && systemPaused == 0) { + this.nativeStop(); + } + + activeThread = null; + } + + soundStack.removeElement(this); + } + + @Override + public void stop() { + synchronized (soundStack) { + if (getActive() == this) { + this.stop(false); + WavSoundPlayer active = getActive(); + if (active != null) { + active.play(-1, false); + } + } else { + soundStack.removeElement(this); + } + } + } + + public static void pauseSystem() { + pauseSystemExceptASF(); + } + + public static void pauseSystemExceptASF() { + synchronized (soundStack) { + WavSoundPlayer active = getActive(); + boolean isLoop = activeThread == null; + if (active != null) { + if (isLoop) { + active.nativeStop(); + } else { + active.stop(false); + } + } + + systemPaused++; + if (active != null) { + active.play(-1, false); + } + + while (playingThreads > 0) { + try { + soundStack.wait(); + } catch (InterruptedException var4) { + } + } + } + } + + public static void resumeSystem() { + resumeSystemExceptASF(); + } + + public static void resumeSystemExceptASF() { + synchronized (soundStack) { + if (systemPaused > 0) { + systemPaused = 0; + WavSoundPlayer active = getActive(); + if (active != null && activeThread == null) { + active.play(-1, false); + } + } + } + } + + public void volume(float left, float right) { + if (!ignoreVolumeChanges) { + synchronized (soundStack) { + if (getActive() == this && (lastLeftVol != left || lastRightVol != right)) { + lastLeftVol = left; + lastRightVol = right; + this.nativeVolume(left, right); + } + } + } + } + + private native void nativePlay(boolean var1); + + private native void nativeVolume(float var1, float var2); + + private native void nativeStop(); +} diff --git a/NET/worlds/scape/WavSoundTerminator.java b/NET/worlds/scape/WavSoundTerminator.java new file mode 100644 index 0000000..2335fb5 --- /dev/null +++ b/NET/worlds/scape/WavSoundTerminator.java @@ -0,0 +1,21 @@ +package NET.worlds.scape; + +import NET.worlds.console.Main; +import NET.worlds.console.MainCallback; +import NET.worlds.console.MainTerminalCallback; + +class WavSoundTerminator implements MainCallback, MainTerminalCallback { + public WavSoundTerminator() { + Main.register(this); + } + + @Override + public void mainCallback() { + } + + @Override + public void terminalCallback() { + WavSoundPlayer.pauseSystem(); + Main.unregister(this); + } +} diff --git a/NET/worlds/scape/WearAction.java b/NET/worlds/scape/WearAction.java new file mode 100644 index 0000000..18e6aa7 --- /dev/null +++ b/NET/worlds/scape/WearAction.java @@ -0,0 +1,339 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.network.URL; +import java.io.IOException; + +public class WearAction extends Action { + char limb = 'B'; + String val = ""; + private static String allowedLimbChars = "PBLMORUVIJKXYZabcdefHQE"; + private static Object classCookie = new Object(); + + @Override + public Persister trigger(Event e, Persister seqID) { + Object owner = this.getOwner(); + if (owner != null) { + setAvLimb(this.limb, this.val); + } + + return null; + } + + public static void setAvLimb(char limb, String v) { + String str = PosableShape.getCurrentAvCustomizable(); + if (str != null) { + int pos = str.indexOf(".", 7); + String bodyType = str.substring(7, pos).toLowerCase(); + int matStart; + int matEnd; + if (limb == 'H' || limb == 'E') { + int head = str.lastIndexOf("NS"); + if (head < 0) { + return; + } + + if (v == null) { + v = bodyType; + if (limb == 'E') { + limb = 'H'; + if (head >= 0 && str.charAt(head + 5) == 'G') { + v = PosableShape.readName(str, head + 6).toLowerCase(); + } + } + } + + int face = str.lastIndexOf("DgT"); + int faceEnd = -1; + if (face < head) { + if (limb == 'E') { + Console.println("Can't change the face of this type of head."); + return; + } + + face = -1; + } else { + faceEnd = face + 2; + + int i; + while ((i = PosableShape.skipMat(str, faceEnd)) != faceEnd) { + faceEnd = i; + } + } + + URL urlVal = PosableShape.getAvURL(v); + if (urlVal == null) { + return; + } + + String val = urlVal.getAbsolute(); + if (val == null) { + return; + } + + if (limb == 'H') { + int newHead = val.lastIndexOf("NS"); + if (newHead < 0) { + return; + } + + String geom = ""; + pos = str.indexOf(".0E", 7); + if (!v.equalsIgnoreCase(str.substring(7, pos))) { + geom = "G" + PosableShape.getBodyType(v); + } + + matStart = head + 5; + matEnd = str.length(); + v = geom + val.substring(newHead + 5); + } else { + int newFace = val.lastIndexOf("Dg"); + if (newFace < 0) { + return; + } + + int newEnd = newFace + 2; + + int i; + while ((i = PosableShape.skipMat(val, newEnd)) != newEnd) { + newEnd = i; + } + + matStart = face; + matEnd = faceEnd; + v = val.substring(newFace, newEnd); + } + } else if (limb == 'Q') { + int sInd = str.lastIndexOf("NS"); + if (sInd < 0) { + Console.println("Can't customize this avatar."); + return; + } + + matStart = sInd + 2; + matEnd = sInd + 5; + if (v == null) { + v = "000"; + } + } else if (limb == 'f') { + int facex = str.lastIndexOf("Dg"); + if (facex > 0) { + int end = facex + 2; + + int i; + while ((i = PosableShape.skipMat(str, end)) != end) { + end = i; + } + + int len = str.length() - 4; + String valx = ""; + + while (i < len) { + char c = str.charAt(i); + if (c == 'Q') { + valx = valx + c; + i++; + } else if (c >= '0' && c <= '9') { + valx = valx + c; + i++; + } else { + int j = PosableShape.skipMat(str, i); + if (i != j) { + valx = valx + "f"; + i = j; + } else { + i++; + } + } + } + + if (v != null) { + str = str.substring(0, end) + valx + ".rwg"; + } else { + URL origURL = PosableShape.getAvURL(bodyType); + String origStr = ""; + if (origURL != null) { + origStr = origURL.getInternal(); + } + + int origFace = origStr.lastIndexOf("Dg"); + if (origFace > 0) { + int origEnd = origFace + 2; + + int k; + while ((k = PosableShape.skipMat(origStr, origEnd)) != origEnd) { + origEnd = k; + } + + str = str.substring(0, end) + origStr.substring(origEnd); + } + } + } + + matStart = PosableShape.getMatPosition(str, limb); + if (matStart < 0) { + return; + } + + matEnd = PosableShape.skipMat(str, matStart); + if (v == null) { + URL origURLx = PosableShape.getAvURL(bodyType); + if (origURLx == null) { + return; + } + + String origStrx = origURLx.getInternal(); + int origMat = PosableShape.getMatPosition(origStrx, limb); + if (origMat < 0) { + return; + } + + int origMatEnd = PosableShape.skipMat(origStrx, origMat); + v = origStrx.substring(origMat, origMatEnd); + } + } else { + matStart = PosableShape.getMatPosition(str, limb); + if (matStart < 0) { + return; + } + + matEnd = PosableShape.skipMat(str, matStart); + if (v == null) { + URL origURLxx = PosableShape.getAvURL(bodyType); + if (origURLxx == null) { + return; + } + + String origStrx = origURLxx.getInternal(); + int origMat = PosableShape.getMatPosition(origStrx, limb); + if (origMat < 0) { + return; + } + + int origMatEnd = PosableShape.skipMat(origStrx, origMat); + v = origStrx.substring(origMat, origMatEnd); + } + } + + Console co = Console.getActive(); + if (co != null) { + co.setAvatar(URL.make(str.substring(0, matStart) + v + str.substring(matEnd))); + } + } + } + + public static String makeMatString(int r, int g, int b) { + StringBuffer sb = new StringBuffer("C"); + sb.append(toBase64(r)); + sb.append(toBase64(g)); + sb.append(toBase64(b)); + return sb.toString(); + } + + public static char toBase64(int i) { + return PosableShape.base64.charAt(i); + } + + @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 = StringPropertyEditor.make(new Property(this, index, "Limb")); + } else if (mode == 1) { + ret = new String("" + this.limb); + } else if (mode == 2) { + String s = (String)value; + if (s.length() == 1 && allowedLimbChars.indexOf(s.charAt(0)) >= 0) { + this.limb = s.charAt(0); + this.val = null; + } else { + Console.println("Limb must one of " + allowedLimbChars); + } + } + break; + case 1: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Value").allowSetNull()); + } else if (mode == 1) { + ret = this.val; + } else if (mode == 2) { + String v = (String)value; + if (v != null) { + if (this.limb != 'H' && this.limb != 'E') { + if (this.limb == 'Q') { + if (v.length() != 3) { + Console.println("Head size must be three letters, usually all the same."); + return ret; + } + + for (int i = 0; i < 3; i++) { + char c = v.charAt(i); + if (c != '0' && (c < 'a' || c > 'z') && (c < 'A' || c > 'Z')) { + Console.println("Head size letters must each be one of z-a9A-Z."); + return ret; + } + } + } else if (v.length() < 1) { + v = null; + } else if (v.charAt(0) != 'C' && v.charAt(0) != 'T') { + Console.println("Material must be C_X, CXYZ, or Ttexname."); + return ret; + } + } else if (PosableShape.readName(v, 0).length() != v.length()) { + Console.println("Head and face must be set to all-lowercase name of body type."); + return ret; + } + } + + this.val = v; + } + break; + default: + ret = super.properties(index, offset + 2, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(1, classCookie); + super.saveState(s); + s.saveString(this.val); + s.saveString("" + this.limb); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + int red = r.restoreInt(); + int green = r.restoreInt(); + int blue = r.restoreInt(); + String v = r.restoreString(); + if (v == null) { + this.val = makeMatString(red, green, blue); + } else { + char c; + if (v.length() == 1 && (c = v.charAt(0)) >= 'A' && c <= 'Z') { + this.val = "C_" + v; + } else { + this.val = "T" + v; + } + } + + this.limb = r.restoreString().charAt(0); + break; + case 1: + super.restoreState(r); + this.val = r.restoreString(); + this.limb = r.restoreString().charAt(0); + break; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/WearWall.java b/NET/worlds/scape/WearWall.java new file mode 100644 index 0000000..ff8ca02 --- /dev/null +++ b/NET/worlds/scape/WearWall.java @@ -0,0 +1,223 @@ +package NET.worlds.scape; + +import NET.worlds.network.URL; +import java.io.IOException; +import java.util.StringTokenizer; + +public class WearWall extends Rect { + char limb = ' '; + String tileList = ""; + WObject[] subs; + private static Object classCookie = new Object(); + + WearWall() { + } + + public void rebuild() { + this.unbuild(); + if (this.limb != ' ') { + int count = 0; + StringTokenizer st = new StringTokenizer(this.tileList); + + while (st.hasMoreTokens()) { + count++; + st.nextToken(); + } + + if (count != 0) { + float width = this.getScaleX(); + float height = this.getScaleZ(); + int wNum = 1; + int hNum = 1; + + while (wNum * hNum < count) { + if (height * (wNum + 1) > width * (hNum + 1)) { + hNum++; + } else { + wNum++; + } + } + + this.subs = new WObject[count]; + float tw = 1.0F / wNum; + float th = 1.0F / hNum; + float wHalfSide = tw * this.getScaleX(); + float hHalfSide = th * this.getScaleZ(); + float sideLen = wHalfSide < hHalfSide ? wHalfSide : hHalfSide; + wHalfSide = (sideLen - 6.0F) / this.getScaleX() / 2.0F; + hHalfSide = (sideLen - 6.0F) / this.getScaleZ() / 2.0F; + st = new StringTokenizer(this.tileList); + float y = -1.0F / this.getScaleY(); + float z = 1.0F - th / 2.0F; + int i = 0; + + for (int row = 0; row < hNum; z -= th) { + float x = tw / 2.0F; + + for (int col = 0; col < wNum; x += tw) { + if (!st.hasMoreTokens()) { + return; + } + + Material m = null; + String s = st.nextToken(); + String bodyType = null; + + label91: { + try { + char c = s.charAt(0); + if (c != 'C' && c != 'T') { + String name = PosableShape.readName(s, 0); + if (this.limb == 'H') { + bodyType = name; + } else { + if (this.limb != 'E') { + break label91; + } + + name = PosableShape.getFace(name); + m = PosableShape.readTexture(name, 0); + } + } else { + if (this.limb == 'H' || this.limb == 'E') { + break label91; + } + + if (c == 'C') { + m = PosableShape.readColor(s, 1); + } else { + m = PosableShape.readTexture(s, 1); + } + } + } catch (StringIndexOutOfBoundsException var25) { + break label91; + } + + if (bodyType != null) { + s = PosableShape.getAvURL(bodyType).getAbsolute(); + int start; + if (s != null && (start = s.indexOf(".0E")) >= 0) { + start = PosableShape.skipLimb(s, start + 3); + if (start >= 0) { + int headIndex = s.lastIndexOf("NS"); + if (headIndex >= 0) { + PosableShape p = new PosableShape( + URL.make(s.substring(0, start) + "PGNG" + PosableShape.getBodyType(bodyType) + "Q" + s.substring(headIndex + 1)), false + ); + p.scale(750.0F / this.getScaleX(), 750.0F / this.getScaleY(), 750.0F / this.getScaleZ()); + p.spin(0.0F, 1.0F, 1.0F, 180.0F); + p.spin(0.0F, 1.0F, 0.0F, 180.0F); + p.moveTo(x, y * 10.0F, z - hHalfSide / 2.0F); + WearAction action = new WearAction(); + action.limb = this.limb; + action.val = bodyType; + p.addAction(action); + p.addHandler(new ClickSensor(action, 1)); + this.add(p); + this.subs[i] = p; + } + } + } + } else if (m != null) { + m.setAmbient(0.75F); + m.setDiffuse(0.0F); + Rect r = new Rect(x - wHalfSide, y, z - hHalfSide, x + wHalfSide, y, z + hHalfSide, m); + WearAction action = new WearAction(); + action.limb = this.limb; + action.val = s; + r.addAction(action); + r.addHandler(new ClickSensor(action, 1)); + this.add(r); + this.subs[i] = r; + } + } + + col++; + i++; + } + + row++; + } + } + } + } + + private void unbuild() { + if (this.subs != null) { + int i = this.subs.length; + + while (--i >= 0) { + if (this.subs[i] != null) { + this.subs[i].detach(); + } + } + } + + this.subs = null; + } + + @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 = StringPropertyEditor.make(new Property(this, index, "Limb")); + } else if (mode == 1) { + ret = new String("" + this.limb); + } else if (mode == 2) { + String s = (String)value; + if (s.length() >= 1) { + this.limb = s.charAt(0); + this.rebuild(); + } + } + break; + case 1: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Tile List")); + } else if (mode == 1) { + ret = new String(this.tileList); + } else if (mode == 2) { + this.tileList = (String)value; + this.rebuild(); + } + break; + default: + ret = super.properties(index, offset + 2, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + this.unbuild(); + s.saveVersion(2, classCookie); + super.saveState(s); + this.rebuild(); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + int vers = r.restoreVersion(classCookie); + switch (vers) { + case 0: + super.restoreState(r); + r.restoreString(); + r.restoreString(); + break; + case 1: + super.restoreState(r); + r.restoreString(); + break; + case 2: + super.restoreState(r); + break; + default: + throw new TooNewException(); + } + + this.rebuild(); + } +} diff --git a/NET/worlds/scape/WebPageWall.java b/NET/worlds/scape/WebPageWall.java new file mode 100644 index 0000000..1dbe843 --- /dev/null +++ b/NET/worlds/scape/WebPageWall.java @@ -0,0 +1,408 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.DefaultConsole; +import NET.worlds.console.NoWebControlException; +import NET.worlds.console.WebControl; +import NET.worlds.console.WebControlFactory; +import NET.worlds.console.WebControlImp; +import NET.worlds.console.WebControlListener; +import NET.worlds.core.IniFile; +import NET.worlds.network.URL; +import java.io.IOException; + +public class WebPageWall extends Rect implements WebControlListener { + WebControlImp _wci = null; + TextureSurface _surface; + Texture[] _textures; + Material _material = null; + String _textureURL = "$SCRIPTSERVERgetad.pl?u=$USERNAME"; + String _postTextureData = null; + String _adURL = "http://www.worlds.com/"; + String _postAdData = null; + String _defTextureURL = IniFile.override().getIniString("defaultAd", "adworlds.cmp"); + int _xPercent = 100; + int _yPercent = 100; + int _xSurface = 468; + int _ySurface = 60; + boolean _hasToolbar = true; + boolean _isFixed = false; + int _rows = 1; + int _refresh = 5; + boolean _passClicks = true; + boolean _isAdBanner = true; + boolean _retryURL = false; + int frameCnt = -1; + private static Object classCookie = new Object(); + + WebPageWall() { + } + + public boolean getIsAdBanner() { + return this._isAdBanner; + } + + public void rebuild() { + this.unbuild(); + this.assignMaterial(); + } + + public void unbuild() { + if (this._wci != null) { + this._wci.detach(); + this._wci = null; + } + } + + @Override + public void detach() { + this.unbuild(); + super.detach(); + } + + @Override + public void finalize() { + this.unbuild(); + super.finalize(); + } + + @Override + public boolean handle(MouseDownEvent event) { + if ((event.key & 1) == 1) { + Point2 pt = this.deproject(); + if (this._passClicks) { + double realX = (double)pt.x * this._surface.getWidth(); + double realY = (double)pt.y * this._surface.getHeight(); + realY = this._surface.getHeight() - realY; + this._surface.sendLeftClick((int)realX, (int)realY); + return false; + } + + Console c = Console.getActive(); + if (c != null && c instanceof DefaultConsole) { + DefaultConsole dc = (DefaultConsole)c; + + try { + WebControl wc = new WebControl(dc.getRender(), this._xPercent, this._yPercent, this._hasToolbar, this._isFixed, false); + wc.activate(); + wc.setURL(this._adURL, this._postAdData); + } catch (NoWebControlException var7) { + new SendURLAction(this._adURL).doIt(); + } + } + } + + return false; + } + + @Override + public void prerender(Camera cam) { + Point3Temp p = this.inCamSpace(cam); + boolean v = p != null && p.z > 1.0F && p.x < p.z && -p.x < p.z; + if (v) { + this.visible = true; + } + } + + @Override + public boolean handle(FrameEvent f) { + if (this.visible) { + if (this._retryURL && this._wci != null) { + if (!this._wci.setURL(this._textureURL, this._postTextureData)) { + return false; + } + + this._retryURL = false; + } + + if (this._surface != null) { + if (this.frameCnt <= this._refresh && this.frameCnt != -1) { + this.frameCnt++; + } else { + if (this.frameCnt != -1 && this._refresh == -1) { + return false; + } + + this.frameCnt = 0; + this.draw(); + } + } + } + + return false; + } + + public WebControlImp getWebControlImp() { + return this._wci; + } + + private void assignMaterial() { + int xTex = this._xSurface / 128; + if (xTex < 1) { + xTex = 1; + } + + int yTex = this._ySurface / 128; + if (yTex < 1) { + yTex = 1; + } + + this._surface = null; + if (this._wci != null) { + this._wci.detach(); + } + + this._wci = null; + this._rows = yTex; + this._material = new Material(URL.make(this._defTextureURL), xTex, yTex); + this.setMaterial(this._material); + this._textures = this._material.getTextures(); + this._surface = new TextureSurface(this._textures, yTex, this._xSurface, this._ySurface); + + try { + this._wci = WebControlFactory.createWebControlImp(this._surface.getHwnd(), false, this._isAdBanner); + } catch (NoWebControlException var4) { + System.out.println("Could not create MSIE control for billboard."); + this._wci = null; + return; + } + + if (!this._wci.setURL(this._textureURL, this._postTextureData)) { + this._retryURL = true; + } + + this._wci.addListener(this); + } + + public synchronized void draw() { + if (this._surface != null && this._wci != null) { + this._surface.setTextures(this._material.getTextures(), this._rows); + this._surface.draw(this._wci); + } + } + + @Override + public void webControlEvent(int eventID) { + if (eventID == 1 && this._refresh == -1) { + this.draw(); + } + } + + @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 = StringPropertyEditor.make(new Property(this, index, "Wall's URL")); + } else if (mode == 1) { + ret = this._textureURL; + } else if (mode == 2) { + this._textureURL = (String)value; + this.rebuild(); + } + break; + case 1: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Wall's POST data")); + } else if (mode == 1) { + ret = this._postTextureData; + } else if (mode == 2) { + this._postTextureData = (String)value; + this.rebuild(); + } + break; + case 2: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Wall Page Width (pixels)"), 0, 1024); + } else if (mode == 1) { + ret = new Integer(this._xSurface); + } else if (mode == 2) { + this._xSurface = (Integer)value; + this.rebuild(); + } + break; + case 3: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Wall Page Height (pixels)"), 0, 1024); + } else if (mode == 1) { + ret = new Integer(this._ySurface); + } else if (mode == 2) { + this._ySurface = (Integer)value; + this.rebuild(); + } + break; + case 4: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Wall Refresh Rate (frames)"), -1, 1024); + } else if (mode == 1) { + ret = new Integer(this._refresh); + } else if (mode == 2) { + this._refresh = (Integer)value; + } + break; + case 5: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Use Scrollbars"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(!this._isAdBanner); + } else if (mode == 2) { + this._isAdBanner = !(Boolean)value; + } + break; + case 6: + if (mode == 0) { + ret = BooleanPropertyEditor.make( + new Property(this, index, "Pass clicks"), "No - Click launches target page", "Yes - Mouse events passed through to wall page" + ); + } else if (mode == 1) { + ret = new Boolean(this._passClicks); + } else if (mode == 2) { + this._passClicks = (Boolean)value; + } + break; + case 7: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Target URL for click")); + } else if (mode == 1) { + ret = this._adURL; + } else if (mode == 2) { + this._adURL = (String)value; + } + break; + case 8: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Target's POST data")); + } else if (mode == 1) { + ret = this._postAdData; + } else if (mode == 2) { + this._postAdData = (String)value; + this.rebuild(); + } + break; + case 9: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Target Page Size Units"), "Percentage", "Pixels"); + } else if (mode == 1) { + ret = new Boolean(this._isFixed); + } else if (mode == 2) { + this._isFixed = (Boolean)value; + } + break; + case 10: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Target X Overlay % or Width"), 0, 1024); + } else if (mode == 1) { + ret = new Integer(this._xPercent); + } else if (mode == 2) { + this._xPercent = (Integer)value; + } + break; + case 11: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Target Y Overlay % or Height"), 0, 1024); + } else if (mode == 1) { + ret = new Integer(this._yPercent); + } else if (mode == 2) { + this._yPercent = (Integer)value; + } + break; + case 12: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Target Page Has Toolbar"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this._hasToolbar); + } else if (mode == 2) { + this._hasToolbar = (Boolean)value; + } + break; + default: + ret = super.properties(index, offset + 13, mode, value); + } + + if (mode == 2) { + this.rebuild(); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(3, classCookie); + super.saveState(s); + s.saveString(this._adURL); + s.saveString(this._textureURL); + s.saveInt(this._xPercent); + s.saveInt(this._yPercent); + s.saveBoolean(this._hasToolbar); + s.saveBoolean(this._isFixed); + s.saveInt(this._xSurface); + s.saveInt(this._ySurface); + s.saveInt(this._refresh); + s.saveBoolean(this._passClicks); + s.saveBoolean(this._isAdBanner); + s.saveString(this._postTextureData); + s.saveString(this._postAdData); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 1: + super.restoreState(r); + this._adURL = r.restoreString(); + this._textureURL = r.restoreString(); + this._xPercent = r.restoreInt(); + this._yPercent = r.restoreInt(); + this._hasToolbar = r.restoreBoolean(); + this._isFixed = r.restoreBoolean(); + this._xSurface = r.restoreInt(); + this._ySurface = r.restoreInt(); + this._refresh = r.restoreInt(); + this._passClicks = r.restoreBoolean(); + this._isAdBanner = r.restoreBoolean(); + break; + case 2: + super.restoreState(r); + this._adURL = r.restoreString(); + this._textureURL = r.restoreString(); + this._xPercent = r.restoreInt(); + this._yPercent = r.restoreInt(); + this._hasToolbar = r.restoreBoolean(); + this._isFixed = r.restoreBoolean(); + this._xSurface = r.restoreInt(); + this._ySurface = r.restoreInt(); + this._refresh = r.restoreInt(); + this._passClicks = r.restoreBoolean(); + this._isAdBanner = r.restoreBoolean(); + this._postTextureData = r.restoreString(); + break; + case 3: + super.restoreState(r); + this._adURL = r.restoreString(); + this._textureURL = r.restoreString(); + this._xPercent = r.restoreInt(); + this._yPercent = r.restoreInt(); + this._hasToolbar = r.restoreBoolean(); + this._isFixed = r.restoreBoolean(); + this._xSurface = r.restoreInt(); + this._ySurface = r.restoreInt(); + this._refresh = r.restoreInt(); + this._passClicks = r.restoreBoolean(); + this._isAdBanner = r.restoreBoolean(); + this._postTextureData = r.restoreString(); + this._postAdData = r.restoreString(); + break; + default: + throw new TooNewException(); + } + + this.rebuild(); + } + + @Override + public boolean acceptsLeftClicks() { + return this.getIsAdBanner() ? true : this.getMouseOver(); + } +} diff --git a/NET/worlds/scape/WebWallControlAction.java b/NET/worlds/scape/WebWallControlAction.java new file mode 100644 index 0000000..7420f51 --- /dev/null +++ b/NET/worlds/scape/WebWallControlAction.java @@ -0,0 +1,128 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class WebWallControlAction extends Action { + private final int reload = 1; + private final int setURL = 2; + private final int refresh = 3; + private final int back = 4; + private final int forward = 5; + private final int stop = 6; + private final int home = 7; + private int mode = 1; + private String url; + private String postData; + private WebPageWall webWall = null; + private static Object classCookie = new Object(); + + WebWallControlAction() { + this.postData = null; + this.url = "http://www.worlds.com/"; + } + + @Override + public Persister trigger(Event e, Persister seqID) { + if (!this.getWebWall()) { + System.out.println("ERROR! Tried to attach WebWallControlAction to something other than a WebWall object."); + return null; + } else { + switch (this.mode) { + case 1: + this.webWall.rebuild(); + break; + case 2: + this.webWall.getWebControlImp().setURL(this.url, this.postData); + break; + case 3: + this.webWall.getWebControlImp().refresh(); + break; + case 4: + this.webWall.getWebControlImp().goBack(); + break; + case 5: + this.webWall.getWebControlImp().goForward(); + break; + case 6: + this.webWall.getWebControlImp().stop(); + break; + case 7: + this.webWall.getWebControlImp().home(); + } + + return null; + } + } + + private boolean getWebWall() { + if (this.webWall != null) { + return true; + } else { + Object owner = this.getOwner(); + if (owner != null && owner instanceof WebPageWall) { + this.webWall = (WebPageWall)owner; + return this.webWall == null ? false : this.webWall.getWebControlImp() != null; + } else { + return false; + } + } + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + s.saveInt(this.mode); + s.saveString(this.url); + s.saveString(this.postData); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this.mode = r.restoreInt(); + this.url = r.restoreString(); + this.postData = r.restoreString(); + } + } + + @Override + public Object properties(int index, int offset, int pmode, Object value) throws NoSuchPropertyException { + Object ret = null; + switch (index - offset) { + case 0: + if (pmode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "1=Reload, 2=SetURL, 3=Refresh, 4=Back, 5=Fwd, 6=Stop, 7=Home")); + } else if (pmode == 1) { + ret = new Integer(this.mode); + } else if (pmode == 2) { + this.mode = (Integer)value; + } + break; + case 1: + if (pmode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "URL for mode 2")); + } else if (pmode == 1) { + ret = this.url; + } else if (pmode == 2) { + this.url = ((String)value).trim(); + } + break; + case 2: + if (pmode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "POST data for mode 2")); + } else if (pmode == 1) { + ret = this.postData; + } else if (pmode == 2) { + this.postData = ((String)value).trim(); + } + break; + default: + ret = super.properties(index, offset + 3, pmode, value); + } + + return ret; + } +} diff --git a/NET/worlds/scape/Whiteboard.java b/NET/worlds/scape/Whiteboard.java new file mode 100644 index 0000000..5fadb07 --- /dev/null +++ b/NET/worlds/scape/Whiteboard.java @@ -0,0 +1,96 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import java.awt.Color; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class Whiteboard extends Attribute { + String _line = "default text"; + private static Object classCookie = new Object(); + + public Whiteboard(int attrID) { + super(attrID); + } + + public Whiteboard() { + } + + @Override + protected void noteAddingTo(SuperRoot owner) { + this.nada((Surface)((Sharer)owner).getOwner()); + this.setOwnerText(); + } + + public void set(String s) { + this._line = s; + this.setOwnerText(); + this.noteChange(); + } + + protected void nada(Surface s) { + } + + private void setOwnerText() { + Sharer sh = (Sharer)this.getOwner(); + if (sh != null) { + Surface surf = (Surface)sh.getOwner(); + surf.setMaterial(new Material(new StringTexture(this._line, Console.message("MaterialFont"), 20, Color.black, Color.white))); + } + } + + public String get() { + return this._line; + } + + @Override + public void generateNetData(DataOutputStream s) throws IOException { + s.writeUTF(this._line); + } + + @Override + public void setFromNetData(DataInputStream ds, int len) throws IOException { + this.set(ds.readUTF()); + } + + @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 = StringPropertyEditor.make(new Property(this, index, "Whiteboard text")); + } else if (mode == 1) { + ret = this._line; + } else if (mode == 2) { + this.set((String)value); + } + break; + default: + ret = super.properties(index, offset + 1, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(0, classCookie); + super.saveState(s); + s.saveString(this._line); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this._line = r.restoreString(); + this.setOwnerText(); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/WidgetButton.java b/NET/worlds/scape/WidgetButton.java new file mode 100644 index 0000000..6d25390 --- /dev/null +++ b/NET/worlds/scape/WidgetButton.java @@ -0,0 +1,125 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.ImageCanvas; +import java.awt.Canvas; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Image; + +abstract class WidgetButton extends Canvas { + private String name; + private Image image; + private Dimension dim; + private String prompt; + private ToolBar toolbar; + private boolean depressed; + + WidgetButton(ToolBar toolbar, String name, String prompt) { + this.name = name; + this.toolbar = toolbar; + this.prompt = prompt; + } + + public WObject getWObject() { + return this.toolbar.getCurrentWObject(); + } + + public String drag(boolean initialDrag, float deltax, float deltay) { + return null; + } + + protected ToolBar getToolBar() { + return this.toolbar; + } + + protected Point3Temp getWorldAxis(int ax, int ay, int az) { + Point3Temp p = new Point3(ax, ay, az).vectorTimes(Pilot.getActive()); + float x = Math.abs(p.x); + float y = Math.abs(p.y); + float z = Math.abs(p.z); + if (x > y) { + if (x > z) { + return p.x > 0.0F ? Point3Temp.make(1.0F, 0.0F, 0.0F) : Point3Temp.make(-1.0F, 0.0F, 0.0F); + } + } else if (y > z) { + return p.y > 0.0F ? Point3Temp.make(0.0F, 1.0F, 0.0F) : Point3Temp.make(0.0F, -1.0F, 0.0F); + } + + return p.z > 0.0F ? Point3Temp.make(0.0F, 0.0F, 1.0F) : Point3Temp.make(0.0F, 0.0F, -1.0F); + } + + protected void applyWorldTransform(boolean initialDrag, Transform t) { + WObject wobj = this.getWObject(); + if (initialDrag) { + Console.getFrame().getEditTile().addUndoable(new UndoablTransform(wobj)); + } + + Point3Temp pos = wobj.getPosition(); + wobj.moveTo(0.0F, 0.0F, 0.0F).post(t).moveBy(pos); + wobj.markEdited(); + } + + public void draw(boolean depressed) { + this.depressed = depressed; + Graphics g = this.getGraphics(); + this.drawOutline(g); + g.dispose(); + } + + public void perform() { + } + + public boolean usesDrag() { + return true; + } + + private void drawOutline(Graphics g) { + g.setColor(this.getBackground()); + g.draw3DRect(0, 0, this.dim.width - 1, this.dim.height - 1, !this.depressed); + } + + public boolean available() { + return this.getWObject() != null; + } + + @Override + public void paint(Graphics g) { + super.paint(g); + if (this.available() && this.dim.width != 0) { + g.drawImage(this.image, 2, 2, this); + this.drawOutline(g); + } + } + + private Dimension imageSize() { + if (this.image == null) { + this.image = ImageCanvas.getSystemImage(this.name, this); + if (this.image != null) { + int width = this.image.getWidth(this); + int height = this.image.getHeight(this); + if (width != -1 && height != -1) { + return this.dim = new Dimension(width + 4, height + 4); + } + } + + this.dim = new Dimension(0, 0); + } + + return this.dim; + } + + @Override + public Dimension preferredSize() { + return this.imageSize(); + } + + @Override + public Dimension minimumSize() { + return this.imageSize(); + } + + public String getPrompt() { + return this.prompt; + } +} diff --git a/NET/worlds/scape/WobClassLoader.java b/NET/worlds/scape/WobClassLoader.java new file mode 100644 index 0000000..cc7b8d5 --- /dev/null +++ b/NET/worlds/scape/WobClassLoader.java @@ -0,0 +1,96 @@ +package NET.worlds.scape; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.util.Hashtable; + +public class WobClassLoader extends ClassLoader { + static Hashtable loaders = new Hashtable(); + Hashtable classes = new Hashtable(); + String zipName; + + public static synchronized Class get(String zipName, String cname) { + WobClassLoader cl = (WobClassLoader)loaders.get(zipName); + if (cl == null) { + cl = new WobClassLoader(zipName); + loaders.put(zipName, cl); + } + + try { + return cl.loadClass(cname, true); + } catch (ClassNotFoundException var4) { + return null; + } + } + + public WobClassLoader(String n) { + this.zipName = n; + } + + @Override + protected synchronized Class loadClass(String cname, boolean resolve) throws ClassNotFoundException { + Class cl = (Class)this.classes.get(cname); + if (cl == null) { + try { + return this.findSystemClass(cname); + } catch (NoClassDefFoundError var7) { + } catch (ClassNotFoundException var8) { + } + + byte[] data = this.loadData(cname); + if (data != null) { + try { + cl = this.defineClass(data, 0, data.length); + } catch (ClassFormatError var6) { + throw new ClassNotFoundException(cname); + } + } + + if (cl == null || !cname.equals(cl.getName())) { + throw new ClassNotFoundException(cname); + } + + this.classes.put(cname, cl); + } + + if (resolve) { + this.resolveClass(cl); + } + + return cl; + } + + private byte[] loadData(String cname) { + byte[] data = (byte[])null; + InputStream in = null; + + byte[] var7; + try { + if (cname == null) { + return null; + } + + File file = new File(this.zipName); + int len = (int)file.length(); + in = new FileInputStream(file); + data = new byte[len]; + if (in.read(data) != len) { + return null; + } + + var7 = data; + } catch (Exception var16) { + return null; + } finally { + if (in != null) { + try { + in.close(); + } catch (Exception var15) { + } + } + } + + return var7; + } +} diff --git a/NET/worlds/scape/WobLoaded.java b/NET/worlds/scape/WobLoaded.java new file mode 100644 index 0000000..11afd39 --- /dev/null +++ b/NET/worlds/scape/WobLoaded.java @@ -0,0 +1,5 @@ +package NET.worlds.scape; + +public interface WobLoaded { + void wobLoaded(WobLoader var1, SuperRoot var2); +} diff --git a/NET/worlds/scape/WobLoader.java b/NET/worlds/scape/WobLoader.java new file mode 100644 index 0000000..eb6d0e6 --- /dev/null +++ b/NET/worlds/scape/WobLoader.java @@ -0,0 +1,107 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.network.URL; + +public class WobLoader implements BGLoaded { + private WobLoaded loaded; + private URL origURL; + SuperRoot value; + + public WobLoader(URL url, WobLoaded loaded) { + this(url, loaded, false); + } + + public WobLoader(URL url, WobLoaded loaded, boolean immediate) { + this.origURL = url; + this.loaded = loaded; + if (url.endsWith(".class")) { + String s = url.getAbsolute(); + if (s.startsWith("system:")) { + int len = s.length(); + + try { + Class c = Class.forName(s.substring(7, len - 6)); + SuperRoot sr = (SuperRoot)c.newInstance(); + sr.loadInit(); + this.gotIt(sr); + } catch (Exception var8) { + var8.printStackTrace(System.out); + Console.println("Can't make instance of class " + url); + this.gotIt(null); + } + + return; + } + } + + if (immediate) { + String s = url.unalias(); + if (s.indexOf(58) > 1) { + this.gotIt(null); + } else { + this.syncBackgroundLoad(this.asyncBackgroundLoad(s, url), url); + } + } else { + BackgroundLoader.get(this, url); + } + } + + public static SuperRoot immediateLoad(URL url) { + WobLoader w = new WobLoader(url, null, true); + return w.value; + } + + @Override + public Object asyncBackgroundLoad(String localName, URL remoteURL) { + return remoteURL.endsWith(".class") ? WobClassLoader.get(localName, remoteURL.getClassName()) : localName; + } + + @Override + public boolean syncBackgroundLoad(Object obj, URL remoteURL) { + SuperRoot sr = null; + if (obj != null) { + if (obj instanceof String) { + sr = SuperRoot.readFile((String)obj, remoteURL); + } else { + try { + sr = (SuperRoot)((Class)obj).newInstance(); + sr.loadInit(); + } catch (Exception var5) { + var5.printStackTrace(System.out); + } + } + } + + this.gotIt(sr); + return false; + } + + private void gotIt(SuperRoot s) { + if (s != null) { + s.setSourceURL(this.origURL); + } + + this.value = s; + if (this.loaded != null) { + this.loaded.wobLoaded(this, s); + } + } + + @Override + public Room getBackgroundLoadRoom() { + if (this.loaded instanceof SuperRoot) { + for (SuperRoot o = (SuperRoot)this.loaded; o != null; o = o.getOwner()) { + if (o instanceof WObject) { + return ((WObject)o).getRoom(); + } + } + } + + return null; + } + + public URL getWobName() { + return this.origURL; + } +} diff --git a/NET/worlds/scape/World.java b/NET/worlds/scape/World.java new file mode 100644 index 0000000..87b7ca4 --- /dev/null +++ b/NET/worlds/scape/World.java @@ -0,0 +1,1157 @@ +package NET.worlds.scape; + +import NET.worlds.console.AdBanner; +import NET.worlds.console.Console; +import NET.worlds.console.Gamma; +import NET.worlds.console.Main; +import NET.worlds.console.WorldsMarkPart; +import NET.worlds.core.Hashtable; +import NET.worlds.core.IniFile; +import NET.worlds.core.Std; +import NET.worlds.network.Galaxy; +import NET.worlds.network.NetUpdate; +import NET.worlds.network.URL; +import NET.worlds.network.WorldServer; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.Enumeration; +import java.util.Vector; + +public class World extends SuperRoot implements URLSelf, LoadedURLSelf, IncrementalRestorer { + static WorldRedirector redir = new WorldRedirector(URL.make(Gamma.getHome() + "redir.txt")); + private static boolean cloistered = false; + private static boolean cloisteredSet = false; + private String adCubeBaseURL = null; + private boolean hasClickableAdCube = false; + private boolean adCubeFormatIsGif = false; + private String defaultAdCubeURL = IniFile.override().getIniString("defaultAdCubeURL", "http://www.worlds.com/"); + private boolean hasBeenEdited = false; + private String defaultRoomName = ""; + protected Hashtable roomHash = new Hashtable(); + protected Vector<Object> roomList = new Vector<Object>(); + Vector<Object> eventHandlers; + private static boolean[] didTouch = new boolean[1]; + private static int lastGeneratedFrameEvents; + private int renderStamp; + private int timeoutAge = 15000; + private int nextRoomCheck = 0; + private static Hashtable worldHash = new Hashtable(); + private static Vector<World> worldList = new Vector<World>(); + private boolean registerable = false; + private static Object classCookie = new Object(); + private static final int INIT = 0; + private static final int RESTOREROOMS = 1; + private static final int ADDROOMS = 2; + private static final int LOADCONSOLE = 3; + private static final int DONE = -1; + private Enumeration<Room> tmpenum; + protected Console console = null; + String loadErr; + static URL defaultServerURL = URL.make("worldserver://www.3dcd.com:6650/"); + private URL worldServerURL; + private URL desiredWorldServerURL = defaultServerURL; + private boolean isCourtesyVIP; + private boolean isForceHuman = false; + private boolean hasAdBanner = false; + private int adBannerWidth = 474; + private int adBannerHeight = 65; + private String adBannerURL = "$SCRIPTSERVERgetad.pl?s=$SERIALNUM"; + private static AdBanner theAdBanner = null; + private boolean isMultiuser; + + World() { + } + + @Override + public World getWorld() { + return this; + } + + public static void load(URL url, LoadedURLSelf callback, boolean force) { + if (Gamma.loadProgress != null) { + Gamma.loadProgress.setMessage("Loading world files..."); + Gamma.loadProgress.advance(); + } + + if (url.toString().indexOf("UserHomeWorld") != -1) { + String homeWorld = WorldsMarkPart.getFirstSystemMarkURL(); + if (homeWorld != null) { + int poundIdx = homeWorld.indexOf("#"); + if (poundIdx != -1) { + homeWorld = homeWorld.substring(0, poundIdx); + } + + url = URL.make(homeWorld); + } + } + + File f = new File(url.unalias()); + if (!f.exists()) { + url = redir.get(url); + } + + if (isProscribed(url, force)) { + callback.loadedURLSelf(null, url, "Can't autoload WorldsStore"); + } else { + World w = (World)worldHash.get(url); + if (w != null) { + w.incRef(); + callback.loadedURLSelf(w, url, null); + } else { + URLSelfLoader.load(url, callback, true); + } + } + } + + public static void load(URL url, LoadedURLSelf callback) { + load(url, callback, false); + } + + public static boolean isCloistered() { + if (!cloisteredSet) { + URL homeDir = URL.make("home:" + WorldsMarkPart.getFirstWorld()); + cloistered = new File(homeDir.unalias() + "/cloistered").exists(); + cloisteredSet = true; + } + + return cloistered; + } + + public static URL getHomeStore() { + URL storeinf = URL.make("home:" + WorldsMarkPart.getFirstWorld() + "/store.inf"); + URL homeStore = URL.make("home:PolyGram/polygramdlb.world"); + File sf = new File(storeinf.unalias()); + if (!sf.exists() || !sf.isFile()) { + sf = new File(URL.make("home:PolyGram/store.inf").unalias()); + if (!sf.exists() || !sf.isFile()) { + return homeStore; + } + } + + try { + BufferedReader rdr = new BufferedReader(new FileReader(sf)); + String s = rdr.readLine(); + rdr.close(); + homeStore = new URL(s); + } catch (IOException var5) { + } + + return homeStore; + } + + public static boolean isWorldsStoreProscribed() { + return isCloistered() && IniFile.gamma().getIniInt("WorldsStoreProscribed", 1) != 0; + } + + public static boolean isProscribed(URL url, boolean forceLoad) { + return !forceLoad && !WorldValidator.allow(url.toString()); + } + + public boolean isHomeWorld() { + URL url = this.getSourceURL(); + if (url != null) { + URL homeURL = URL.make("home:" + WorldsMarkPart.getFirstWorld()); + if (url.unalias().startsWith(homeURL.unalias() + "/")) { + return true; + } + } + + return false; + } + + public void setEdited(boolean state) { + if (state != this.hasBeenEdited) { + this.hasBeenEdited = state; + worldListChanged(); + } + } + + @Override + public void markEdited() { + this.setEdited(true); + } + + public String getAdCubeBaseURL() { + if (this.adCubeBaseURL == null) { + String worldURL = this.getSourceURL().toString(); + if (worldURL.lastIndexOf("/") == -1) { + return "ads/ad"; + } else { + worldURL = worldURL.substring(0, worldURL.lastIndexOf("/")); + WorldServer w = Pilot.getActive().getServer(); + if (w != null && w.getGalaxy().getOnline()) { + String adserverURL = NetUpdate.getUpgradeServerURL(); + if (adserverURL != null) { + int i1 = worldURL.lastIndexOf("/"); + int i2 = worldURL.lastIndexOf(":"); + i1 = i1 > i2 ? i1 : i2; + if (i1 > -1) { + worldURL = worldURL.substring(i1 + 1); + } + + return adserverURL + worldURL + "/ads/ad"; + } + } + + return worldURL + "/ads/ad"; + } + } else { + return this.adCubeBaseURL; + } + } + + public void setAdCubeBaseURL(String s) { + this.adCubeBaseURL = new String(s); + } + + public boolean getHasClickableAdCube() { + return this.hasClickableAdCube; + } + + public void setHasClickableAdCube(boolean b) { + this.hasClickableAdCube = b; + } + + public boolean getAdCubeFormatIsGif() { + return this.adCubeFormatIsGif; + } + + public void setAdCubeFormatIsGif(boolean b) { + this.adCubeFormatIsGif = b; + } + + public String getDefaultAdCubeURL() { + return this.defaultAdCubeURL; + } + + public void setDefaultAdCubeURL(String s) { + this.defaultAdCubeURL = new String(s); + } + + public boolean getEdited() { + return this.hasBeenEdited; + } + + private static void worldListChanged() { + if (Gamma.getShaper() != null) { + Gamma.getShaper().worldListChange(); + } + } + + @Override + public void getChildren(DeepEnumeration d) { + d.addChildEnumeration(this.getRooms()); + if (this.eventHandlers != null) { + d.addChildVector(this.eventHandlers); + } + } + + public Room getRoom(String roomName) { + if (roomName.indexOf("UserHomeRoom") != -1) { + roomName = this.getDefaultRoomName(); + } + + return (Room)this.roomHash.get(roomName); + } + + public String getDefaultRoomName() { + if (this.getRoom(this.defaultRoomName) == null) { + if (this.roomList.isEmpty()) { + this.defaultRoomName = ""; + } else { + this.defaultRoomName = ((Room)this.roomList.elementAt(0)).getName(); + } + } + + return this.defaultRoomName; + } + + public void setDefaultRoomName(String name) { + this.defaultRoomName = name; + } + + public void addRoom(Room room) { + String name = room.getName(); + int roomNum = 1; + + while (this.getRoom(name) != null) { + name = "Room" + roomNum++; + } + + room.setName(name); + this.roomHash.put(name, room); + this.roomList.addElement(room); + this.add(room); + URL sourceURL = this.getSourceURL(); + if (sourceURL != null && worldHash.containsKey(sourceURL)) { + room.register(); + } + } + + public void renameRoom(String oldName, String newName, Room room) { + if (oldName != null) { + assert this.roomHash.get(oldName) == room; + + this.roomHash.remove(oldName); + } else { + assert !this.roomList.removeElement(room); + + this.roomList.addElement(room); + } + + assert newName != null; + + assert room.getName().equals(newName); + + this.roomHash.put(newName, room); + } + + public void removeRoom(Room room) { + this.roomHash.remove(this.roomHash.getKey(room)); + this.roomList.removeElement(room); + } + + public Enumeration<Object> getRooms() { + return this.roomList.elements(); + } + + public static Room findRoomByName(String name) { + Enumeration<World> we = worldList.elements(); + + while (we.hasMoreElements()) { + World w = we.nextElement(); + Enumeration<Object> re = w.getRooms(); + + while (re.hasMoreElements()) { + Room r = (Room)re.nextElement(); + if (r.toString().equals(name)) { + return r; + } + } + } + + return null; + } + + public void invokeActions(String actLabel) { + Enumeration<Object> en = this.getDeepOwned(); + + while (en.hasMoreElements()) { + Object obj = en.nextElement(); + if (obj instanceof WObject) { + ((WObject)obj).doAction(actLabel, null); + } + } + } + + public boolean deliver(FrameEvent event) { + if (this.eventHandlers != null) { + if (Main.profile != 0) { + int i = this.eventHandlers.size(); + + while (--i >= 0) { + FrameHandler fh = (FrameHandler)this.eventHandlers.elementAt(i); + int start = Std.getRealTime(); + long startBytes = Runtime.getRuntime().freeMemory(); + event.retargetAndDeliver(fh, null); + int dur = Std.getRealTime() - start; + long used = Runtime.getRuntime().freeMemory() - startBytes; + if (dur > Main.profile) { + System.out.println("Took " + dur + "ms and " + used + " bytes to call world eventHandler " + fh); + } + } + } else { + int i = this.eventHandlers.size(); + + while (--i >= 0) { + event.retargetAndDeliver((FrameHandler)this.eventHandlers.elementAt(i), null); + } + } + } + + return true; + } + + public static void generateFrameEvents(FrameEvent f) { + didTouch[0] = false; + int now = Std.getFastTime(); + int i = worldList.size(); + + while (--i >= 0) { + World w = worldList.elementAt(i); + if (!w.discardIfOld(didTouch)) { + w.deliver(f); + } + } + + if (Pilot.getActiveWorld() != null) { + lastGeneratedFrameEvents = now; + } + } + + public Enumeration<Object> getHandlers() { + return this.eventHandlers == null ? new Vector<Object>().elements() : this.eventHandlers.elements(); + } + + public boolean hasHandler(SuperRoot h) { + return this.eventHandlers != null && this.eventHandlers.indexOf(h) != -1; + } + + public World addHandler(SuperRoot h) { + if (!(h instanceof FrameHandler)) { + Object[] arguments = new Object[]{new String(h.getName())}; + Console.println(MessageFormat.format(Console.message("FrameHandler"), arguments)); + return this; + } else { + if (this.eventHandlers == null) { + this.eventHandlers = new Vector<Object>(); + } + + this.eventHandlers.addElement(h); + this.add(h); + return this; + } + } + + public void removeHandler(SuperRoot h) { + if (this.eventHandlers.contains(h)) { + h.detach(); + this.eventHandlers.removeElement(h); + if (this.eventHandlers.size() == 0) { + this.eventHandlers = null; + } + } + } + + @Override + public void incRef() { + this.renderStamp = Std.getFastTime(); + } + + @Override + public void decRef() { + } + + private void touchAdjacentRooms(boolean[] didTouch) { + if (!didTouch[0]) { + didTouch[0] = true; + Room r = Pilot.getActiveRoom(); + if (r != null) { + Vector<Portal> portals = r.getOutgoingPortals(); + int i = portals.size(); + + while (--i >= 0) { + Room farr = portals.elementAt(i).farSideRoom(); + if (farr != null) { + farr.noteRef(); + } + } + } + } + } + + boolean discardIfOld(boolean[] didTouch) { + int now = Std.getFastTime(); + if (now < this.nextRoomCheck) { + return false; + } else { + this.nextRoomCheck = now + 5000 + (int)(3000.0 * Math.random()); + this.touchAdjacentRooms(didTouch); + int i = this.roomList.size(); + + while (--i >= 0) { + ((Room)this.roomList.elementAt(i)).discardIfOld(); + } + + if (this.hasBeenEdited) { + return false; + } else { + i = now - this.renderStamp; + if (i > this.timeoutAge && this.renderStamp < lastGeneratedFrameEvents && i > this.timeoutAge) { + this.discard(); + return true; + } else { + return false; + } + } + } + } + + @Override + public void discard() { + URL url = this.getSourceURL(); + synchronized (worldHash) { + worldHash.remove(url); + worldList.removeElement(this); + } + + worldListChanged(); + URLSelfLoader.unload(this); + if (this.eventHandlers != null) { + int i = this.eventHandlers.size(); + + while (--i >= 0) { + this.removeHandler((SuperRoot)this.eventHandlers.elementAt(i)); + } + } + + assert this.eventHandlers == null; + + this.discardRooms(); + if (this.console != null) { + this.console.decRef(); + } + + this.console = null; + System.gc(); + System.runFinalization(); + } + + private void discardRooms() { + while (!this.roomList.isEmpty()) { + Room r = (Room)this.roomList.elementAt(0); + r.discard(); + } + } + + @Override + protected void finalize() { + this.discardRooms(); + super.finalize(); + } + + private void markInitialized() { + if (this.getSourceURL() != null) { + this.register(); + } else { + this.registerable = true; + } + } + + private void register() { + URL url = this.getSourceURL(); + synchronized (worldHash) { + assert !worldHash.containsKey(url); + + worldHash.put(url, this); + worldList.addElement(this); + } + + worldListChanged(); + this.registerable = false; + int i = this.roomList.size(); + + while (--i >= 0) { + ((Room)this.roomList.elementAt(i)).register(); + } + } + + @Override + public void setSourceURL(URL url) { + super.setSourceURL(url); + if (this.registerable) { + this.register(); + } + } + + @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 = StringPropertyEditor.make(new Property(this, index, "Default Room Name")); + } else if (mode == 1) { + ret = this.getDefaultRoomName(); + } else if (mode == 2) { + String name = (String)value; + if (this.getRoom(name) == null) { + Console.println(name + Console.message("No-room-named")); + } else { + this.setDefaultRoomName(name); + } + } + break; + case 1: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Multiuser"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.getMultiuser()); + } else if (mode == 2) { + this.setMultiuser((Boolean)value); + } + break; + case 2: + if (mode == 0) { + ret = new Property(this, index, "Console"); + } else if (mode == 1) { + ret = this.console; + } + break; + case 3: + if (mode == 0) { + ret = PropAdder.make(new VectorProperty(this, index, "Rooms")); + } else if (mode == 1) { + ret = VectorProperty.toVector(this.roomHash); + } else if (mode == 4) { + ((Room)value).detach(); + } else if (mode == 3) { + if (!(value instanceof Room)) { + throw new Error("Can only add Rooms to a World."); + } + + this.addRoom((Room)value); + } else if (mode == 5 && value instanceof Room) { + ret = value; + } + break; + case 4: + if (mode == 0) { + ret = FloatPropertyEditor.make(new Property(this, index, "Time-out Age (seconds)")); + } else if (mode == 1) { + ret = new Float(this.timeoutAge / 1000.0F); + } else if (mode == 2) { + this.timeoutAge = Math.round((Float)value * 1000.0F); + } + break; + case 5: + if (mode == 0) { + ret = PropAdder.make(new VectorProperty(this, index, "Running Actions (delete to stop)")); + } else if (mode == 1) { + if (this.eventHandlers != null) { + ret = this.eventHandlers.clone(); + } + } else if (mode == 4) { + this.removeHandler((SuperRoot)value); + } + break; + case 6: + if (mode == 0) { + ret = URLPropertyEditor.make(new Property(this, index, "Server URL"), "console"); + } else if (mode == 1) { + ret = this.desiredWorldServerURL; + if (ret != null) { + String u = this.desiredWorldServerURL.unalias(); + if (u.startsWith("worldserver://")) { + ret = URL.make(u + "default.console"); + } + } + } else if (mode == 2) { + URL url = (URL)value; + if (url != null) { + String u = url.unalias(); + int len = u.length(); + if (u.startsWith("worldserver://")) { + if (!url.endsWith("/default.console") || len < 31) { + Console.println(Console.message("server-URL") + "default.console"); + break; + } + + u = u.substring(14, len - 16); + } + + url = Console.makeServerURL(u); + } + + this.setWorldServerURL(url); + } + break; + case 7: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Courtesy VIP"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.getCourtesyVIP()); + } else if (mode == 2) { + this.setCourtesyVIP((Boolean)value); + } + break; + case 8: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Force Human"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.getForceHuman()); + } else if (mode == 2) { + this.setForceHuman((Boolean)value); + } + break; + case 9: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Has Ad Banner"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.getHasAdBanner()); + } else if (mode == 2) { + this.setHasAdBanner((Boolean)value); + this.setupAdBanner(); + } + break; + case 10: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Banner Width")); + } else if (mode == 1) { + ret = new Integer(this.getBannerWidth()); + } else if (mode == 2) { + this.setBannerWidth((Integer)value); + this.setupAdBanner(); + } + break; + case 11: + if (mode == 0) { + ret = IntegerPropertyEditor.make(new Property(this, index, "Banner Height")); + } else if (mode == 1) { + ret = new Integer(this.getBannerHeight()); + } else if (mode == 2) { + this.setBannerHeight((Integer)value); + this.setupAdBanner(); + } + break; + case 12: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Ad Banner URL")); + } else if (mode == 1) { + ret = this.getBannerURL(); + } else if (mode == 2) { + String name = (String)value; + this.setBannerURL(name); + } + break; + case 13: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Has Clickable Ad Cube"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.getHasClickableAdCube()); + } else if (mode == 2) { + this.setHasClickableAdCube((Boolean)value); + } + break; + case 14: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Ad Cube image format"), "CMP", "GIF"); + } else if (mode == 1) { + ret = new Boolean(this.getAdCubeFormatIsGif()); + } else if (mode == 2) { + this.setAdCubeFormatIsGif((Boolean)value); + } + break; + case 15: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Ad cube base URL")); + } else if (mode == 1) { + ret = this.getAdCubeBaseURL(); + } else if (mode == 2) { + String name = (String)value; + this.setAdCubeBaseURL(name); + } + break; + case 16: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Ad cube default click URL")); + } else if (mode == 1) { + ret = this.getDefaultAdCubeURL(); + } else if (mode == 2) { + String name = (String)value; + this.setDefaultAdCubeURL(name); + } + break; + default: + ret = super.properties(index, offset + 17, mode, value); + } + + return ret; + } + + @Override + public void saveState(Saver s) throws IOException { + s.saveVersion(13, classCookie); + super.saveState(s); + s.saveString(this.defaultRoomName); + URL.save(s, this.desiredWorldServerURL); + s.saveInt(this.timeoutAge); + s.saveBoolean(this.getMultiuser()); + s.saveBoolean(this.getCourtesyVIP()); + s.saveBoolean(this.getForceHuman()); + s.saveBoolean(this.getHasAdBanner()); + s.saveInt(this.getBannerWidth()); + s.saveInt(this.getBannerHeight()); + s.saveString(this.getBannerURL()); + s.saveBoolean(this.getHasClickableAdCube()); + s.saveBoolean(this.getAdCubeFormatIsGif()); + s.saveString(this.getAdCubeBaseURL()); + s.saveString(this.getDefaultAdCubeURL()); + s.save(this.roomHash); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + URLSelfLoader.immediateLoad(this, r); + } + + private void restoreOldURL(Restorer r) throws IOException { + String s = r.restoreString(); + URL url; + if (s == null || s.equals("UNSHARED")) { + url = null; + } else if (!s.endsWith(".console")) { + url = Console.makeServerURL(s); + } else { + url = URL.restore(r, s, null); + } + + if (url == null) { + url = defaultServerURL; + } else { + this.setMultiuser(true); + } + + this.setWorldServerURL(url); + } + + public int restorePreRooms(Restorer r) throws IOException, TooNewException { + int version = r.restoreVersion(classCookie); + switch (version) { + case 0: + r.setOldFlag(); + this.setName(r.restoreString()); + this.defaultRoomName = r.restoreString(); + this.restoreOldURL(r); + this.roomHash = (Hashtable)r.restore(false); + break; + case 1: + case 3: + r.setOldFlag(); + super.restoreState(r); + this.defaultRoomName = r.restoreString(); + this.restoreOldURL(r); + this.roomHash = (Hashtable)r.restore(false); + break; + case 2: + r.setOldFlag(); + super.restoreState(r); + this.defaultRoomName = r.restoreString(); + this.restoreOldURL(r); + r.restoreString(); + this.roomHash = (Hashtable)r.restore(false); + break; + case 4: + super.restoreState(r); + this.defaultRoomName = r.restoreString(); + this.restoreOldURL(r); + this.roomHash = (Hashtable)r.restore(false); + break; + case 5: + super.restoreState(r); + this.defaultRoomName = r.restoreString(); + this.restoreOldURL(r); + this.timeoutAge = r.restoreInt(); + this.roomHash = (Hashtable)r.restore(false); + break; + case 6: + super.restoreState(r); + this.defaultRoomName = r.restoreString(); + this.restoreOldURL(r); + this.timeoutAge = r.restoreInt(); + r.restoreBoolean(); + this.roomHash = (Hashtable)r.restore(false); + break; + case 7: + super.restoreState(r); + this.defaultRoomName = r.restoreString(); + URL url = URL.restore(r); + if (url == null) { + url = defaultServerURL; + } else { + this.setMultiuser(true); + } + + this.setWorldServerURL(url); + this.timeoutAge = r.restoreInt(); + r.restoreBoolean(); + this.roomHash = (Hashtable)r.restore(false); + break; + case 8: + case 9: + case 10: + case 11: + case 12: + case 13: + super.restoreState(r); + this.defaultRoomName = r.restoreString(); + this.setWorldServerURL(URL.restore(r)); + this.timeoutAge = r.restoreInt(); + this.setMultiuser(r.restoreBoolean()); + if (version > 9) { + this.setCourtesyVIP(r.restoreBoolean()); + } + + if (version > 10) { + this.setForceHuman(r.restoreBoolean()); + } + + if (version > 11) { + this.setHasAdBanner(r.restoreBoolean()); + this.setBannerWidth(r.restoreInt()); + this.setBannerHeight(r.restoreInt()); + this.setBannerURL(r.restoreString()); + } + + if (version > 12) { + this.setHasClickableAdCube(r.restoreBoolean()); + this.setAdCubeFormatIsGif(r.restoreBoolean()); + this.setAdCubeBaseURL(r.restoreString()); + this.setDefaultAdCubeURL(r.restoreString()); + } + + this.roomHash = (Hashtable)r.restore(false); + break; + default: + throw new TooNewException(); + } + + Enumeration<Room> e = this.roomHash.elements(); + + while (e.hasMoreElements()) { + this.roomList.addElement(e.nextElement()); + } + + if (version < 9 && this.timeoutAge == 60000) { + this.timeoutAge = 15000; + } + + return version; + } + + @Override + public Object clone() { + World newWorld = (World)super.clone(); + int worldNum = 1; + + String newname; + URL key; + do { + newname = "World" + worldNum++; + key = URL.make("session:" + newname + ".world"); + } while (worldHash.containsKey(key)); + + newWorld.setName(newname); + newWorld.setSourceURL(key); + return newWorld; + } + + @Override + public int incRestore(int state, Restorer r, URLSelfLoader p) throws Exception { + switch (state) { + case 0: + p.itemp2 = this.restorePreRooms(r); + p.itemp1 = this.roomHash.restoreCount(r); + case 1: + if (--p.itemp1 >= 0) { + this.roomHash.restoreEntry(r); + return 1; + } else { + if (p.itemp2 == 4) { + this.timeoutAge = r.restoreInt(); + if (this.timeoutAge == 900000 || this.timeoutAge == 60000) { + this.timeoutAge = 15000; + } + } + + if (r.version() < 3) { + return -1; + } + } + case 2: + case 3: + return this.finishRestore(state, r.version() != Saver.version() || r.oldFlag(), p.getURL()); + default: + assert false; + + return -1; + } + } + + public int finishRestore(int state, boolean oldFlag, URL url) throws Exception { + switch (state) { + case 0: + case 1: + this.tmpenum = this.roomHash.elements(); + this.roomHash = new Hashtable(); + case 2: + if (this.tmpenum.hasMoreElements()) { + Room rm = this.tmpenum.nextElement(); + this.addRoom(rm); + return 2; + } else { + this.tmpenum = null; + } + case 3: + if (this.console == null && this.loadErr == null) { + return 3; + } else { + if (this.loadErr != null) { + throw new IOException(this.loadErr); + } + + this.markInitialized(); + return -1; + } + default: + assert false; + + return -1; + } + } + + @Override + public void postRestore(int version) { + super.postRestore(version); + if (version <= 2) { + int state = 0; + + try { + while ((state = this.finishRestore(state, true, URL.make("error:This file"))) != -1) { + } + } catch (Exception var4) { + var4.printStackTrace(System.out); + + assert false; + } + } + } + + public Console getConsole() { + return this.console; + } + + @Override + public void loadedURLSelf(URLSelf o, URL url, String err) { + if (err == null && o instanceof Console) { + Console oldConsole = this.console; + this.console = (Console)o; + if (oldConsole != null) { + Galaxy oldGalaxy = oldConsole.getGalaxy(); + Galaxy galaxy = this.console.getGalaxy(); + + assert oldGalaxy != null; + + assert galaxy != null; + + if (oldGalaxy != galaxy) { + oldGalaxy.forceObjectRereg(); + } + + oldConsole.decRef(); + } + + this.worldServerURL = url; + if (Pilot.getActive() != null && Pilot.getActive().getWorld() == this) { + Pilot.changeActiveRoom(Pilot.getActive().getRoom()); + } + } else { + if (err == null) { + Object[] arguments = new Object[]{new String("" + url)}; + Console.println(MessageFormat.format(Console.message("no-world"), arguments)); + o.decRef(); + } + + Console.println(Console.message("cant-load") + err); + Console.load(null, this); + } + } + + public boolean getCourtesyVIP() { + return this.isCourtesyVIP; + } + + private void setCourtesyVIP(boolean b) { + this.isCourtesyVIP = b; + } + + public boolean getForceHuman() { + return this.isForceHuman; + } + + private void setForceHuman(boolean b) { + this.isForceHuman = b; + } + + public boolean getHasAdBanner() { + return this.hasAdBanner; + } + + public void setHasAdBanner(boolean b) { + this.hasAdBanner = b; + } + + public int getBannerWidth() { + return this.adBannerWidth; + } + + public void setBannerWidth(int i) { + this.adBannerWidth = i; + } + + public int getBannerHeight() { + return this.adBannerHeight; + } + + public void setBannerHeight(int i) { + this.adBannerHeight = i; + } + + public String getBannerURL() { + return this.adBannerURL; + } + + public void setBannerURL(String s) { + this.adBannerURL = s; + } + + public void setupAdBanner() { + if (theAdBanner != null) { + theAdBanner.detach(); + theAdBanner = null; + } + + if (this.hasAdBanner) { + theAdBanner = new AdBanner(this.adBannerWidth, this.adBannerHeight, this.adBannerURL); + } + } + + private boolean getMultiuser() { + return this.isMultiuser; + } + + private void setMultiuser(boolean b) { + this.isMultiuser = b; + this.setWorldServerURL(this.desiredWorldServerURL); + } + + public World setWorldServerURL(URL s) { + this.desiredWorldServerURL = s; + String i = s.getInternal(); + if (i.startsWith("worldserver://www.3dcd.com") && NetUpdate.overrideWorldServer != null) { + i = i.substring(26); + if (i.startsWith(":") && NetUpdate.overrideWorldServer.indexOf(58, 13) >= 0) { + int j = 1; + + while (j < i.length() && Character.isDigit(i.charAt(j))) { + j++; + } + + i = i.substring(j); + } + + s = URL.make(NetUpdate.overrideWorldServer + i); + } + + this.loadErr = null; + Console.load(this.isMultiuser ? s : null, this); + return this; + } + + public static Enumeration<World> getWorlds() { + return worldList.elements(); + } +} diff --git a/NET/worlds/scape/WorldRedirector.java b/NET/worlds/scape/WorldRedirector.java new file mode 100644 index 0000000..ca6cf72 --- /dev/null +++ b/NET/worlds/scape/WorldRedirector.java @@ -0,0 +1,79 @@ +package NET.worlds.scape; + +import NET.worlds.network.URL; +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.net.MalformedURLException; +import java.util.Hashtable; + +public class WorldRedirector { + private Hashtable _ht = new Hashtable(); + + public WorldRedirector() { + } + + public WorldRedirector(URL mappingfile) { + try { + BufferedReader in = new BufferedReader(new FileReader(mappingfile.unalias())); + this.addFile(in); + } catch (IOException var3) { + System.out.println("Reading " + mappingfile + " got " + var3); + } + } + + void addFile(BufferedReader in) throws IOException { + String line; + while ((line = in.readLine()) != null) { + this.addLine(line); + } + } + + void addLine(String line) { + if (!line.startsWith("#")) { + int split = line.indexOf("=>"); + if (split > 0) { + String key = line.substring(0, split); + String value = line.substring(split + 2); + this._ht.put(key, value); + } + } + } + + public URL get(URL orig) { + String prefix = orig.toString(); + String suffix = ""; + + while (true) { + Object res = this._ht.get(prefix); + if (res != null) { + try { + URL result; + if (suffix == "") { + result = new URL((String)res); + } else { + result = new URL((String)res + "/" + suffix); + } + + System.out.println("Redirecting " + orig + " => " + result); + return result; + } catch (MalformedURLException var7) { + System.out.println("Failed: " + var7); + } + } + + int split = prefix.lastIndexOf(47); + if (split == -1) { + return orig; + } + + if (suffix == "") { + suffix = prefix.substring(split + 1); + } else { + suffix = prefix.substring(split + 1) + "/" + suffix; + } + + prefix = prefix.substring(0, split); + } + } +} diff --git a/NET/worlds/scape/WorldScript.java b/NET/worlds/scape/WorldScript.java new file mode 100644 index 0000000..f754282 --- /dev/null +++ b/NET/worlds/scape/WorldScript.java @@ -0,0 +1,47 @@ +package NET.worlds.scape; + +import NET.worlds.console.DialogReceiver; +import java.util.Vector; + +public abstract class WorldScript implements DialogReceiver, AnimatedActionCallback { + public static final int CURRENT_SCRIPT_VERSION = 15; + protected static WorldScriptToolkit toolkit = WorldScriptToolkit.getInstance(); + + public int getMinScriptVersion() { + return 15; + } + + public abstract void roomEnter(String var1); + + public abstract void roomExit(String var1); + + public abstract void worldEnter(); + + public abstract void worldExit(); + + public abstract void onEachFrame(); + + @Override + public void dialogDone(Object who, boolean confirmed) { + } + + public void onTriggerAction(String message) { + } + + public Vector onShapeClick(Object shape, String shapeName) { + return null; + } + + @Override + public void motionComplete(int completionCode) { + } + + public void onMenuClick(String action, Object source) { + } + + public void objectVisibilityNotification(Object obj, boolean visible) { + } + + public void onConversation(String who, String text) { + } +} diff --git a/NET/worlds/scape/WorldScriptLoader.java b/NET/worlds/scape/WorldScriptLoader.java new file mode 100644 index 0000000..f209e1d --- /dev/null +++ b/NET/worlds/scape/WorldScriptLoader.java @@ -0,0 +1,109 @@ +package NET.worlds.scape; + +import NET.worlds.network.Cache; +import NET.worlds.network.CacheFile; +import NET.worlds.network.NetUpdate; +import NET.worlds.network.URL; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.util.Hashtable; + +class WorldScriptLoader extends ClassLoader { + Hashtable cache = new Hashtable(); + String lastWorldName; + + private byte[] loadClassData(String name) { + String prefix = "NET.worlds.scape."; + if (name.startsWith(prefix)) { + name = name.substring(prefix.length()); + } + + int nameIdx = name.indexOf("WorldScript"); + if (nameIdx == -1) { + nameIdx = 0; + } else { + nameIdx += new String("WorldScript").length(); + } + + int extIdx = name.indexOf(".class"); + String worldName; + if (nameIdx == 0 && this.lastWorldName != null) { + worldName = this.lastWorldName; + if (!name.endsWith(".class")) { + name = name + ".class"; + } + } else if (extIdx != -1) { + worldName = name.substring(nameIdx, extIdx); + } else { + worldName = name.substring(nameIdx); + name = name + ".class"; + } + + URL scriptURL = URL.make(NetUpdate.getUpgradeServerURL() + worldName + "/" + name); + CacheFile f = Cache.getFile(scriptURL, true); + f.waitUntilLoaded(); + if (f.error()) { + return null; + } else { + this.lastWorldName = worldName; + String fileName = f.getLocalName(); + + try { + File file = new File(fileName); + FileInputStream fis = new FileInputStream(file); + byte[] buffer = new byte[1024]; + ByteArrayOutputStream os = new ByteArrayOutputStream(); + + while (true) { + try { + int bytesRead = fis.read(buffer); + if (bytesRead == -1) { + break; + } + + os.write(buffer, 0, bytesRead); + } catch (Exception var14) { + break; + } + } + + return os.toByteArray(); + } catch (Exception var15) { + return null; + } + } + } + + @Override + public synchronized Class loadClass(String name, boolean resolve) { + Class c = (Class)this.cache.get(name); + if (c == null) { + byte[] data = (byte[])null; + if (!name.startsWith("java.")) { + data = this.loadClassData(name); + } + + if (data == null) { + try { + return this.findSystemClass(name); + } catch (Error var6) { + System.out.println("Could not load script " + name + " " + var6); + return null; + } catch (Exception var7) { + System.out.println("Could not load script " + name + " " + var7); + return null; + } + } + + c = this.defineClass(data, 0, data.length); + this.cache.put(name, c); + } + + if (resolve) { + this.resolveClass(c); + } + + return c; + } +} diff --git a/NET/worlds/scape/WorldScriptManager.java b/NET/worlds/scape/WorldScriptManager.java new file mode 100644 index 0000000..b38e832 --- /dev/null +++ b/NET/worlds/scape/WorldScriptManager.java @@ -0,0 +1,164 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.DefaultConsole; +import NET.worlds.console.Main; +import NET.worlds.console.MainCallback; +import NET.worlds.console.MainTerminalCallback; +import NET.worlds.console.RenderCanvas; +import java.awt.PopupMenu; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.Enumeration; +import java.util.Vector; + +public class WorldScriptManager implements ActionListener, MainCallback, MainTerminalCallback { + private static WorldScriptManager instance = new WorldScriptManager(); + private static WorldScriptLoader loader = new WorldScriptLoader(); + private WorldScript currentScript = null; + private String lastRoom; + + public static WorldScriptManager getInstance() { + return instance; + } + + private WorldScriptManager() { + Main.register(this); + } + + @Override + public void terminalCallback() { + if (this.currentScript != null) { + this.currentScript.worldExit(); + } + + this.currentScript = null; + Main.unregister(this); + } + + public void worldEntered(String worldName) { + if (this.currentScript != null) { + this.currentScript.worldExit(); + } + + this.currentScript = null; + if (worldName != null) { + worldName = worldName.replace(' ', '_'); + worldName = worldName.replace('-', '_'); + worldName = worldName.replace('.', '_'); + worldName = worldName.replace('/', '_'); + worldName = worldName.replace('\\', '_'); + + try { + this.currentScript = (WorldScript)loader.loadClass("WorldScript" + worldName + ".class", true).newInstance(); + } catch (Exception var3) { + System.out.println("Exception constructing world script: " + var3); + } catch (Error var4) { + System.out.println("Error constructing world script: " + var4); + } + + if (this.currentScript != null) { + if (this.currentScript.getMinScriptVersion() > 15) { + System.out + .println("Script requires newer client version. script is ver. " + this.currentScript.getMinScriptVersion() + " and client has ver. " + 15); + this.currentScript = null; + } else { + this.currentScript.worldEnter(); + } + } + } + } + + @Override + public void mainCallback() { + if (this.currentScript != null) { + this.currentScript.onEachFrame(); + } + } + + public void onPrerender(WObject obj, Camera cam) { + if (this.currentScript != null) { + Console c = Console.getActive(); + if (c == null) { + return; + } + + if (!(c instanceof DefaultConsole)) { + return; + } + + DefaultConsole dc = (DefaultConsole)c; + RenderCanvas rc = dc.getRender(); + if (rc == null) { + return; + } + + Camera renderCam = rc.getCamera(); + if (cam != renderCam) { + return; + } + + Point3Temp p = obj.inCamSpace(cam); + boolean v = p != null && p.z > 1.0F && p.x < p.z && -p.x < p.z; + this.currentScript.objectVisibilityNotification(obj, v); + } + } + + public void action(String message) { + if (this.currentScript != null) { + this.currentScript.onTriggerAction(message); + } + } + + public PopupMenu shapeClicked(Shape shape) { + if (this.currentScript != null) { + SuperRoot ultimateOwner = shape; + + while (ultimateOwner.getOwner() != null) { + ultimateOwner = ultimateOwner.getOwner(); + if (ultimateOwner instanceof PosableShape) { + shape = (Shape)ultimateOwner; + break; + } + } + + Vector v = this.currentScript.onShapeClick(shape, shape.getName()); + if (v != null) { + PopupMenu m = new PopupMenu(); + Enumeration e = v.elements(); + + while (e.hasMoreElements()) { + m.add((String)e.nextElement()); + } + + return m; + } + } + + return null; + } + + @Override + public void actionPerformed(ActionEvent e) { + if (this.currentScript != null) { + this.currentScript.onMenuClick(e.getActionCommand(), e.getSource()); + } + } + + public void roomEntered(String roomName) { + if (this.currentScript != null) { + if (this.lastRoom != null) { + this.currentScript.roomExit(this.lastRoom); + } + + this.currentScript.roomEnter(roomName); + this.lastRoom = new String(roomName); + } + } + + public void onConversation(String who, String what) { + if (this.currentScript != null) { + this.currentScript.onConversation(who, what); + } + } +} diff --git a/NET/worlds/scape/WorldScriptToolkit.java b/NET/worlds/scape/WorldScriptToolkit.java new file mode 100644 index 0000000..4f52d21 --- /dev/null +++ b/NET/worlds/scape/WorldScriptToolkit.java @@ -0,0 +1,100 @@ +package NET.worlds.scape; + +public abstract class WorldScriptToolkit { + public static final int videoWallNotFound = -1; + public static final int videoUnitialized = 0; + public static final int videoStopped = 1; + public static final int videoPaused = 2; + public static final int videoPlaying = 3; + private static WorldScriptToolkit instance = new WorldScriptToolkitImp(); + + public abstract int getTime(); + + public abstract void teleport(String var1, boolean var2); + + public abstract float getPilotX(); + + public abstract float getPilotY(); + + public abstract float getPilotYaw(); + + public abstract void walkTo(float var1, float var2, float var3, float var4); + + public abstract void walkTo(float var1, float var2, float var3); + + public abstract void walkTo(WorldScript var1, float var2, float var3, float var4, float var5); + + public abstract float getWalkFriction(); + + public abstract void setWalkFriction(float var1); + + public abstract void showWebPage(String var1); + + public abstract void showWebPage(String var1, int var2, int var3); + + public abstract void showAdBanner(String var1, int var2, int var3); + + public abstract void showExternalWebPage(String var1); + + public abstract Object playSound(String var1, int var2); + + public abstract void stopSound(Object var1); + + public abstract boolean serviceSound(Object var1); + + public abstract String expandURLMacros(String var1); + + public abstract int getIniInt(String var1, int var2); + + public abstract String getIniString(String var1, String var2); + + public abstract void setIniInt(String var1, int var2); + + public abstract void setIniString(String var1, String var2); + + public abstract int getClientVersion(); + + public abstract void messageBox(String var1, String var2); + + public abstract Object yesNoDialog(String var1, String var2, String var3, String var4, WorldScript var5); + + public abstract void printToChat(String var1); + + public abstract Object findObjectInRoom(String var1); + + public abstract void walkObjectTo(WorldScript var1, Object var2, float var3, float var4, float var5, float var6); + + public abstract void moveObjectTo(Object var1, float var2, float var3, float var4); + + public abstract void moveObjectTo(Object var1, float var2, float var3, float var4, float var5); + + public abstract boolean animateBot(Object var1, String var2); + + public abstract boolean watchVisibility(Object var1); + + public abstract boolean setShapeURL(Object var1, String var2); + + public abstract int getVideoWallStatus(Object var1); + + public abstract boolean playVideo(Object var1, int var2); + + public abstract boolean stopVideo(Object var1); + + public abstract boolean setVideoURL(Object var1, String var2, int var3, int var4); + + public abstract boolean setWebWallURL(Object var1, String var2); + + public abstract boolean setWebWallURL(Object var1, String var2, String var3); + + public abstract void setAdCube(boolean var1, boolean var2, String var3, String var4); + + public abstract boolean isLoggedIn(); + + public abstract int getConcurrentDownloads(); + + public abstract boolean getIsVIP(); + + public static WorldScriptToolkit getInstance() { + return instance; + } +} diff --git a/NET/worlds/scape/WorldScriptToolkitImp.java b/NET/worlds/scape/WorldScriptToolkitImp.java new file mode 100644 index 0000000..180f0ea --- /dev/null +++ b/NET/worlds/scape/WorldScriptToolkitImp.java @@ -0,0 +1,429 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.console.DefaultConsole; +import NET.worlds.console.NoWebControlException; +import NET.worlds.console.OkCancelDialog; +import NET.worlds.console.WebControl; +import NET.worlds.console.WebControlImp; +import NET.worlds.core.IniFile; +import NET.worlds.core.Std; +import NET.worlds.network.CacheEntry; +import NET.worlds.network.Galaxy; +import NET.worlds.network.URL; + +class WorldScriptToolkitImp extends WorldScriptToolkit { + @Override + public int getTime() { + return Std.getSynchronizedTime(); + } + + @Override + public void teleport(String destination, boolean showDlg) { + TeleportAction.teleport(destination, null, false, showDlg); + } + + @Override + public float getPilotX() { + Pilot p = Pilot.getActive(); + return p != null ? p.getX() : 0.0F; + } + + @Override + public float getPilotY() { + Pilot p = Pilot.getActive(); + return p != null ? p.getY() : 0.0F; + } + + @Override + public float getPilotYaw() { + Pilot p = Pilot.getActive(); + return p != null ? 360.0F - p.getYaw() : 0.0F; + } + + private SmoothDriver getSmoothDriver() { + Pilot p = Pilot.getActive(); + if (p != null && p instanceof HoloPilot) { + HoloPilot hp = (HoloPilot)p; + return hp.getSmoothDriver(); + } else { + return null; + } + } + + @Override + public float getWalkFriction() { + SmoothDriver sd = this.getSmoothDriver(); + return sd != null ? sd.getVelocityDamping() : 0.0F; + } + + @Override + public void setWalkFriction(float friction) { + SmoothDriver sd = this.getSmoothDriver(); + if (sd != null) { + sd.setVelocityDamping(friction); + } + } + + @Override + public void walkTo(float x, float y, float yaw, float velocity) { + Pilot p = Pilot.getActive(); + if (p != null && p instanceof HoloPilot) { + HoloPilot hp = (HoloPilot)p; + hp.walkTo(new Point2(x, y), yaw, velocity); + } + } + + @Override + public void walkTo(float x, float y, float yaw) { + Pilot p = Pilot.getActive(); + if (p != null && p instanceof HoloPilot) { + HoloPilot hp = (HoloPilot)p; + hp.walkTo(new Point2(x, y), yaw); + } + } + + @Override + public void walkTo(WorldScript script, float x, float y, float yaw, float velocity) { + Pilot p = Pilot.getActive(); + if (p != null && p instanceof HoloPilot) { + HoloPilot hp = (HoloPilot)p; + hp.walkTo(new Point2(x, y), yaw, velocity); + hp.addCallback(script); + } + } + + @Override + public void showWebPage(String url) { + this.showWebPage(url, 100, 100); + } + + @Override + public void showWebPage(String url, int percentW, int percentH) { + Console c = Console.getActive(); + if (c != null && c instanceof DefaultConsole) { + DefaultConsole dc = (DefaultConsole)c; + + try { + WebControl wc = new WebControl(dc.getRender(), percentW, percentH, true, false, false); + wc.activate(); + wc.setURL(url); + } catch (NoWebControlException var7) { + new SendURLAction(url).doIt(); + } + } + } + + @Override + public void showExternalWebPage(String url) { + new SendURLAction(url).doIt(); + } + + @Override + public void showAdBanner(String url, int width, int height) { + Pilot p = Pilot.getActive(); + if (p != null) { + World w = p.getWorld(); + if (w != null) { + w.setHasAdBanner(true); + w.setBannerURL(url); + w.setBannerWidth(width); + w.setBannerHeight(height); + w.setupAdBanner(); + } + } + } + + @Override + public Object playSound(String soundFile, int loop) { + Sound owner = new Sound(URL.make(soundFile)); + SoundPlayer autoSound = null; + if (soundFile.toLowerCase().endsWith(".wav")) { + autoSound = new WavSoundPlayer(owner); + } else { + autoSound = new WMPSoundPlayer(owner); + } + + autoSound.start(loop); + return autoSound; + } + + @Override + public boolean serviceSound(Object soundPlayer) { + if (!(soundPlayer instanceof SoundPlayer)) { + System.out.println("Error - invalid handle passed to serviceSound"); + return false; + } else { + SoundPlayer sp = (SoundPlayer)soundPlayer; + return sp.getState() == 0; + } + } + + @Override + public void stopSound(Object soundPlayer) { + if (!(soundPlayer instanceof SoundPlayer)) { + System.out.println("Error - invalid handle passed to stopSound"); + } else { + SoundPlayer autoSound = (SoundPlayer)soundPlayer; + autoSound.stop(); + } + } + + @Override + public String expandURLMacros(String urlIn) { + return WebControlImp.processURL(urlIn); + } + + @Override + public int getIniInt(String entry, int defaultVal) { + return IniFile.gamma().getIniInt(entry, defaultVal); + } + + @Override + public String getIniString(String entry, String defaultVal) { + return IniFile.gamma().getIniString(entry, defaultVal); + } + + @Override + public void setIniInt(String entry, int val) { + IniFile.gamma().setIniInt(entry, val); + } + + @Override + public void setIniString(String entry, String val) { + IniFile.gamma().setIniString(entry, val); + } + + @Override + public int getClientVersion() { + return Std.getVersion(); + } + + @Override + public void messageBox(String text, String caption) { + Console c = Console.getActive(); + if (c != null) { + new OkCancelDialog(Console.getFrame(), null, caption, null, Console.message("OK"), text, true); + } + } + + @Override + public Object yesNoDialog(String text, String caption, String yes, String no, WorldScript callback) { + Console c = Console.getActive(); + return c == null ? null : new OkCancelDialog(Console.getFrame(), callback, caption, no, yes, text); + } + + @Override + public void printToChat(String text) { + Console c = Console.getActive(); + if (c != null) { + Console.println(text); + } + } + + @Override + public boolean watchVisibility(Object obj) { + if (obj == null) { + return false; + } else if (!(obj instanceof WObject)) { + return false; + } else { + WObject wobj = (WObject)obj; + Room r = wobj.getRoom(); + if (r == null) { + return false; + } else { + r.addPrerenderHandler(wobj); + return true; + } + } + } + + @Override + public int getVideoWallStatus(Object video) { + if (video != null && video instanceof VideoWall) { + VideoWall vw = (VideoWall)video; + return vw.getState(); + } else { + return -1; + } + } + + @Override + public boolean playVideo(Object video, int repeat) { + if (video != null && video instanceof VideoWall) { + VideoWall vw = (VideoWall)video; + VideoSurface vs = vw.getVideoSurface(); + if (vs == null) { + return false; + } else { + vs.play(repeat); + return true; + } + } else { + return false; + } + } + + @Override + public boolean stopVideo(Object video) { + if (video != null && video instanceof VideoWall) { + VideoWall vw = (VideoWall)video; + VideoSurface vs = vw.getVideoSurface(); + if (vs == null) { + return false; + } else { + vs.stop(); + return true; + } + } else { + return false; + } + } + + @Override + public boolean setVideoURL(Object video, String url, int width, int height) { + if (video != null && video instanceof VideoWall) { + VideoWall vw = (VideoWall)video; + vw.changeURL(url, width, height); + return true; + } else { + return false; + } + } + + @Override + public boolean setWebWallURL(Object webWall, String url) { + if (webWall != null && webWall instanceof WebPageWall) { + WebPageWall wpw = (WebPageWall)webWall; + WebControlImp wci = wpw.getWebControlImp(); + return wci != null && url != null ? wci.setURL(url) : false; + } else { + return false; + } + } + + @Override + public boolean setWebWallURL(Object webWall, String url, String postData) { + if (webWall != null && webWall instanceof WebPageWall) { + WebPageWall wpw = (WebPageWall)webWall; + WebControlImp wci = wpw.getWebControlImp(); + return wci != null && url != null ? wci.setURL(url, postData) : false; + } else { + return false; + } + } + + @Override + public boolean animateBot(Object obj, String action) { + if (!(obj instanceof PosableShape)) { + return false; + } else { + PosableShape ps = (PosableShape)obj; + ps.animate(action); + return true; + } + } + + @Override + public boolean setShapeURL(Object obj, String url) { + if (!(obj instanceof Shape)) { + return false; + } else { + Shape s = (Shape)obj; + s.setURL(URL.make(url)); + return true; + } + } + + @Override + public Object findObjectInRoom(String objectName) { + Room r = Pilot.getActive().getRoom(); + if (r != null) { + DeepEnumeration e = new DeepEnumeration(); + r.getChildren(e); + + while (e.hasMoreElements()) { + SuperRoot wobj = (SuperRoot)e.nextElement(); + if (wobj.getName().equals(objectName)) { + return wobj; + } + } + } + + return null; + } + + @Override + public void walkObjectTo(WorldScript script, Object obj, float x, float y, float yaw, float vel) { + if (obj instanceof WObject) { + HandsOffDriver hod = new HandsOffDriver(); + hod.setDestPos(new Point2(x, y), yaw, vel); + hod.setTarget((Transform)obj); + hod.addCallback(script); + ((WObject)obj).addHandler(hod); + } + } + + @Override + public void moveObjectTo(Object obj, float x, float y, float yaw) { + if (obj instanceof Transform) { + Transform t = (Transform)obj; + t.moveTo(x, y, t.getZ()).yaw(yaw); + } + } + + @Override + public void moveObjectTo(Object obj, float x, float y, float z, float yaw) { + if (obj instanceof Transform) { + Transform t = (Transform)obj; + t.moveTo(x, y, z).yaw(yaw); + } + } + + public void moveObjectTo(Object obj, float x, float y, float z, float yaw, float sc) { + if (obj instanceof Transform) { + Transform t = (Transform)obj; + t.moveTo(x, y, z).yaw(yaw); + t.scale(sc); + } + } + + @Override + public boolean isLoggedIn() { + Console c = Console.getActive(); + if (c != null) { + Galaxy g = c.getGalaxy(); + if (g != null) { + return g.getOnline(); + } + } + + return false; + } + + @Override + public int getConcurrentDownloads() { + return CacheEntry.getConcurrentDownloads(); + } + + @Override + public boolean getIsVIP() { + Console c = Console.getActive(); + return c != null ? c.getVIP() : false; + } + + @Override + public void setAdCube(boolean clickable, boolean usesGIF, String baseURL, String defaultURL) { + Pilot p = Pilot.getActive(); + if (p != null) { + World w = p.getWorld(); + if (w != null) { + w.setHasClickableAdCube(clickable); + w.setAdCubeFormatIsGif(usesGIF); + w.setAdCubeBaseURL(baseURL); + w.setDefaultAdCubeURL(defaultURL); + } + } + } +} diff --git a/NET/worlds/scape/WorldValidator.java b/NET/worlds/scape/WorldValidator.java new file mode 100644 index 0000000..dbfd629 --- /dev/null +++ b/NET/worlds/scape/WorldValidator.java @@ -0,0 +1,84 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.core.IniFile; +import NET.worlds.network.Cache; +import NET.worlds.network.CacheFile; +import NET.worlds.network.NetUpdate; +import NET.worlds.network.URL; +import java.io.RandomAccessFile; +import java.util.Vector; + +public class WorldValidator { + static Vector worldList = null; + private static final boolean debug = true; + + public static boolean allow(String worldName) { + if (IniFile.gamma().getIniInt("FreeFreeFree", 1) == 1) { + return true; + } else if (NetUpdate.isInternalVersion()) { + return true; + } else { + Console c = Console.getActive(); + if (c != null && !c.getGalaxy().getOnline()) { + return true; + } else { + if (worldList == null) { + try { + initializeList(); + } catch (Exception var3) { + return true; + } + } + + if (worldList == null) { + return true; + } else { + worldName = normalize(worldName); + System.out.println("Validating " + worldName); + boolean allow = worldList.contains(worldName); + System.out.println(allow); + return allow; + } + } + } + } + + public static void initializeList() throws Exception { + String worldListFile = NetUpdate.getUpgradeServerURL() + "tables/worlds.txt"; + URL worldListURL = URL.make(worldListFile); + CacheFile cf = Cache.getFile(worldListURL, true); + cf.waitUntilLoaded(); + if (!cf.error()) { + boolean foundAtLeastOneEntry = false; + worldList = new Vector(); + RandomAccessFile f = new RandomAccessFile(cf.getLocalName(), "r"); + + while (f.getFilePointer() < f.length()) { + String line = f.readLine(); + if (line.indexOf(".world") != -1) { + line = normalize(line); + foundAtLeastOneEntry = true; + System.out.println("Adding world " + line); + worldList.addElement(line); + } + } + + f.close(); + if (!foundAtLeastOneEntry) { + throw new Exception(); + } + } else { + throw new Exception(); + } + } + + private static String normalize(String worldName) { + String out = URL.make(worldName).getAbsolute(); + if (out.startsWith("home:/")) { + out = "home:" + out.substring(6); + } + + return out.toLowerCase().trim(); + } +} diff --git a/NET/worlds/scape/WrRamp.java b/NET/worlds/scape/WrRamp.java new file mode 100644 index 0000000..6e72628 --- /dev/null +++ b/NET/worlds/scape/WrRamp.java @@ -0,0 +1,207 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class WrRamp extends Room { + private static final float epsilon = 0.01F; + public Portal portal1; + public Portal portal2; + private float dzByLength; + + public WrRamp( + World world, + String name, + float length, + float width, + float pWidth, + float pHeight, + float dz, + float lintelZ, + float floorTileX, + float floorTileY, + float ceilTileX, + float ceilTileY, + float leftTileX, + float leftTileY, + float rightTileX, + float rightTileY, + Material floor, + Material left, + Material right, + Material doorpost, + Material lintel, + Material ceiling + ) { + super(world, name); + if (pWidth > width) { + System.out.println("WrRamp: portal too wide; reducing."); + pWidth = width; + } + + if (length < 0.0F) { + System.out.println("WrRamp: length must be positive; inverting."); + length = -length; + } + + if (width < 0.0F) { + System.out.println("WrRamp: width must be positive; inverting."); + width = -width; + } + + if (pWidth < 0.0F) { + System.out.println("WrRamp: portal width must be positive; inverting."); + pWidth = -pWidth; + } + + if (pHeight < 0.0F) { + System.out.println("WrRamp: portal height must be positive; inverting."); + pHeight = -pHeight; + } + + if (lintelZ < 0.0F) { + System.out.println("WrRamp: lintel height must be positive; ignoring."); + lintelZ = 0.0F; + } + + if (floorTileX < 10.0F) { + System.out.println("WrRamp: floor tile width must be at least 10; fixing."); + floorTileX = 10.0F; + } + + if (floorTileY < 10.0F) { + System.out.println("WrRamp: floor tile length must be at least 10; fixing."); + floorTileY = 10.0F; + } + + if (ceilTileX < 10.0F) { + System.out.println("WrRamp: ceiling tile width must be at least 10; fixing."); + ceilTileX = 10.0F; + } + + if (ceilTileY < 10.0F) { + System.out.println("WrRamp: ceiling tile length must be at least 10; fixing."); + ceilTileY = 10.0F; + } + + if (leftTileX < 10.0F) { + System.out.println("WrRamp: lWall tile width must be at least 10; fixing."); + leftTileX = 10.0F; + } + + if (leftTileY < 10.0F) { + System.out.println("WrRamp: lWall tile length must be at least 10; fixing."); + leftTileY = 10.0F; + } + + if (rightTileX < 10.0F) { + System.out.println("WrRamp: rWall tile width must be at least 10; fixing."); + rightTileX = 10.0F; + } + + if (rightTileY < 10.0F) { + System.out.println("WrRamp: rWall tile length must be at least 10; fixing."); + rightTileY = 10.0F; + } + + RoomEnvironment env = this.getEnvironment(); + float postX = (width - pWidth) / 2.0F; + this.dzByLength = dz / length; + float nearTop = pHeight + lintelZ; + float farTop = dz + nearTop; + this.portal1 = new Portal(width - postX, 0.0F, 0.0F, postX, 0.0F, pHeight); + this.portal2 = new Portal(postX, length, dz, width - postX, length, dz + pHeight); + env.add(this.portal1); + env.add(this.portal2); + float[] floorVerts = new float[]{ + 0.0F, + 0.0F, + 0.0F, + 0.0F, + 0.0F, + width, + 0.0F, + 0.0F, + width / floorTileX, + 0.0F, + width, + length, + dz, + width / floorTileX, + length / floorTileY, + 0.0F, + length, + dz, + 0.0F, + length / floorTileY + }; + env.add(new Polygon(floorVerts, floor)); + if (lintelZ > 0.0F) { + env.add(new Rect(width, 0.0F, pHeight, 0.0F, 0.0F, nearTop, lintel)); + env.add(new Rect(0.0F, length, dz + pHeight, width, length, farTop, lintel)); + } + + if (width > pWidth) { + env.add(new Rect(width, 0.0F, 0.0F, width - postX, 0.0F, pHeight, doorpost)); + env.add(new Rect(postX, 0.0F, 0.0F, 0.0F, 0.0F, pHeight, doorpost)); + env.add(new Rect(0.0F, length, dz, postX, length, dz + pHeight, doorpost)); + env.add(new Rect(width - postX, length, dz, width, length, dz + pHeight, doorpost)); + } + + float[] ceilVerts = new float[]{ + 0.0F, + 0.0F, + nearTop, + 0.0F, + 0.0F, + 0.0F, + length, + farTop, + 0.0F, + length / ceilTileY, + width, + length, + farTop, + width / ceilTileX, + length / ceilTileY, + width, + 0.0F, + nearTop, + width / ceilTileX, + 0.0F + }; + env.add(new Polygon(ceilVerts, ceiling)); + float bottom = Math.min(dz, 0.0F); + float top = Math.max(nearTop, farTop); + env.add(new Rect(-0.01F, 0.0F, bottom, -0.01F, length, top, left)); + env.add(new Rect(width + 0.01F, length, bottom, width + 0.01F, 0.0F, top, right)); + } + + public WrRamp() { + } + + @Override + public float floorHeight(float x, float y, float z) { + return y * this.dzByLength; + } + + @Override + public Point3 surfaceNormal(float x, float y, float z) { + Point3 A = new Point3(1.0F, 0.0F, 0.0F); + Point3Temp B = Point3Temp.make(0.0F, 1.0F, this.dzByLength); + A.cross(B); + A.normalize(); + return A; + } + + @Override + public void saveState(Saver s) throws IOException { + super.saveState(s); + s.saveFloat(this.dzByLength); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + super.restoreState(r); + this.dzByLength = r.restoreFloat(); + } +} diff --git a/NET/worlds/scape/WrRectPatch.java b/NET/worlds/scape/WrRectPatch.java new file mode 100644 index 0000000..7efd67c --- /dev/null +++ b/NET/worlds/scape/WrRectPatch.java @@ -0,0 +1,19 @@ +package NET.worlds.scape; + +import java.io.IOException; + +class WrRectPatch extends RectPatch { + private static Object classCookie = new Object(); + + @Override + public void saveState(Saver s) throws IOException { + assert false; + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + RectPatch p = new RectPatch(); + r.replace(this, p); + p.restoreStateRectPatchHelper(r, classCookie); + } +} diff --git a/NET/worlds/scape/WrStaircase.java b/NET/worlds/scape/WrStaircase.java new file mode 100644 index 0000000..78ee4bc --- /dev/null +++ b/NET/worlds/scape/WrStaircase.java @@ -0,0 +1,137 @@ +package NET.worlds.scape; + +import java.io.IOException; + +public class WrStaircase extends Room { + private static final float epsilon = 0.01F; + public Portal portal1; + public Portal portal2; + private float dzByLength; + + public WrStaircase( + World world, + String name, + float length, + float width, + float pWidth, + float pHeight, + float dz, + float lintelZ, + int numSteps, + Material riser, + Material tread, + Material left, + Material right, + Material doorpost, + Material lintel, + Material ceiling + ) { + super(world, name); + if (pWidth > width) { + System.out.println("WrStaircase: portal too wide; reducing."); + pWidth = width; + } + + if (length < 0.0F) { + System.out.println("WrStaircase: length must be positive; inverting."); + length = -length; + } + + if (width < 0.0F) { + System.out.println("WrStaircase: width must be positive; inverting."); + width = -width; + } + + if (pWidth < 0.0F) { + System.out.println("WrStaircase: portal width must be positive; inverting."); + pWidth = -pWidth; + } + + if (pHeight < 0.0F) { + System.out.println("WrStaircase: portal height must be positive; inverting."); + pHeight = -pHeight; + } + + if (lintelZ < 0.0F) { + System.out.println("WrStaircase: lintel height must be positive; ignoring."); + lintelZ = 0.0F; + } + + if (numSteps < 2) { + System.out.println("WrStaircase: must have at least 2 steps."); + numSteps = 2; + } + + RoomEnvironment env = this.getEnvironment(); + float postX = (width - pWidth) / 2.0F; + float bottom = Math.min(dz, 0.0F); + float ceilingHeight = Math.max(dz, 0.0F) + pHeight + lintelZ; + this.dzByLength = dz / length; + this.portal1 = new Portal(width - postX, 0.0F, 0.0F, postX, 0.0F, pHeight); + this.portal2 = new Portal(postX, length, dz, width - postX, length, dz + pHeight); + env.add(this.portal1); + env.add(this.portal2); + float stepWidth = length / numSteps; + float stepHeight = dz / numSteps; + + for (int i = 1; i <= numSteps; i++) { + Rect w = new Rect(0.0F, i * stepWidth, (i - 1) * stepHeight, width, i * stepWidth, i * stepHeight - 0.01F, riser); + w.setTileSize(stepHeight, stepHeight); + env.add(w); + } + + for (int i = 0; i < numSteps; i++) { + Rect w = Rect.floor(0.0F, i * stepWidth, i * stepHeight, width, (i + 1) * stepWidth - 0.01F, tread); + w.setTileSize(Math.abs(stepWidth), Math.abs(stepWidth)); + env.add(w); + } + + if (ceilingHeight > pHeight) { + env.add(new Rect(width, 0.0F, pHeight, 0.0F, 0.0F, ceilingHeight - 0.01F, lintel)); + } + + if (ceilingHeight > dz + pHeight) { + env.add(new Rect(0.0F, length, dz + pHeight, width, length, ceilingHeight - 0.01F, lintel)); + } + + if (width > pWidth) { + env.add(new Rect(width, 0.0F, 0.0F, width - postX, 0.0F, pHeight, doorpost)); + env.add(new Rect(postX, 0.0F, 0.0F, 0.0F, 0.0F, pHeight, doorpost)); + env.add(new Rect(0.0F, length, dz, postX, length, dz + pHeight, doorpost)); + env.add(new Rect(width - postX, length, dz, width, length, dz + pHeight, doorpost)); + } + + env.add(Rect.ceiling(0.0F, 0.0F, ceilingHeight, width, length, ceiling)); + env.add(new Rect(-0.01F, 0.0F, bottom, -0.01F, length, ceilingHeight, left)); + env.add(new Rect(width + 0.01F, length, bottom, width + 0.01F, 0.0F, ceilingHeight, right)); + } + + public WrStaircase() { + } + + @Override + public float floorHeight(float x, float y, float z) { + return y * this.dzByLength; + } + + @Override + public Point3 surfaceNormal(float x, float y, float z) { + Point3 A = new Point3(1.0F, 0.0F, 0.0F); + Point3Temp B = Point3Temp.make(0.0F, 1.0F, this.dzByLength); + A.cross(B); + A.normalize(); + return A; + } + + @Override + public void saveState(Saver s) throws IOException { + super.saveState(s); + s.saveFloat(this.dzByLength); + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + super.restoreState(r); + this.dzByLength = r.restoreFloat(); + } +} diff --git a/NET/worlds/scape/WrVisiRectPatch.java b/NET/worlds/scape/WrVisiRectPatch.java new file mode 100644 index 0000000..b8e3db1 --- /dev/null +++ b/NET/worlds/scape/WrVisiRectPatch.java @@ -0,0 +1,46 @@ +package NET.worlds.scape; + +import java.io.IOException; + +class WrVisiRectPatch extends RectPatch { + private static Object classCookie = new Object(); + + @Override + public void saveState(Saver s) throws IOException { + assert false; + } + + @Override + public void restoreState(Restorer r) throws IOException, TooNewException { + RectPatch p = new RectPatch(); + r.replace(this, p); + switch (r.restoreVersion(classCookie)) { + case 0: + super.restoreState(r); + this.xTile = r.restoreFloat(); + this.xTileOffset = r.restoreFloat(); + this.yTile = r.restoreFloat(); + this.yTileOffset = r.restoreFloat(); + this.mat = (Material)r.restoreMaybeNull(); + this.t[0] = (Polygon)r.restoreMaybeNull(); + this.t[1] = (Polygon)r.restoreMaybeNull(); + this.t[2] = (Polygon)r.restoreMaybeNull(); + this.t[3] = (Polygon)r.restoreMaybeNull(); + p.xDim = this.xDim; + p.yDim = this.yDim; + p.z[0] = this.z[0]; + p.z[1] = this.z[1]; + p.z[2] = this.z[2]; + p.z[3] = this.z[3]; + p.xTile = this.xTile; + p.xTileOffset = this.xTileOffset; + p.yTile = this.yTile; + p.yTileOffset = this.yTileOffset; + p.mat = this.mat; + p.setVisible(true); + return; + default: + throw new TooNewException(); + } + } +} diff --git a/NET/worlds/scape/YawWidget.java b/NET/worlds/scape/YawWidget.java new file mode 100644 index 0000000..489c88b --- /dev/null +++ b/NET/worlds/scape/YawWidget.java @@ -0,0 +1,21 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; + +class YawWidget extends WidgetButton { + public YawWidget(ToolBar toolbar) { + super(toolbar, "yaw.gif", Console.message("Yaw")); + } + + @Override + public String drag(boolean initialDrag, float deltax, float deltay) { + if (Math.abs(deltay) > Math.abs(deltax)) { + deltax = 0.0F; + } + + Transform t = Transform.make(); + this.applyWorldTransform(initialDrag, t.spin(this.getWorldAxis(0, 0, 1), deltax)); + t.recycle(); + return "Yaw"; + } +} diff --git a/NET/worlds/scape/sendURL.java b/NET/worlds/scape/sendURL.java new file mode 100644 index 0000000..4f512e5 --- /dev/null +++ b/NET/worlds/scape/sendURL.java @@ -0,0 +1,156 @@ +package NET.worlds.scape; + +import NET.worlds.console.Console; +import NET.worlds.network.URL; +import java.io.IOException; +import java.text.MessageFormat; + +public class sendURL extends TriggeredSwitchableBehavior implements MouseDownHandler, BumpHandler, FrameHandler { + protected String browser; + protected String destination; + protected boolean silentURL; + protected boolean initialized = false; + + public sendURL() { + this.trigger = new String("none"); + this.externalTriggerTag = new String(""); + this.silentURL = false; + this.browser = new String("NETSCAPE"); + this.destination = new String("http://www.worlds.net"); + } + + public static native int init(String var0); + + public static native int get(String var0); + + public static native int silent_get(String var0); + + @Override + public void ExternalTrigger(Trigger source, int seqno, int eventno) { + this.sendURLStart(); + } + + public void sendURLStart() { + if (this.silentURL) { + silent_get(this.destination); + } else { + get(this.destination); + } + } + + @Override + public boolean handle(FrameEvent e) { + if (!this.initialized) { + init(this.browser); + this.initialized = true; + } + + return true; + } + + @Override + public boolean handle(MouseDownEvent e) { + if (this.enabled && this.trigger.equals("click")) { + this.sendURLStart(); + } + + return true; + } + + @Override + public boolean handle(BumpEventTemp e) { + if (this.enabled && this.trigger.equals("bump")) { + this.sendURLStart(); + } + + return true; + } + + @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 = StringPropertyEditor.make(new Property(this, index, "Trigger")); + } else if (mode == 1) { + ret = new String(this.trigger); + } else if (mode == 2) { + this.trigger = ((String)value).toString().trim(); + if (this.trigger.equals("external")) { + Trigger.TriggeredSwitchableBehaviorList[Trigger.TriggeredSwitchableBehaviorListCount] = this; + Trigger.TriggeredSwitchableBehaviorListCount++; + } + } + break; + case 1: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "External Trigger Tag")); + } else if (mode == 1) { + ret = new String(this.externalTriggerTag); + } else if (mode == 2) { + this.externalTriggerTag = ((String)value).toString().trim(); + } + break; + case 2: + if (mode == 0) { + ret = BooleanPropertyEditor.make(new Property(this, index, "Silent URL"), "No", "Yes"); + } else if (mode == 1) { + ret = new Boolean(this.silentURL); + } else if (mode == 2) { + this.silentURL = (Boolean)value; + } + break; + case 3: + if (mode == 0) { + ret = StringPropertyEditor.make(new Property(this, index, "Destination")); + } else if (mode == 1) { + ret = new String(this.destination); + } else if (mode == 2) { + this.destination = ((String)value).toString().trim(); + } + break; + default: + ret = super.properties(index, offset + 4, mode, value); + } + + return ret; + } + + @Override + public String toString() { + return super.toString() + "[enabled " + this.enabled + ", trigger " + this.trigger + ", externalTriggerTag " + this.externalTriggerTag + "]"; + } + + @Override + public void saveState(Saver s) throws IOException { + Object[] arguments = new Object[]{new String(this.getName())}; + Console.println(MessageFormat.format(Console.message("sendURL-obs"), arguments)); + s.saveString(this.trigger); + s.saveString(this.externalTriggerTag); + s.saveBoolean(this.silentURL); + s.saveString(this.destination); + } + + @Override + public void restoreState(Restorer r) throws IOException { + this.trigger = r.restoreString(); + this.externalTriggerTag = r.restoreString(); + this.silentURL = r.restoreBoolean(); + this.destination = r.restoreString(); + if (this.trigger.equals("external")) { + Object[] arguments = new Object[]{new String(this.getName())}; + Console.println(MessageFormat.format(Console.message("sendURL-obs"), arguments)); + Trigger.TriggeredSwitchableBehaviorList[Trigger.TriggeredSwitchableBehaviorListCount] = this; + Trigger.TriggeredSwitchableBehaviorListCount++; + } else { + SendURLAction sua = new SendURLAction(); + if (this.destination != null) { + sua.setDestination(URL.make(this.destination)); + } + + sua.setTrigger(this.trigger); + r.replace(this, sua); + } + } +} |