Refactored things so that the whirled.spot Location class is merely an

interface and specific games can define their own concept of a location.
Portal and SceneLocation now both have a Location instance within them.
All the whirled stuff is happy not knowing the details of the Location even
though it manages portals and other such goodies. The 'stage' stuff
does need to know, and yohoho uses the new StageLocation class
that is essentially identical to the old 'Location'.

SceneLocation previously extended Location, and there were a lot of places
where they were used somewhat interchangeably, or a SceneLocation and
a regular Location were compared. This shouldn't be done anymore and I've
left in code that should dump stack if it occurs, so that we can spot
these logic errors at runtime.


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@4140 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Ray Greenwell
2006-05-23 21:44:05 +00:00
parent 869641562d
commit 99a97622a6
12 changed files with 188 additions and 204 deletions
@@ -3,12 +3,16 @@
package com.threerings.stage.client;
import com.samskivert.util.Tuple;
import com.threerings.crowd.client.PlaceView;
import com.threerings.crowd.util.CrowdContext;
import com.threerings.whirled.data.SceneUpdate;
import com.threerings.whirled.spot.client.SpotSceneController;
import com.threerings.stage.Log;
import com.threerings.stage.data.StageLocation;
import com.threerings.stage.util.StageContext;
/**
@@ -17,6 +21,25 @@ import com.threerings.stage.util.StageContext;
*/
public class StageSceneController extends SpotSceneController
{
/**
* Called when the user clicks on a location within the scene.
*/
public void handleLocationClicked (Object source, StageLocation loc)
{
Log.warning("handleLocationClicked(" + source + ", " + loc + ")");
}
/**
* Handles a cluster clicked event.
*
* @param tuple a Tuple containing (Cluster, Point) with the Cluster
* that was clicked and the Point being the screen coords of the click.
*/
public void handleClusterClicked (Object source, Tuple tuple)
{
Log.warning("handleClusterClicked(" + source + ", " + tuple + ")");
}
// documentation inherited
protected PlaceView createPlaceView (CrowdContext ctx)
{
@@ -46,11 +46,14 @@ import com.threerings.crowd.client.PlaceView;
import com.threerings.crowd.data.PlaceObject;
import com.threerings.whirled.data.SceneUpdate;
import com.threerings.whirled.spot.data.Cluster;
import com.threerings.whirled.spot.data.Location;
import com.threerings.whirled.spot.data.Portal;
import com.threerings.whirled.spot.data.SceneLocation;
import com.threerings.stage.Log;
import com.threerings.stage.data.StageLocation;
import com.threerings.stage.data.StageMisoSceneModel;
import com.threerings.stage.data.StageScene;
import com.threerings.stage.data.StageSceneModel;
@@ -68,10 +71,6 @@ public class StageScenePanel extends MisoScenePanel
* within the scene. */
public static final String LOCATION_CLICKED = "LocationClicked";
/** An action command generated when something besides the user wants
* us to move to a location. */
public static final String LOCATION_REQUESTED = "LocationRequested";
/** An action command generated when a cluster is clicked. */
public static final String CLUSTER_CLICKED = "ClusterClicked";
@@ -163,9 +162,10 @@ public class StageScenePanel extends MisoScenePanel
_portobjs.clear();
for (Iterator iter = _scene.getPortals(); iter.hasNext(); ) {
Portal portal = (Portal) iter.next();
Point p = getScreenCoords(portal.loc.x, portal.loc.y);
int tx = MisoUtil.fullToTile(portal.loc.x);
int ty = MisoUtil.fullToTile(portal.loc.y);
StageLocation loc = (StageLocation) portal.loc;
Point p = getScreenCoords(loc.x, loc.y);
int tx = MisoUtil.fullToTile(loc.x);
int ty = MisoUtil.fullToTile(loc.y);
Point ts = MisoUtil.tileToScreen(_metrics, tx, ty, new Point());
// Log.info("Added portal " + portal +
@@ -180,7 +180,7 @@ public class StageScenePanel extends MisoScenePanel
ObjectTile tile = new PortalObjectTile(
ts.x + _metrics.tilehwid - p.x + (PORTAL_ICON_WIDTH / 2),
ts.y + _metrics.tilehei - p.y + (PORTAL_ICON_HEIGHT / 2));
tile.setImage(ots.getTileMirage(portal.loc.orient));
tile.setImage(ots.getTileMirage(loc.orient));
_portobjs.add(new SceneObject(this, info, tile) {
public boolean setHovered (boolean hovered) {
@@ -266,15 +266,14 @@ public class StageScenePanel extends MisoScenePanel
// if the hover object is a cluster, we clicked it!
if (event.getButton() == MouseEvent.BUTTON1) {
if (hobject instanceof Cluster) {
int mx = event.getX(), my = event.getY();
Object actarg = new Tuple(hobject, new Point(mx, my));
Object actarg = new Tuple(hobject, event.getPoint());
Controller.postAction(this, CLUSTER_CLICKED, actarg);
} else {
// post an action indicating that we've clicked on a location
Point lc = MisoUtil.screenToFull(
_metrics, event.getX(), event.getY(), new Point());
Controller.postAction(this, LOCATION_CLICKED,
new Location(lc.x, lc.y, (byte)0));
new StageLocation(lc.x, lc.y, (byte)0));
}
return true;
}
@@ -304,10 +303,10 @@ public class StageScenePanel extends MisoScenePanel
{
// compute a screen rectangle that contains all possible "spots"
// in this cluster
ArrayList spots = StageSceneUtil.getClusterLocs(cluster);
ArrayList<SceneLocation> spots = StageSceneUtil.getClusterLocs(cluster);
Rectangle cbounds = null;
for (int ii = 0, ll = spots.size(); ii < ll; ii++) {
Location loc = (Location)spots.get(ii);
StageLocation loc = ((StageLocation) spots.get(ii).loc);
Point sp = getScreenCoords(loc.x, loc.y);
if (cbounds == null) {
cbounds = new Rectangle(sp.x, sp.y, 0, 0);
@@ -482,7 +481,8 @@ public class StageScenePanel extends MisoScenePanel
Iterator iter = _scene.getPortals();
while (iter.hasNext()) {
Portal portal = (Portal)iter.next();
if (portal.loc.x == fullX && portal.loc.y == fullY) {
StageLocation loc = (StageLocation) portal.loc;
if (loc.x == fullX && loc.y == fullY) {
return portal;
}
}
@@ -37,6 +37,7 @@ import com.threerings.stage.client.StageSceneService;
import com.threerings.stage.data.DefaultColorUpdate;
import com.threerings.stage.data.ModifyObjectsUpdate;
import com.threerings.stage.data.StageCodes;
import com.threerings.stage.data.StageLocation;
import com.threerings.stage.data.StageMisoSceneModel;
import com.threerings.stage.data.StageOccupantInfo;
import com.threerings.stage.data.StageScene;
@@ -67,7 +68,7 @@ public class StageSceneManager extends SpotSceneManager
_tloc.y = MisoUtil.toFull(y, 2);
return mayStandAtLocation((BodyObject)traverser, _tloc);
}
protected Location _tloc = new Location();
protected StageLocation _tloc = new StageLocation();
};
}
@@ -150,7 +151,7 @@ public class StageSceneManager extends SpotSceneManager
* Called by NPPs to determine whether or not they can stand at the
* specified location.
*/
public boolean mayStandAtLocation (BodyObject source, Location loc)
public boolean mayStandAtLocation (BodyObject source, StageLocation loc)
{
return validateLocation(source, loc, false);
}
@@ -279,7 +280,8 @@ public class StageSceneManager extends SpotSceneManager
super.updateLocation(source, loc);
// keep a rectangle around for each un-clustered occupant
int tx = MisoUtil.fullToTile(loc.x), ty = MisoUtil.fullToTile(loc.y);
StageLocation sloc = (StageLocation) loc;
int tx = MisoUtil.fullToTile(sloc.x), ty = MisoUtil.fullToTile(sloc.y);
_loners.put(source.getOid(), new Rectangle(tx, ty, 1, 1));
}
@@ -307,8 +309,9 @@ public class StageSceneManager extends SpotSceneManager
_plocs.clear();
for (Iterator iter = _sscene.getPortals(); iter.hasNext(); ) {
Portal port = (Portal)iter.next();
_plocs.add(new Point(MisoUtil.fullToTile(port.loc.x),
MisoUtil.fullToTile(port.loc.y)));
StageLocation loc = (StageLocation) port.loc;
_plocs.add(new Point(MisoUtil.fullToTile(loc.x),
MisoUtil.fullToTile(loc.y)));
}
}
@@ -316,7 +319,7 @@ public class StageSceneManager extends SpotSceneManager
* Helper function for {@link #mayStandAtLocation} and {@link
* #validateLocation(BodyObject,Location)}.
*/
protected boolean validateLocation (BodyObject source, Location loc,
protected boolean validateLocation (BodyObject source, StageLocation loc,
boolean allowPortals)
{
int tx = MisoUtil.fullToTile(loc.x), ty = MisoUtil.fullToTile(loc.y);
@@ -335,14 +338,16 @@ public class StageSceneManager extends SpotSceneManager
}
// if they are already standing on this tile, allow it
Location cloc = (Location)
SceneLocation cloc = (SceneLocation)
_ssobj.occupantLocs.get(new Integer(source.getOid()));
if (cloc != null &&
MisoUtil.fullToTile(cloc.x) == tx &&
MisoUtil.fullToTile(cloc.y) == ty) {
// Log.info("Allowing adjust [who=" + source.who () +
// ", cloc=" + cloc + ", nloc=" + loc + "].");
return true;
if (cloc != null) {
StageLocation sloc = (StageLocation) cloc.loc;
if (MisoUtil.fullToTile(sloc.x) == tx &&
MisoUtil.fullToTile(sloc.y) == ty) {
// Log.info("Allowing adjust [who=" + source.who () +
// ", cloc=" + cloc + ", nloc=" + loc + "].");
return true;
}
}
// make sure they're not standing in a cluster footprint, an
@@ -393,9 +398,10 @@ public class StageSceneManager extends SpotSceneManager
MisoSceneMetrics metrics = StageSceneUtil.getMetrics();
SceneLocation loc = new SceneLocation(
entry.getOppLocation(), body.getOid());
int tx = MisoUtil.fullToTile(loc.x),
ty = MisoUtil.fullToTile(loc.y);
int oidx = loc.orient/2;
StageLocation sloc = (StageLocation) loc.loc;
int tx = MisoUtil.fullToTile(sloc.x),
ty = MisoUtil.fullToTile(sloc.y);
int oidx = sloc.orient/2;
int lidx = (oidx+3)%4; // rotate to the left
int ridx = (oidx+1)%4; // rotate to the right
@@ -409,7 +415,7 @@ public class StageSceneManager extends SpotSceneManager
ty += PORTAL_DY[oidx];
// look in the center column
if (checkEntry(metrics, body, tx, ty, loc)) {
if (checkEntry(metrics, body, tx, ty, sloc)) {
break LOC_SEARCH;
}
@@ -417,7 +423,7 @@ public class StageSceneManager extends SpotSceneManager
for (int lx = tx, ly = ty, ff = 0; ff < fan; ff++) {
lx += PORTAL_DX[lidx];
ly += PORTAL_DY[lidx];
if (checkEntry(metrics, body, lx, ly, loc)) {
if (checkEntry(metrics, body, lx, ly, sloc)) {
break LOC_SEARCH;
}
}
@@ -426,7 +432,7 @@ public class StageSceneManager extends SpotSceneManager
for (int rx = tx, ry = ty, ff = 0; ff < fan; ff++) {
rx += PORTAL_DX[ridx];
ry += PORTAL_DY[ridx];
if (checkEntry(metrics, body, rx, ry, loc)) {
if (checkEntry(metrics, body, rx, ry, sloc)) {
break LOC_SEARCH;
}
}
@@ -434,24 +440,25 @@ public class StageSceneManager extends SpotSceneManager
// if this is our last pass and we didn't find anything,
// revert back to the portal location
if (fan == MAX_FAN-1) {
loc = new SceneLocation(
entry.getOppLocation(), body.getOid());
sloc = (StageLocation) entry.getOppLocation();
}
}
tx = MisoUtil.fullToTile(loc.x);
ty = MisoUtil.fullToTile(loc.y);
tx = MisoUtil.fullToTile(sloc.x);
ty = MisoUtil.fullToTile(sloc.y);
_loners.put(body.getOid(), new Rectangle(tx, ty, 1, 1));
loc.loc = sloc;
return loc;
}
/** Helper function for {@link #computeEnteringLocation}. */
protected boolean checkEntry (MisoSceneMetrics metrics, BodyObject body,
int tx, int ty, SceneLocation sloc)
int tx, int ty, StageLocation loc)
{
sloc.x = MisoUtil.toFull(tx, metrics.finegran/2);
sloc.y = MisoUtil.toFull(ty, metrics.finegran/2);
return validateLocation(body, sloc, false);
loc.x = MisoUtil.toFull(tx, metrics.finegran/2);
loc.y = MisoUtil.toFull(ty, metrics.finegran/2);
return validateLocation(body, loc, false);
}
// documentation inherited
@@ -459,7 +466,7 @@ public class StageSceneManager extends SpotSceneManager
{
// TODO: make sure the user isn't warping to hell and gone (and if
// they are, make sure they're an admin)
return validateLocation(source, loc, true);
return validateLocation(source, (StageLocation)loc, true);
}
// documentation inherited
@@ -653,14 +660,15 @@ public class StageSceneManager extends SpotSceneManager
// if we're adding our first player, assign initial dimensions
// to the cluster
cl.width = 1; cl.height = 1;
Location loc = locationForBody(bodyOid);
SceneLocation loc = locationForBody(bodyOid);
if (loc == null) {
Log.warning("Foreign body added to cluster [clrec=" + clrec +
", body=" + body.who() + "].");
cl.x = 10; cl.y = 10;
} else {
cl.x = MisoUtil.fullToTile(loc.x);
cl.y = MisoUtil.fullToTile(loc.y);
StageLocation sloc = (StageLocation) loc.loc;
cl.x = MisoUtil.fullToTile(sloc.x);
cl.y = MisoUtil.fullToTile(sloc.y);
}
// we'll do everything else when occupant two shows up
return;
@@ -703,7 +711,7 @@ public class StageSceneManager extends SpotSceneManager
// Log.info("Maybe moving " + bodyOid + " from " + sloc +
// " to " + cloc +
// " (avail=" + StringUtil.toString(locs) + ").");
if (cloc != null && !cloc.equivalent(sloc)) {
if (cloc != null && !cloc.loc.equivalent(sloc.loc)) {
cloc.bodyOid = bodyOid;
// Log.info("Moving " + bodyOid + " to " + cloc +
// " for " + cl + ".");
@@ -771,14 +779,16 @@ public class StageSceneManager extends SpotSceneManager
* supplied location.
*/
protected static SceneLocation getClosestLoc (
ArrayList locs, SceneLocation loc)
ArrayList locs, SceneLocation optimalLocation)
{
StageLocation loc = (StageLocation) optimalLocation.loc;
SceneLocation cloc = null;
float cdist = Integer.MAX_VALUE;
int cidx = -1;
for (int ii = 0, ll = locs.size(); ii < ll; ii++) {
SceneLocation tloc = (SceneLocation)locs.get(ii);
float tdist = MathUtil.distance(loc.x, loc.y, tloc.x, tloc.y);
StageLocation sl = (StageLocation) tloc.loc;
float tdist = MathUtil.distance(loc.x, loc.y, sl.x, sl.y);
if (tdist < cdist) {
cloc = tloc;
cdist = tdist;
@@ -51,6 +51,7 @@ import com.threerings.miso.data.ObjectInfo;
import com.threerings.miso.util.MisoUtil;
import com.threerings.stage.client.StageScenePanel;
import com.threerings.stage.data.StageLocation;
import com.threerings.stage.data.StageMisoSceneModel;
import com.threerings.stage.data.StageScene;
@@ -888,15 +889,16 @@ public class EditorScenePanel extends StageScenePanel
protected void paintPortal (Graphics2D gfx, EditablePortal port)
{
// get the portal's center coordinate
StageLocation loc = (StageLocation) port.loc;
Point spos = new Point();
MisoUtil.fullToScreen(_metrics, port.loc.x, port.loc.y, spos);
MisoUtil.fullToScreen(_metrics, loc.x, loc.y, spos);
int cx = spos.x, cy = spos.y;
// translate the origin to center on the portal
gfx.translate(cx, cy);
// rotate to reflect the portal orientation
double rot = (Math.PI / 4.0f) * port.loc.orient;
double rot = (Math.PI / 4.0f) * loc.orient;
gfx.rotate(rot);
// draw the triangle
@@ -17,6 +17,7 @@ import com.threerings.util.DirectionUtil;
import com.threerings.whirled.spot.data.Location;
import com.threerings.whirled.spot.tools.EditablePortal;
import com.threerings.stage.data.StageLocation;
import com.threerings.stage.data.StageScene;
import com.threerings.stage.tools.editor.util.ExtrasPainter;
@@ -37,7 +38,7 @@ public class PortalTool extends MouseInputAdapter
// configure the portal with these full coordinates
_portal = new EditablePortal();
_portal.loc = new Location(p.x, p.y, (byte)DirectionCodes.NORTH);
_portal.loc = new StageLocation(p.x, p.y, (byte)DirectionCodes.NORTH);
// we want to listen to drags and clicks
_panel.addMouseListener(this);
@@ -99,8 +100,9 @@ public class PortalTool extends MouseInputAdapter
}
// if our orientation changed, repaint
if (norient != _portal.loc.orient) {
_portal.loc.orient = (byte)norient;
StageLocation loc = (StageLocation) _portal.loc;
if (norient != loc.orient) {
loc.orient = (byte)norient;
_panel.repaint();
}
}
@@ -111,8 +113,8 @@ public class PortalTool extends MouseInputAdapter
protected void savePortal ()
{
// try to come up with a reasonable name
String dirname =
DirectionUtil.toString(_portal.loc.orient).toLowerCase();
byte orient = ((StageLocation) _portal.loc).orient;
String dirname = DirectionUtil.toString(orient).toLowerCase();
String name = dirname;
for (int ii=1; portalNameExists(name); ii++) {
name = dirname + ii;
@@ -31,6 +31,7 @@ import com.threerings.stage.client.StageScenePanel;
import com.threerings.whirled.spot.data.Location;
import com.threerings.stage.Log;
import com.threerings.stage.data.StageLocation;
import com.threerings.stage.data.StageScene;
import com.threerings.stage.util.StageContext;
@@ -66,8 +67,8 @@ public class ViewerScenePanel extends StageScenePanel
setScene(scene);
// move all of our sprites to the default entrance
_defloc = defloc;
Point defpos = getScreenCoords(defloc.x, defloc.y);
_defloc = (StageLocation) defloc;
Point defpos = getScreenCoords(_defloc.x, _defloc.y);
_sprite.setLocation(defpos.x, defpos.y);
if (_decoys != null) {
@@ -220,7 +221,7 @@ public class ViewerScenePanel extends StageScenePanel
protected static final int DEFAULT_NUM_DECOYS = 10;
/** The current scene's default entrance. */
protected Location _defloc;
protected StageLocation _defloc;
/** Provides character sprite data. */
protected CharacterManager _charmgr;
@@ -11,6 +11,9 @@ import com.threerings.whirled.spot.tools.xml.SpotSceneRuleSet;
import com.threerings.whirled.tools.xml.SceneParser;
import com.threerings.whirled.tools.xml.SceneRuleSet;
import com.threerings.whirled.spot.data.Location;
import com.threerings.stage.data.StageLocation;
import com.threerings.stage.data.StageSceneModel;
/**
@@ -37,7 +40,11 @@ public class StageSceneParser extends SceneParser
});
// add rule sets for our aux scene models
registerAuxRuleSet(new SpotSceneRuleSet());
registerAuxRuleSet(new SpotSceneRuleSet() {
protected Location createLocation () {
return new StageLocation();
}
});
registerAuxRuleSet(new StageMisoSceneRuleSet());
}
@@ -31,6 +31,7 @@ import com.threerings.whirled.spot.data.Location;
import com.threerings.whirled.spot.data.SceneLocation;
import com.threerings.stage.Log;
import com.threerings.stage.data.StageLocation;
import com.threerings.stage.data.StageMisoSceneModel;
import com.threerings.stage.data.StageSceneModel;
@@ -51,7 +52,7 @@ public class StageSceneUtil
* Does the necessary jiggery pokery to figure out where the specified
* object's associated location is.
*/
public static Location locationForObject (
public static StageLocation locationForObject (
TileManager tilemgr, ObjectInfo info)
{
return locationForObject(tilemgr, info.tileId, info.x, info.y);
@@ -67,7 +68,7 @@ public class StageSceneUtil
* @param tx the object's x tile coordinate.
* @param ty the object's y tile coordinate.
*/
public static Location locationForObject (
public static StageLocation locationForObject (
TileManager tilemgr, int tileId, int tx, int ty)
{
try {
@@ -89,7 +90,8 @@ public class StageSceneUtil
// ", sy=" + tset.getYSpot(tidx) +
// ", lx=" + opos.x + ", ly=" + opos.y +
// ", fg=" + _metrics.finegran + "].");
return new Location(opos.x, opos.y, (byte)tset.getSpotOrient(tidx));
return new StageLocation(opos.x, opos.y,
(byte)tset.getSpotOrient(tidx));
} catch (Exception e) {
Log.warning("Unable to look up object tile for scene object " +
@@ -189,9 +191,9 @@ public class StageSceneUtil
/**
* Computes a list of the valid locations in this cluster.
*/
public static ArrayList getClusterLocs (Cluster cluster)
public static ArrayList<SceneLocation> getClusterLocs (Cluster cluster)
{
ArrayList list = new ArrayList();
ArrayList<SceneLocation> list = new ArrayList<SceneLocation>();
// convert our tile coordinates into a cartesian coordinate system
// with units equal to one fine coordinate in size
@@ -204,9 +206,10 @@ public class StageSceneUtil
// if it's a 1x1 cluster, return one location in the center of the
// cluster
if (cluster.width == 1) {
list.add(new SceneLocation(MisoUtil.toFull(cluster.x, 2),
MisoUtil.toFull(cluster.y, 2),
(byte)DirectionCodes.SOUTHWEST, 0));
StageLocation loc = new StageLocation(
MisoUtil.toFull(cluster.x, 2), MisoUtil.toFull(cluster.y, 2),
(byte)DirectionCodes.SOUTHWEST);
list.add(new SceneLocation(loc, 0));
return list;
}
@@ -233,7 +236,8 @@ public class StageSceneUtil
sx = MisoUtil.toFull(tx, sx-(tx*_metrics.finegran));
int ty = MathUtil.floorDiv(sy, _metrics.finegran);
sy = MisoUtil.toFull(ty, sy-(ty*_metrics.finegran));
list.add(new SceneLocation(sx, sy, (byte)orient, 0));
StageLocation loc = new StageLocation(sx, sy, (byte) orient);
list.add(new SceneLocation(loc, 0));
}
return list;
@@ -279,7 +283,7 @@ public class StageSceneUtil
*
* @return the closest spot to the
*/
public static Location findStandingSpot (
public static StageLocation findStandingSpot (
Rectangle foot, int dist, AStarPathUtil.TraversalPred pred,
Object traverser, final Point nearto, int orient)
{
@@ -292,28 +296,36 @@ public class StageSceneUtil
int xx1 = foot.x-dd, xx2 = foot.x+foot.width+dd-1;
// get the corners
spots.add(new Location(xx1, yy1, (byte)DirectionCodes.SOUTHWEST));
spots.add(new Location(xx1, yy2, (byte)DirectionCodes.SOUTHEAST));
spots.add(new Location(xx2, yy1, (byte)DirectionCodes.NORTHWEST));
spots.add(new Location(xx2, yy2, (byte)DirectionCodes.NORTHEAST));
spots.add(
new StageLocation(xx1, yy1, (byte)DirectionCodes.SOUTHWEST));
spots.add(
new StageLocation(xx1, yy2, (byte)DirectionCodes.SOUTHEAST));
spots.add(
new StageLocation(xx2, yy1, (byte)DirectionCodes.NORTHWEST));
spots.add(
new StageLocation(xx2, yy2, (byte)DirectionCodes.NORTHEAST));
// then the sides
for (int xx = xx1+1; xx < xx2; xx++) {
spots.add(new Location(xx, yy1, (byte)DirectionCodes.WEST));
spots.add(new Location(xx, yy2, (byte)DirectionCodes.EAST));
spots.add(
new StageLocation(xx, yy1, (byte)DirectionCodes.WEST));
spots.add(
new StageLocation(xx, yy2, (byte)DirectionCodes.EAST));
}
for (int yy = yy1+1; yy < yy2; yy++) {
spots.add(new Location(xx1, yy, (byte)DirectionCodes.SOUTH));
spots.add(new Location(xx2, yy, (byte)DirectionCodes.NORTH));
spots.add(
new StageLocation(xx1, yy, (byte)DirectionCodes.SOUTH));
spots.add(
new StageLocation(xx2, yy, (byte)DirectionCodes.NORTH));
}
// sort them in order of closeness to the players current
// coordinate
spots.sort(new Comparator() {
public int compare (Object o1, Object o2) {
return dist((Location)o1) - dist((Location)o2);
return dist((StageLocation)o1) - dist((StageLocation)o2);
}
private final int dist (Location l) {
private final int dist (StageLocation l) {
return Math.round(100*MathUtil.distance(
l.x, l.y, nearto.x, nearto.y));
}
@@ -322,7 +334,7 @@ public class StageSceneUtil
// return the first spot that can be "traversed" which we're
// taking to mean "stood upon"
for (int ii = 0, ll = spots.size(); ii < ll; ii++) {
Location loc = (Location)spots.get(ii);
StageLocation loc = (StageLocation)spots.get(ii);
if (pred.canTraverse(traverser, loc.x, loc.y)) {
// convert to full coordinates
loc.x = MisoUtil.toFull(loc.x, 2);
@@ -1,112 +1,34 @@
//
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2004 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.whirled.spot.data;
import com.threerings.io.SimpleStreamableObject;
import com.threerings.util.DirectionCodes;
import com.threerings.util.DirectionUtil;
import com.threerings.io.Streamable;
/**
* Contains information on a scene occupant's position and orientation.
*/
public class Location extends SimpleStreamableObject
implements Cloneable
public interface Location extends Streamable, Cloneable
{
/** The user's x position (interpreted by the display system). */
public int x;
/** The user's y position (interpreted by the display system). */
public int y;
/** The user's orientation (defined by {@link DirectionCodes}). */
public byte orient;
/** {@link #toString} helper function. */
public String orientToString ()
{
return DirectionUtil.toShortString(orient);
}
/**
* Get a new Location instance that is equals() to this one but that
* has an orientation facing the opposite direction.
*/
public Location getOpposite ();
/**
* A zero-argument constructor used when unserializing instances.
* Two locations are equivalent if they specify the same location
* and orientation.
*/
public Location ()
{
}
public boolean equivalent (Location other);
/**
* Constructs a location with the specified coordinates and
* orientation.
* Two locations are equals if they specify the same coordinates, but
* the orientation may be different.
*/
public Location (int x, int y, byte orient)
{
this.x = x;
this.y = y;
this.orient = orient;
if (orient == -1) {
Thread.dumpStack();
}
}
public boolean equals (Object other);
/**
* Creates a clone of this instance.
* The hashcode of a Location should be based only on its coordinates.
*/
public Object clone ()
{
try {
return (Location)super.clone();
} catch (CloneNotSupportedException cnse) {
throw new RuntimeException("Location.clone() failed " + cnse);
}
}
public int hashCode ();
/**
* Location equality is determined by coordinates.
* Locations are cloneable.
*/
public boolean equals (Object other)
{
if (other instanceof Location) {
Location oloc = (Location)other;
return (x == oloc.x) && (y == oloc.y);
} else {
return false;
}
}
/**
* Location equivalence means that the coordinates and orientation are
* the same.
*/
public boolean equivalent (Location oloc)
{
return equals(oloc) && (orient == oloc.orient);
}
/**
* Computes a reasonable hashcode for location instances.
*/
public int hashCode ()
{
return x ^ y;
}
public Object clone ();
}
@@ -22,7 +22,6 @@
package com.threerings.whirled.spot.data;
import com.threerings.io.SimpleStreamableObject;
import com.threerings.util.DirectionUtil;
/**
* Represents an exit to another scene. A body sprite would walk over to a
@@ -39,9 +38,8 @@ public class Portal extends SimpleStreamableObject
/** This portal's unique identifier. */
public short portalId;
/** The location of the portal. Typically this is a base Location (2d)
* class, but different games could use a different subclass of
* Location. */
/** The location of the portal.
* This field is present on client and server, it is streamed specially. */
public Location loc;
/** The scene identifier of the scene to which a body will exit when
@@ -70,9 +68,7 @@ public class Portal extends SimpleStreamableObject
*/
public Location getOppLocation ()
{
Location oppLoc = getLocation();
oppLoc.orient = (byte) DirectionUtil.getOpposite(oppLoc.orient);
return oppLoc;
return loc.getOpposite();
}
/**
@@ -102,12 +98,8 @@ public class Portal extends SimpleStreamableObject
*/
public boolean equals (Object other)
{
if (other instanceof Portal) {
Portal oport = (Portal)other;
return portalId == oport.portalId;
} else {
return false;
}
return (other instanceof Portal) &&
((Portal) other).portalId == portalId;
}
/**
@@ -21,33 +21,29 @@
package com.threerings.whirled.spot.data;
import com.threerings.io.SimpleStreamableObject;
import com.threerings.presents.dobj.DSet;
/**
* Extends {@link Location} with the data and functionality needed to
* represent a particular user's location in a scene.
*/
public class SceneLocation extends Location
public class SceneLocation extends SimpleStreamableObject
implements DSet.Entry
{
/** The oid of the body that occupies this location. */
public int bodyOid;
/**
* Creates a scene location with the specified information.
*/
public SceneLocation (int x, int y, byte orient, int bodyOid)
{
super(x, y, orient);
this.bodyOid = bodyOid;
}
/** The actual location, which is interpreted by the display system. */
public Location loc;
/**
* Creates a scene location with the specified information.
*/
public SceneLocation (Location loc, int bodyOid)
{
super(loc.x, loc.y, loc.orient);
this.loc = loc;
this.bodyOid = bodyOid;
}
@@ -67,6 +63,26 @@ public class SceneLocation extends Location
return _key;
}
// documentation inherited
public boolean equals (Object other)
{
// TEMP
if (other instanceof Location) {
Thread.dumpStack(); // this will help us find logic errors,
// as a SceneLocation and a Location shouldn't be compared
}
// END: temp
return (other instanceof SceneLocation) &&
this.loc.equals(((SceneLocation) other).loc);
}
// documentation inherited
public int hashCode ()
{
return loc.hashCode();
}
/** Used for {@link #getKey}. */
protected transient Integer _key;
}
@@ -43,7 +43,7 @@ import com.threerings.whirled.spot.tools.EditablePortal;
/**
* Used to parse a {@link SpotSceneModel} from XML.
*/
public class SpotSceneRuleSet implements NestableRuleSet
public abstract class SpotSceneRuleSet implements NestableRuleSet
{
// documentation inherited from interface
public String getOuterElement ()
@@ -70,10 +70,7 @@ public class SpotSceneRuleSet implements NestableRuleSet
* Create a new instance of the Location class that should be used
* with Portals.
*/
protected Location createNewLocation ()
{
return new Location();
}
protected abstract Location createLocation ();
/**
* A rule used to create the portal but also initialize the Location
@@ -95,7 +92,7 @@ public class SpotSceneRuleSet implements NestableRuleSet
// create the empty Location in the Portal
Portal p = (Portal) digester.peek();
p.loc = _ruleset.createNewLocation();
p.loc = _ruleset.createLocation();
}
protected SpotSceneRuleSet _ruleset;