Atlanti is now part of the Game Gardens repository.
git-svn-id: https://samskivert.googlecode.com/svn/trunk@1615 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
@@ -1,4 +0,0 @@
|
||||
(jde-set-variables
|
||||
'(jde-db-source-directories (quote ("/export/local/jdk1.4/src" "/home/mdb/projects/samskivert/src/java" "/home/mdb/work/narya/src/java" "/home/mdb/projects/atlanti/src/java")))
|
||||
'(jde-global-classpath (quote ("/home/mdb/projects/samskivert/dist/classes" "/home/mdb/work/narya/dist/classes" "/home/mdb/projects/atlanti/dist/classes")))
|
||||
)
|
||||
@@ -1,21 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
BINDIR=`dirname $0`
|
||||
JAVA_ARGS=""
|
||||
ARGS=""
|
||||
|
||||
# grab the -Dinviter if it's specified
|
||||
while [ ! -z "$1" ] ; do
|
||||
case $1 in
|
||||
-D*)
|
||||
JAVA_ARGS="$JAVA_ARGS $1"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
ARGS="$ARGS $1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
$BINDIR/runjava $JAVA_ARGS com.threerings.micasa.client.MiCasaApp $ARGS
|
||||
@@ -1,4 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
bindir=`dirname $0`
|
||||
$bindir/runjava com.threerings.micasa.server.MiCasaServer $*
|
||||
@@ -1,90 +0,0 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
use Getopt::Std;
|
||||
|
||||
my $usage = "Usage: $0 [-p pid_file] [-r root_directory] args\n";
|
||||
|
||||
# locations of stuff
|
||||
chomp($location = `dirname $0`);
|
||||
|
||||
# get the server root by popping the /bin off of our parent directory
|
||||
@parts = split(/\//, $location);
|
||||
pop(@parts);
|
||||
my $root = join("/", @parts);
|
||||
|
||||
my $jhome = $ENV{"JAVA_HOME"};
|
||||
|
||||
# make sure JAVA_HOME is set
|
||||
if (!defined $jhome) {
|
||||
warn "$0: Error: No JAVA_HOME specified!\n";
|
||||
warn "\n";
|
||||
warn "You must set your JAVA_HOME environment variable to the\n";
|
||||
warn "the absolute path of your JDK installation. For example:\n";
|
||||
warn "\n";
|
||||
warn " % JAVA_HOME=/usr/local/jdk1.2\n";
|
||||
warn " % export JAVA_HOME\n";
|
||||
die "\n";
|
||||
}
|
||||
|
||||
# make sure it's set to a directory
|
||||
if (! -d $jhome) {
|
||||
die "$0: Can't find a java interpreter in '$jhome'.\n";
|
||||
}
|
||||
|
||||
my $java = "$jhome/bin/java";
|
||||
my $jlib = "$jhome/lib/classes.zip";
|
||||
|
||||
# put everything in our class path
|
||||
my $classpath = "-classpath $root/dist/classes";
|
||||
|
||||
# add zip and jar files from our lib/ directory and the system lib/ directory
|
||||
my @dirs = ( "$root/lib" );
|
||||
foreach $dir (@dirs) {
|
||||
next unless (defined $dir);
|
||||
if (opendir(DIR, $dir)) {
|
||||
foreach $lib (grep { /.(zip|jar)/ && -f "$dir/$_" } readdir(DIR)) {
|
||||
$classpath .= ":$dir/$lib";
|
||||
}
|
||||
closedir DIR;
|
||||
}
|
||||
}
|
||||
|
||||
# finally add the standard classes
|
||||
$classpath = "$classpath:$jlib";
|
||||
|
||||
# specify our application root (the resource manager needs this)
|
||||
my $rootarg = "-Dresource_url=file:$root/rsrc";
|
||||
|
||||
my $pid_file = undef;
|
||||
my $i = 0;
|
||||
|
||||
# strip out the -p and -r args (we'd use getopt() but the damned thing
|
||||
# provides no way of escaping arguments so that we can pass args to
|
||||
# runjava that get passed down to the JVM)
|
||||
for ($i = 0; $i < @ARGV; $i++) {
|
||||
my $arg = $ARGV[$i];
|
||||
|
||||
# stop when we see -- (and strip it out because Java don't dig --)
|
||||
if ($arg eq "--") {
|
||||
splice(@ARGV, $i, 1);
|
||||
last;
|
||||
}
|
||||
|
||||
if ($arg eq "-p") {
|
||||
$pid_file = $ARGV[$i+1];
|
||||
splice(@ARGV, $i, 2);
|
||||
$i -= 1; # decrement i so that things stay in sync
|
||||
|
||||
} elsif ($arg eq "-r") {
|
||||
$rootarg = "-DDapplication.root=" . $ARGV[$i+1];
|
||||
splice(@ARGV, $i, 2);
|
||||
$i -= 1; # decrement i so that things stay in sync
|
||||
}
|
||||
}
|
||||
|
||||
# log the pid file if requested to do so
|
||||
print `echo $$ > $pid_file` if (defined $pid_file);
|
||||
|
||||
my $cmd = "$java -mx256M $classpath $rootarg " . join(" ", @ARGV);
|
||||
# print "$cmd\n";
|
||||
exec($cmd);
|
||||
@@ -1,83 +0,0 @@
|
||||
<!-- build configuration -->
|
||||
<project name="atlanti" default="compile" basedir=".">
|
||||
|
||||
<!-- things you may want to change -->
|
||||
<property name="app.name" value="atlanti"/>
|
||||
<property name="doc.packages" value="com.threerings.atlanti.*"/>
|
||||
<property name="doc.overview" value="com/threerings/atlanti/overview.html"/>
|
||||
<property name="copyright.holder" value="Michael Bayne"/>
|
||||
<property name="narya.home" value="../../work/narya"/>
|
||||
|
||||
<!-- things you probably don't want to change -->
|
||||
<property name="src.dir" value="src/java"/>
|
||||
<property name="deploy.dir" value="dist"/>
|
||||
<property name="dist.jar" value="${app.name}.jar"/>
|
||||
<property name="javadoc.dir" value="${deploy.dir}/docs"/>
|
||||
<property name="gendobj.path" value="${narya.home}/bin/gendobj"/>
|
||||
|
||||
<!-- declare our classpath -->
|
||||
<path id="classpath">
|
||||
<fileset dir="lib" includes="**/*.jar"/>
|
||||
<pathelement location="${deploy.dir}/classes"/>
|
||||
</path>
|
||||
|
||||
<!-- generates .java files for all .dobj files -->
|
||||
<target name="gendobj">
|
||||
<apply executable="${gendobj.path}" failonerror="true">
|
||||
<srcfile/>
|
||||
<fileset dir="src/java" includes="**/*.dobj"/>
|
||||
</apply>
|
||||
</target>
|
||||
|
||||
<!-- prepares the application directories -->
|
||||
<target name="prepare" depends="gendobj">
|
||||
<mkdir dir="${deploy.dir}"/>
|
||||
<mkdir dir="${deploy.dir}/classes"/>
|
||||
<mkdir dir="${deploy.dir}/classes/rsrc"/>
|
||||
<mkdir dir="${javadoc.dir}"/>
|
||||
<copy todir="${deploy.dir}/classes">
|
||||
<fileset dir="${src.dir}" includes="**/*.properties"/>
|
||||
</copy>
|
||||
<copy todir="${deploy.dir}/classes/rsrc">
|
||||
<fileset dir="rsrc" includes="**/*"/>
|
||||
</copy>
|
||||
</target>
|
||||
|
||||
<!-- cleans out the installed application -->
|
||||
<target name="clean">
|
||||
<delete dir="${deploy.dir}"/>
|
||||
</target>
|
||||
|
||||
<!-- build the java class files -->
|
||||
<target name="compile" depends="prepare">
|
||||
<javac srcdir="${src.dir}" destdir="${deploy.dir}/classes"
|
||||
debug="on" optimize="off" deprecation="on">
|
||||
<classpath refid="classpath"/>
|
||||
</javac>
|
||||
</target>
|
||||
|
||||
<!-- build the javadoc documentation -->
|
||||
<target name="javadoc" depends="prepare">
|
||||
<javadoc sourcepath="${src.dir}"
|
||||
packagenames="${doc.packages}"
|
||||
windowtitle="${app.name} API"
|
||||
doctitle="${app.name} API"
|
||||
overview="${src.dir}/${doc.overview}"
|
||||
bottom="Copyright © 2001 ${copyright.holder}. All Rights Reserved."
|
||||
destdir="${javadoc.dir}"
|
||||
additionalparam="-breakiterator">
|
||||
<classpath refid="classpath"/>
|
||||
<link href="http://java.sun.com/j2se/1.3/docs/api/"/>
|
||||
</javadoc>
|
||||
</target>
|
||||
|
||||
<!-- a target for rebuilding everything -->
|
||||
<target name="all" depends="clean,prepare,compile,javadoc,dist"/>
|
||||
|
||||
<!-- builds our distribution files (war and jar) -->
|
||||
<target name="dist" depends="prepare,compile">
|
||||
<jar file="${deploy.dir}/${dist.jar}"
|
||||
basedir="${deploy.dir}/classes"/>
|
||||
</target>
|
||||
|
||||
</project>
|
||||
@@ -1 +0,0 @@
|
||||
i686-Linux
|
||||
@@ -1,22 +0,0 @@
|
||||
Required external libraries
|
||||
---------------------------
|
||||
|
||||
The Atlantissonne code requires the following external Java libraries (JAR
|
||||
files) to be placed (or symlinked) here in the lib/ directory.
|
||||
|
||||
* Apache Commons Lang library (from the sanbox)
|
||||
http://jakarta.apache.org/commons/index.html
|
||||
|
||||
* The samskivert library:
|
||||
http://www.waywardgeeks.org/code/samskivert/
|
||||
|
||||
* The Narya game development libraries; specifically: base, distrib,
|
||||
media, micasa and parlor
|
||||
http://www.threerings.net/code/narya/
|
||||
|
||||
Once the jar files are in place (regardless of what they are named), the
|
||||
build system will automatically include them in the compile-time
|
||||
classpath.
|
||||
|
||||
--
|
||||
$Id: README,v 1.3 2002/12/12 06:10:13 mdb Exp $
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,14 +0,0 @@
|
||||
#
|
||||
# $Id: dbmap.properties,v 1.3 2003/03/23 05:02:31 mdb Exp $
|
||||
#
|
||||
# This provides information on the JDBC connections that are used by
|
||||
# Atlantisonne server services.
|
||||
|
||||
# The default database mapping. All other definitions will inherit from
|
||||
# this and need only be specified in cases where they differ from the
|
||||
# defaults.
|
||||
|
||||
default.driver = org.gjt.mm.mysql.Driver
|
||||
default.url = jdbc:mysql://DBHOST:3306/usermgmt
|
||||
default.username = USERNAME
|
||||
default.password = PASSWORD
|
||||
@@ -1,4 +0,0 @@
|
||||
#
|
||||
# $Id: server.properties,v 1.2 2002/12/12 05:51:53 mdb Exp $
|
||||
#
|
||||
# Configuration for the Atlantissonne server
|
||||
@@ -1,20 +0,0 @@
|
||||
#
|
||||
# $Id: server.properties,v 1.3 2002/12/12 05:51:53 mdb Exp $
|
||||
#
|
||||
# Configuration for the MiCasa server
|
||||
|
||||
_package = atlanti.server
|
||||
_overrides = micasa.server
|
||||
|
||||
#
|
||||
# The list of lobby identifiers to be loaded into this server.
|
||||
#
|
||||
lobby_ids = atlanti
|
||||
|
||||
#
|
||||
# The cofiguration for the test lobby.
|
||||
#
|
||||
atlanti.config = com.threerings.micasa.lobby.table.TableLobbyConfig
|
||||
atlanti.ugi = atlanti,board,tile,strategy
|
||||
atlanti.name = Atlanti Lobby
|
||||
atlanti.game_config = com.samskivert.atlanti.data.AtlantiConfig
|
||||
@@ -1,4 +0,0 @@
|
||||
#
|
||||
# $Id: atlanti.properties,v 1.1 2002/05/21 04:45:09 mdb Exp $
|
||||
#
|
||||
# Translation messages
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.2 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 63 KiB |
@@ -1,54 +0,0 @@
|
||||
//
|
||||
// $Id: Log.java,v 1.3 2002/12/12 05:51:53 mdb Exp $
|
||||
|
||||
package com.samskivert.atlanti;
|
||||
|
||||
/**
|
||||
* A placeholder class that contains a reference to the log object used by
|
||||
* this package. This is a useful pattern to use when using the samskivert
|
||||
* logging facilities. One creates a top-level class like this one that
|
||||
* instantiates a log object with an name that identifies log messages
|
||||
* from that package and then provides static methods that generate log
|
||||
* messages using that instance. Then, classes in that package need only
|
||||
* import the log wrapper class and can easily use it to generate log
|
||||
* messages. For example:
|
||||
*
|
||||
* <pre>
|
||||
* import com.samskivert.atlanti.Log;
|
||||
* // ...
|
||||
* Log.warning("All hell is breaking loose!");
|
||||
* // ...
|
||||
* </pre>
|
||||
*
|
||||
* @see com.samskivert.util.Log
|
||||
*/
|
||||
public class Log
|
||||
{
|
||||
/** The static log instance configured for use by this package. */
|
||||
public static com.samskivert.util.Log log =
|
||||
new com.samskivert.util.Log("atlanti");
|
||||
|
||||
/** Convenience function. */
|
||||
public static void debug (String message)
|
||||
{
|
||||
log.debug(message);
|
||||
}
|
||||
|
||||
/** Convenience function. */
|
||||
public static void info (String message)
|
||||
{
|
||||
log.info(message);
|
||||
}
|
||||
|
||||
/** Convenience function. */
|
||||
public static void warning (String message)
|
||||
{
|
||||
log.warning(message);
|
||||
}
|
||||
|
||||
/** Convenience function. */
|
||||
public static void logStackTrace (Throwable t)
|
||||
{
|
||||
log.logStackTrace(com.samskivert.util.Log.WARNING, t);
|
||||
}
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
//
|
||||
// $Id: TileGeometryTest.java,v 1.7 2003/03/23 02:22:51 mdb Exp $
|
||||
|
||||
package com.samskivert.atlanti;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import com.samskivert.swing.util.SwingUtil;
|
||||
|
||||
import com.threerings.media.image.ImageManager;
|
||||
import com.threerings.media.tile.TileManager;
|
||||
import com.threerings.resource.ResourceManager;
|
||||
|
||||
import com.samskivert.atlanti.data.AtlantiTile;
|
||||
import com.samskivert.atlanti.data.TileCodes;
|
||||
import com.samskivert.atlanti.util.PiecenUtil;
|
||||
|
||||
/**
|
||||
* A simple class for testing the tile geometry specifications by drawing
|
||||
* them.
|
||||
*/
|
||||
public class TileGeometryTest extends JPanel
|
||||
implements TileCodes
|
||||
{
|
||||
public TileGeometryTest ()
|
||||
{
|
||||
for (int i = 0; i < TILE_TYPES; i++) {
|
||||
_tiles[i] = new AtlantiTile(i+1, true, NORTH, i % 5, i / 5);
|
||||
}
|
||||
}
|
||||
|
||||
public void paintComponent (Graphics g)
|
||||
{
|
||||
super.paintComponent(g);
|
||||
|
||||
// paint our tiles
|
||||
for (int i = 0; i < _tiles.length; i++) {
|
||||
_tiles[i].paint((Graphics2D)g, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public Dimension getPreferredSize ()
|
||||
{
|
||||
// we want to be five tiles wide by four tiles tall
|
||||
return new Dimension(TILE_WIDTH * 5, TILE_HEIGHT * 4);
|
||||
}
|
||||
|
||||
public static void main (String[] args)
|
||||
{
|
||||
JFrame frame = new JFrame("Tile geometry test");
|
||||
|
||||
ResourceManager rmgr = new ResourceManager("rsrc");
|
||||
ImageManager imgr = new ImageManager(rmgr, frame);
|
||||
TileManager tmgr = new TileManager(imgr);
|
||||
|
||||
AtlantiTile.setManagers(imgr, tmgr);
|
||||
AtlantiTile.piecenDebug = true;
|
||||
PiecenUtil.init(tmgr);
|
||||
|
||||
// quit if we're closed
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
TileGeometryTest panel = new TileGeometryTest();
|
||||
frame.getContentPane().add(panel);
|
||||
frame.pack();
|
||||
SwingUtil.centerWindow(frame);
|
||||
frame.show();
|
||||
}
|
||||
|
||||
protected AtlantiTile[] _tiles = new AtlantiTile[TILE_TYPES];
|
||||
}
|
||||
@@ -1,693 +0,0 @@
|
||||
//
|
||||
// $Id: AtlantiBoard.java,v 1.19 2003/03/23 05:12:43 mdb Exp $
|
||||
|
||||
package com.samskivert.atlanti.client;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import javax.swing.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import com.samskivert.swing.Controller;
|
||||
import com.samskivert.swing.util.SwingUtil;
|
||||
import com.samskivert.util.CollectionUtil;
|
||||
|
||||
import com.threerings.presents.dobj.DSet;
|
||||
|
||||
import com.samskivert.atlanti.Log;
|
||||
import com.samskivert.atlanti.data.AtlantiCodes;
|
||||
import com.samskivert.atlanti.data.AtlantiTile;
|
||||
import com.samskivert.atlanti.data.Piecen;
|
||||
import com.samskivert.atlanti.data.TileCodes;
|
||||
import com.samskivert.atlanti.util.TileUtil;
|
||||
|
||||
/**
|
||||
* Displays the tiles that make up the board.
|
||||
*/
|
||||
public class AtlantiBoard extends JPanel
|
||||
implements TileCodes, AtlantiCodes
|
||||
{
|
||||
/**
|
||||
* Constructs a board.
|
||||
*/
|
||||
public AtlantiBoard ()
|
||||
{
|
||||
// create mouse adapters that will let us know when interesting
|
||||
// mouse events happen
|
||||
addMouseListener(new MouseAdapter() {
|
||||
public void mouseClicked (MouseEvent evt) {
|
||||
AtlantiBoard.this.mouseClicked(evt);
|
||||
}
|
||||
});
|
||||
addMouseMotionListener(new MouseMotionAdapter() {
|
||||
public void mouseMoved (MouseEvent evt) {
|
||||
AtlantiBoard.this.mouseMoved(evt);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the piecen color to use when creating new piecens.
|
||||
*/
|
||||
public void setNewPiecenColor (int color)
|
||||
{
|
||||
_newPiecenColor = color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the tiles to be displayed by this board. Any previous tiles
|
||||
* are forgotten and the new tiles are initialized according to their
|
||||
* geometry to set up initial claim groups.
|
||||
*
|
||||
* @param tset the set of {@link AtlantiTile} objects to be displayed
|
||||
* by this board.
|
||||
*/
|
||||
public void setTiles (DSet tset)
|
||||
{
|
||||
// clear out our old tiles list
|
||||
_tiles.clear();
|
||||
|
||||
// copy the tiles from the set into our local list
|
||||
CollectionUtil.addAll(_tiles, tset.entries());
|
||||
|
||||
// sort the list
|
||||
Collections.sort(_tiles);
|
||||
|
||||
// recompute our desired dimensions and then have our parent
|
||||
// adjust to our changed size
|
||||
computeDimensions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the piecens to be placed on the appropriate tiles of the
|
||||
* board. This should only be done when first entering the game room
|
||||
* and subsequent piecen placement should be done via {@link
|
||||
* #placePiecen}.
|
||||
*/
|
||||
public void setPiecens (DSet piecens)
|
||||
{
|
||||
// just iterate over the set placing each of the piecens in turn
|
||||
Iterator iter = piecens.entries();
|
||||
while (iter.hasNext()) {
|
||||
placePiecen((Piecen)iter.next());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instructs the board to add the specified tile to the display. The
|
||||
* tile will have its claims inherited accordingly.
|
||||
*/
|
||||
public void addTile (AtlantiTile tile)
|
||||
{
|
||||
Log.info("Adding tile to board " + tile + ".");
|
||||
|
||||
// if we add a tile that is the same as our most recently placed
|
||||
// tile, leave the placed tile. otherwise clear it out
|
||||
if (!tile.equals(_placedTile)) {
|
||||
_placedTile = null;
|
||||
}
|
||||
|
||||
// add the tile
|
||||
_tiles.add(tile);
|
||||
|
||||
// reference this as our most recently placed tile
|
||||
_lastPlacedTile = tile;
|
||||
|
||||
// resort the list
|
||||
Collections.sort(_tiles);
|
||||
|
||||
// have the new tile inherit its claim groups
|
||||
TileUtil.inheritClaims(_tiles, tile);
|
||||
|
||||
// recompute our desired dimensions and then have our parent
|
||||
// adjust to our changed size
|
||||
computeDimensions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Places the specified piecen on the appropriate tile and updates
|
||||
* claim groups as necessary.
|
||||
*/
|
||||
public void placePiecen (Piecen piecen)
|
||||
{
|
||||
// if we still have a placed tile, we get rid of it
|
||||
_placedTile = null;
|
||||
|
||||
Log.info("Placing " + piecen + ".");
|
||||
|
||||
// locate the tile associated with this piecen
|
||||
int tidx = _tiles.indexOf(piecen);
|
||||
if (tidx != -1) {
|
||||
AtlantiTile tile = (AtlantiTile)_tiles.get(tidx);
|
||||
// set the piecen on the tile (supplying our tile list so that
|
||||
// the necessary claim group adjustments can be made)
|
||||
tile.setPiecen(piecen, _tiles);
|
||||
// and repaint
|
||||
repaintTile(tile);
|
||||
|
||||
} else {
|
||||
Log.warning("Requested to place piecen for which we could " +
|
||||
"find no associated tile! [piecen=" + piecen + "].");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When a piecen is removed (after scoring it), this method should be
|
||||
* called to update the board display.
|
||||
*/
|
||||
public void clearPiecen (Object key)
|
||||
{
|
||||
// locate the tile associated with this piecen key
|
||||
int tsize = _tiles.size();
|
||||
for (int i = 0; i < tsize; i++) {
|
||||
AtlantiTile tile = (AtlantiTile)_tiles.get(i);
|
||||
if (tile.getKey().equals(key)) {
|
||||
// clear the piecen out of the tile
|
||||
tile.clearPiecen();
|
||||
// and repaint
|
||||
repaintTile(tile);
|
||||
// and get on out
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Log.warning("Requested to clear piecen for which we could " +
|
||||
"find no associated tile! [key=" + key + "].");
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn off the ability to place a piecen on the most recently played
|
||||
* tile. This function assumes that the mouse will not be over a valid
|
||||
* piecen placement at the time this function is called (it expects
|
||||
* that it will be over a button of some sort that says something to
|
||||
* the effect of "skip placement for this turn").
|
||||
*/
|
||||
public void cancelPiecenPlacement ()
|
||||
{
|
||||
_placingPiecen = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* If we freed up a placeable piecen that we didn't have when we
|
||||
* placed our tile, this can be called to reenable piecen placement.
|
||||
*/
|
||||
public void enablePiecenPlacement ()
|
||||
{
|
||||
_placingPiecen = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the tile to be placed on the board. The tile will be displayed
|
||||
* in the square under the mouse cursor where it can be legally placed
|
||||
* and its orientation will be determined based on the pointer's
|
||||
* proximity to the edges of the target square. When the user clicks
|
||||
* the mouse while the tile is in a placeable position, a
|
||||
* <code>TILE_PLACED</code> command will be dispatched to the
|
||||
* controller in scope. The coordinates and orientation of the tile
|
||||
* will be available by fetching the tile back via {@link
|
||||
* #getPlacedTile}. The tile provided to this method will not be
|
||||
* modified.
|
||||
*
|
||||
* @param tile the new tile to be placed or null if no tile is to
|
||||
* currently be placed.
|
||||
*/
|
||||
public void setTileToBePlaced (AtlantiTile tile)
|
||||
{
|
||||
Log.info("Setting tile to be placed [tile=" + tile + "].");
|
||||
|
||||
// make a copy of this tile so that we can play with it
|
||||
_placingTile = (AtlantiTile)tile.clone();;
|
||||
|
||||
// update our internal state based on this new placing tile
|
||||
if (_placingTile != null) {
|
||||
updatePlacingInfo(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the last tile placed by the user.
|
||||
*/
|
||||
public AtlantiTile getPlacedTile ()
|
||||
{
|
||||
return _placedTile;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void doLayout ()
|
||||
{
|
||||
super.doLayout();
|
||||
|
||||
// compute our translation coordinates based on our size
|
||||
_tx = (getWidth() - TILE_WIDTH * _width)/2;
|
||||
_ty = (getHeight() - TILE_HEIGHT * _height)/2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Causes the supplied tile to be repainted.
|
||||
*/
|
||||
public void repaintTile (AtlantiTile tile)
|
||||
{
|
||||
int offx = _tx + (tile.x + _origX) * TILE_WIDTH;
|
||||
int offy = _ty + (tile.y + _origY) * TILE_HEIGHT;
|
||||
repaint(offx, offy, TILE_WIDTH, TILE_HEIGHT);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void paintComponent (Graphics g)
|
||||
{
|
||||
super.paintComponent(g);
|
||||
|
||||
Graphics2D g2 = (Graphics2D)g;
|
||||
|
||||
// center the tile display if we are bigger than we need to be
|
||||
g.translate(_tx, _ty);
|
||||
|
||||
// iterate over our tiles, painting each of them
|
||||
int tsize = _tiles.size();
|
||||
for (int i = 0; i < tsize; i++) {
|
||||
AtlantiTile tile = (AtlantiTile)_tiles.get(i);
|
||||
tile.paint(g2, _origX, _origY);
|
||||
}
|
||||
|
||||
// if we have a placing tile, draw that one as well
|
||||
if (_placingTile != null && _validPlacement) {
|
||||
// if the current position is valid, draw the placing tile
|
||||
_placingTile.paint(g2, _origX, _origY);
|
||||
|
||||
// draw a green rectangle around the placing tile
|
||||
g.setColor(Color.blue);
|
||||
int sx = (_placingTile.x + _origX) * TILE_WIDTH;
|
||||
int sy = (_placingTile.y + _origY) * TILE_HEIGHT;
|
||||
g.drawRect(sx, sy, TILE_WIDTH-1, TILE_HEIGHT-1);
|
||||
}
|
||||
|
||||
// if we have a recently placed tile, draw that one as well
|
||||
if (_placedTile != null) {
|
||||
// draw the tile
|
||||
_placedTile.paint(g2, _origX, _origY);
|
||||
|
||||
// draw a white rectangle around the placed tile
|
||||
g.setColor(Color.white);
|
||||
int sx = (_placedTile.x + _origX) * TILE_WIDTH;
|
||||
int sy = (_placedTile.y + _origY) * TILE_HEIGHT;
|
||||
g.drawRect(sx, sy, TILE_WIDTH-1, TILE_HEIGHT-1);
|
||||
}
|
||||
|
||||
// draw a white rectangle around the last placed
|
||||
if (_lastPlacedTile != null) {
|
||||
g.setColor(Color.white);
|
||||
int sx = (_lastPlacedTile.x + _origX) * TILE_WIDTH;
|
||||
int sy = (_lastPlacedTile.y + _origY) * TILE_HEIGHT;
|
||||
g.drawRect(sx, sy, TILE_WIDTH-1, TILE_HEIGHT-1);
|
||||
}
|
||||
|
||||
// undo our translations
|
||||
g.translate(-_tx, -_ty);
|
||||
}
|
||||
|
||||
/** Called by our adapter when the mouse moves. */
|
||||
protected void mouseMoved (MouseEvent evt)
|
||||
{
|
||||
// we always want to know about our last mouse coordinates
|
||||
_mouseX = evt.getX() - _tx;
|
||||
_mouseY = evt.getY() - _ty;
|
||||
|
||||
if (_placingTile != null) {
|
||||
// if we have a tile to be placed, update its coordinates (it
|
||||
// will automatically be repainted)
|
||||
updatePlacingInfo(false);
|
||||
|
||||
} else if (_placedTile != null && _placingPiecen) {
|
||||
// if we have a recently placed tile, we're doing piecen
|
||||
// placement; first convert the mouse coords into tile coords
|
||||
int mx = _mouseX - (_placedTile.x + _origX) * TILE_WIDTH;
|
||||
int my = _mouseY - (_placedTile.y + _origY) * TILE_HEIGHT;
|
||||
boolean changed = false;
|
||||
|
||||
// now see if we're inside the placing tile
|
||||
if (mx >= 0 && mx < TILE_WIDTH && my >= 0 && my < TILE_HEIGHT) {
|
||||
int fidx = _placedTile.getFeatureIndex(mx, my);
|
||||
|
||||
// if the feature is not already claimed, we can put a
|
||||
// piece there to indicate that it can be claimed
|
||||
if (_placedTile.claims[fidx] == 0) {
|
||||
if (_placedTile.piecen == null ||
|
||||
_placedTile.piecen.featureIndex != fidx) {
|
||||
Piecen p = new Piecen(_newPiecenColor, 0, 0, fidx);
|
||||
_placedTile.setPiecen(p, null);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
// we may need to clear out a piecen since we've moved
|
||||
if (_placedTile.piecen != null) {
|
||||
_placedTile.clearPiecen();
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// we may need to clear out a piecen since we've moved
|
||||
if (_placedTile.piecen != null) {
|
||||
_placedTile.clearPiecen();
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
repaintTile(_placedTile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Called by our adapter when the mouse is clicked. */
|
||||
protected void mouseClicked (MouseEvent evt)
|
||||
{
|
||||
int modifiers = evt.getModifiers();
|
||||
|
||||
// if this is a right button click, and we're in piecen placing
|
||||
// mode, generate a PLACE_NOTHING notification instead
|
||||
if (_placingPiecen && (modifiers & MouseEvent.BUTTON3_MASK) != 0) {
|
||||
// stop piecen placement
|
||||
_placingPiecen = false;
|
||||
// clear out any placed piecen because we're placing nothing
|
||||
if (_placedTile != null && _placedTile.piecen != null) {
|
||||
_placedTile.piecen = null;
|
||||
repaintTile(_placedTile);
|
||||
}
|
||||
// post the action
|
||||
Controller.postAction(this, PLACE_NOTHING);
|
||||
|
||||
} else {
|
||||
// ignore non-button one presses other than cancel piecen
|
||||
// placement
|
||||
if ((modifiers & MouseEvent.BUTTON1_MASK) == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// if we have a placing tile and it's in a valid position, we want
|
||||
// to dispatch an action letting the controller know that the user
|
||||
// placed it
|
||||
if (_placingTile != null && _validPlacement) {
|
||||
// move the placing tile to the placed tile
|
||||
_placedTile = _placingTile;
|
||||
_placingTile = null;
|
||||
|
||||
// inherit claims on the placed tile
|
||||
TileUtil.inheritClaims(_tiles, _placedTile);
|
||||
|
||||
// post the action
|
||||
Controller.postAction(this, TILE_PLACED);
|
||||
|
||||
// move into placing piecen mode
|
||||
_placingPiecen = true;
|
||||
|
||||
// recompute our dimensions (which will relayout or repaint)
|
||||
computeDimensions();
|
||||
}
|
||||
|
||||
// if we're placing a piecen and the piecen is in a valid
|
||||
// position, we want to dispatch an action letting the controller
|
||||
// know that the user placed it
|
||||
if (_placingPiecen && _placedTile != null &&
|
||||
_placedTile.piecen != null) {
|
||||
// clear out placing piecen mode
|
||||
_placingPiecen = false;
|
||||
|
||||
// post the action
|
||||
Controller.postAction(this, PIECEN_PLACED);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the coordinates and orientation of the placing tile based
|
||||
* on the last known coordinates of the mouse and causes it to be
|
||||
* repainted.
|
||||
*/
|
||||
protected void updatePlacingInfo (boolean force)
|
||||
{
|
||||
boolean updated = false;
|
||||
|
||||
// convert mouse coordinates into tile coordinates and offset them
|
||||
// by the origin
|
||||
int x = divFloor(_mouseX, TILE_WIDTH) - _origX;
|
||||
int y = divFloor(_mouseY, TILE_HEIGHT) - _origY;
|
||||
|
||||
// if these are different than the values currently in the placing
|
||||
// tile, update the tile coordinates
|
||||
if (_placingTile.x != x || _placingTile.y != y || force) {
|
||||
// if we have a valid orientation presently, and we're moving,
|
||||
// we need to clear out the old orientation
|
||||
if (_validPlacement) {
|
||||
repaintTile(_placingTile);
|
||||
}
|
||||
|
||||
// update the coordinates of the tile
|
||||
_placingTile.x = x;
|
||||
_placingTile.y = y;
|
||||
|
||||
// make a note that we moved
|
||||
updated = true;
|
||||
|
||||
// we also need to recompute the valid orientations for the
|
||||
// tile in this new position
|
||||
_validOrients = TileUtil.computeValidOrients(_tiles, _placingTile);
|
||||
|
||||
// if we've changed positions, clear out our valid placement
|
||||
// flag
|
||||
_validPlacement = false;
|
||||
}
|
||||
|
||||
// determine if we should change the orientation based on the
|
||||
// position of the mouse within the tile boundaries
|
||||
int rx = _mouseX % TILE_WIDTH;
|
||||
int ry = _mouseY % TILE_HEIGHT;
|
||||
int orient = coordToOrient(rx, ry);
|
||||
|
||||
// scan for a legal orientation that is closest to our desired
|
||||
// orientation
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int candOrient = (orient+i)%4;
|
||||
if (_validOrients[candOrient]) {
|
||||
if (_placingTile.orientation != candOrient) {
|
||||
_placingTile.orientation = candOrient;
|
||||
// make a note that we moved
|
||||
updated = true;
|
||||
}
|
||||
_validPlacement = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if we now have a valid orientation and something was changed,
|
||||
// we want to repaint at the new tile location
|
||||
if (_validPlacement && updated) {
|
||||
repaintTile(_placingTile);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts mouse coordinates which are relative to a particular tile,
|
||||
* into an orientation based on the position within that tile. A tile
|
||||
* is divided up into four quadrants by lines connecting its four
|
||||
* corners. If the tile is in a quadrant closes to an edge, it is
|
||||
* converted to the orientation corresponding with that edge.
|
||||
*
|
||||
* @param rx the mouse coordinates modulo tile width.
|
||||
* @param ry the mouse coordinates modulo tile height.
|
||||
*
|
||||
* @return the orientation desired for the tile in which the mouse
|
||||
* resides.
|
||||
*/
|
||||
protected int coordToOrient (int rx, int ry)
|
||||
{
|
||||
if (rx > ry) {
|
||||
if (rx > (TILE_HEIGHT - ry)) {
|
||||
return EAST;
|
||||
} else {
|
||||
return NORTH;
|
||||
}
|
||||
} else {
|
||||
if (rx > (TILE_HEIGHT - ry)) {
|
||||
return SOUTH;
|
||||
} else {
|
||||
return WEST;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Divides the two integers returning the floor of the divided value
|
||||
* rather than its truncation. */
|
||||
protected static int divFloor (int value, int divisor)
|
||||
{
|
||||
return (int)Math.floor((double)value/divisor);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public Dimension getPreferredSize ()
|
||||
{
|
||||
if (_tiles.size() == 0) {
|
||||
return new Dimension(100, 100);
|
||||
|
||||
} else {
|
||||
return new Dimension(TILE_WIDTH * _width, TILE_HEIGHT * _height);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines how big we want to be based on where the tiles have been
|
||||
* laid out. This will cause the component to be re-layed out if the
|
||||
* dimensions change or repainted if not.
|
||||
*/
|
||||
protected void computeDimensions ()
|
||||
{
|
||||
int maxX = 0, maxY = 0;
|
||||
int minX = 0, minY = 0;
|
||||
|
||||
// if we have a recently placed tile, start with that one
|
||||
if (_placedTile != null) {
|
||||
minX = maxX = _placedTile.x;
|
||||
minY = maxY = _placedTile.y;
|
||||
}
|
||||
|
||||
// figure out what our boundaries are
|
||||
int tsize = _tiles.size();
|
||||
for (int i = 0; i < tsize; i++) {
|
||||
AtlantiTile tile = (AtlantiTile)_tiles.get(i);
|
||||
if (tile.x > maxX) {
|
||||
maxX = tile.x;
|
||||
} else if (tile.x < minX) {
|
||||
minX = tile.x;
|
||||
}
|
||||
if (tile.y > maxY) {
|
||||
maxY = tile.y;
|
||||
} else if (tile.y < minY) {
|
||||
minY = tile.y;
|
||||
}
|
||||
}
|
||||
|
||||
// spread our bounds out by one
|
||||
minX -= 1; minY -= 1;
|
||||
maxX += 1; maxY += 1;
|
||||
|
||||
// keep track of these to know if we've change dimensions
|
||||
int oldOrigX = _origX, oldOrigY = _origY;
|
||||
int oldWidth = _width, oldHeight = _height;
|
||||
|
||||
// now we can compute our width and the origin offset
|
||||
_origX = -minX;
|
||||
_origY = -minY;
|
||||
_width = maxX - minX + 1;
|
||||
_height = maxY - minY + 1;
|
||||
|
||||
if (_origX != oldOrigX || _origY != oldOrigY ||
|
||||
oldWidth != _width || oldHeight != _height) {
|
||||
// if the dimensions changed, we need to relayout
|
||||
revalidate();
|
||||
}
|
||||
|
||||
// always repaint because revalidation doesn't always seem to
|
||||
// result in a repaint
|
||||
repaint();
|
||||
}
|
||||
|
||||
/** Test code. */
|
||||
public static void main (String[] args)
|
||||
{
|
||||
JFrame frame = new JFrame("Board test");
|
||||
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
AtlantiBoard board = new AtlantiBoard();
|
||||
|
||||
TestDSet set = new TestDSet();
|
||||
set.addTile(new AtlantiTile(CITY_TWO, true, WEST, 0, 0));
|
||||
set.addTile(new AtlantiTile(CITY_TWO, false, WEST, -1, 1));
|
||||
set.addTile(new AtlantiTile(CITY_ONE, false, SOUTH, -1, -1));
|
||||
AtlantiTile zero = new AtlantiTile(CURVED_ROAD, false, WEST, 0, 2);
|
||||
set.addTile(zero);
|
||||
AtlantiTile one = new AtlantiTile(TWO_CITY_TWO, false, NORTH, 0, 1);
|
||||
set.addTile(one);
|
||||
set.addTile(new AtlantiTile(CITY_THREE, false, WEST, 1, 1));
|
||||
set.addTile(new AtlantiTile(CITY_THREE_ROAD, false, EAST, 1, 2));
|
||||
set.addTile(new AtlantiTile(CITY_THREE, false, NORTH, -1, 0));
|
||||
AtlantiTile two = new AtlantiTile(CITY_ONE, false, EAST, -2, 0);
|
||||
set.addTile(two);
|
||||
board.setTiles(set);
|
||||
|
||||
AtlantiTile placing = new AtlantiTile(CITY_TWO, false, NORTH, 0, 0);
|
||||
board.setTileToBePlaced(placing);
|
||||
|
||||
// set a feature group to test propagation
|
||||
List tiles = new ArrayList();
|
||||
CollectionUtil.addAll(tiles, set.entries());
|
||||
Collections.sort(tiles);
|
||||
|
||||
zero.setPiecen(new Piecen(Piecen.GREEN, 0, 0, 2), tiles);
|
||||
one.setPiecen(new Piecen(Piecen.BLUE, 0, 0, 0), tiles);
|
||||
two.setPiecen(new Piecen(Piecen.RED, 0, 0, 1), tiles);
|
||||
|
||||
Log.info("Incomplete road: " +
|
||||
TileUtil.computeFeatureScore(tiles, zero, 2));
|
||||
|
||||
Log.info("Completed city: " +
|
||||
TileUtil.computeFeatureScore(tiles, two, 1));
|
||||
|
||||
Log.info("Incomplete city: " +
|
||||
TileUtil.computeFeatureScore(tiles, one, 2));
|
||||
|
||||
frame.getContentPane().add(board, BorderLayout.CENTER);
|
||||
frame.pack();
|
||||
SwingUtil.centerWindow(frame);
|
||||
frame.show();
|
||||
}
|
||||
|
||||
protected static class TestDSet extends DSet
|
||||
{
|
||||
public void addTile (AtlantiTile tile)
|
||||
{
|
||||
add(tile);
|
||||
}
|
||||
}
|
||||
|
||||
/** A reference to our tile set. */
|
||||
protected ArrayList _tiles = new ArrayList();
|
||||
|
||||
/** The tile currently being placed by the user. */
|
||||
protected AtlantiTile _placingTile;
|
||||
|
||||
/** The last tile being placed by the user. */
|
||||
protected AtlantiTile _placedTile;
|
||||
|
||||
/** The last tile placed on the board via {@link #addTile}. */
|
||||
protected AtlantiTile _lastPlacedTile;
|
||||
|
||||
/** A flag indicating whether or not we're placing a piecen. */
|
||||
protected boolean _placingPiecen = false;
|
||||
|
||||
/** Whether or not the current position and orientation of the placing
|
||||
* tile is valid. */
|
||||
protected boolean _validPlacement = false;
|
||||
|
||||
/** An array indicating which of the four directions are valid
|
||||
* placements based on the current position of the placing tile. */
|
||||
protected boolean[] _validOrients;
|
||||
|
||||
/** The color to use when creating new piecens. */
|
||||
protected int _newPiecenColor = Piecen.BLUE;
|
||||
|
||||
/** Our render offset in pixels. */
|
||||
protected int _tx, _ty;
|
||||
|
||||
/** The offset in tile coordinates of the origin. */
|
||||
protected int _origX, _origY;
|
||||
|
||||
/** The width and height of the board in tile coordinates. */
|
||||
protected int _width, _height;
|
||||
|
||||
/** The last known position of the mouse. */
|
||||
protected int _mouseX, _mouseY;
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
//
|
||||
// $Id: AtlantiConfigurator.java,v 1.1 2002/12/12 05:51:53 mdb Exp $
|
||||
|
||||
package com.samskivert.atlanti.client;
|
||||
|
||||
import com.samskivert.swing.SimpleSlider;
|
||||
import com.samskivert.swing.VGroupLayout;
|
||||
|
||||
import com.threerings.micasa.lobby.table.TableGameConfigurator;
|
||||
|
||||
import com.samskivert.atlanti.data.AtlantiConfig;
|
||||
|
||||
/**
|
||||
* Provides a user interface for configuring a game.
|
||||
*/
|
||||
public class AtlantiConfigurator extends TableGameConfigurator
|
||||
{
|
||||
// documentation inherited
|
||||
protected void createConfigInterface ()
|
||||
{
|
||||
super.createConfigInterface();
|
||||
|
||||
// _boardSize = new SimpleSlider("Board size:", 16, 48, 32);
|
||||
// add(_boardSize, VGroupLayout.FIXED);
|
||||
// _handSize = new SimpleSlider("Hand size:", 2, 5, 5);
|
||||
// add(_handSize, VGroupLayout.FIXED);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected void gotGameConfig ()
|
||||
{
|
||||
super.gotGameConfig();
|
||||
_vconfig = (AtlantiConfig)_config;
|
||||
|
||||
// // configure our elements
|
||||
// _boardSize.setValue(_vconfig.boardWidth);
|
||||
// _handSize.setValue(_vconfig.handSize);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected void flushGameConfig ()
|
||||
{
|
||||
super.flushGameConfig();
|
||||
|
||||
// // configure our elements
|
||||
// _vconfig.boardWidth = _boardSize.getValue();
|
||||
// _vconfig.boardHeight = _boardSize.getValue();
|
||||
// _vconfig.handSize = _handSize.getValue();
|
||||
}
|
||||
|
||||
protected AtlantiConfig _vconfig;
|
||||
// protected SimpleSlider _boardSize;
|
||||
// protected SimpleSlider _handSize;
|
||||
}
|
||||
@@ -1,223 +0,0 @@
|
||||
//
|
||||
// $Id
|
||||
|
||||
package com.samskivert.atlanti.client;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import com.samskivert.util.ListUtil;
|
||||
import com.threerings.util.Name;
|
||||
|
||||
import com.threerings.presents.dobj.AttributeChangedEvent;
|
||||
import com.threerings.presents.dobj.DSet;
|
||||
import com.threerings.presents.dobj.EntryAddedEvent;
|
||||
import com.threerings.presents.dobj.EntryRemovedEvent;
|
||||
import com.threerings.presents.dobj.EntryUpdatedEvent;
|
||||
import com.threerings.presents.dobj.MessageEvent;
|
||||
import com.threerings.presents.dobj.SetListener;
|
||||
|
||||
import com.threerings.crowd.data.BodyObject;
|
||||
import com.threerings.crowd.data.PlaceObject;
|
||||
import com.threerings.crowd.client.PlaceView;
|
||||
|
||||
import com.threerings.parlor.game.GameController;
|
||||
import com.threerings.parlor.turn.TurnGameController;
|
||||
import com.threerings.parlor.turn.TurnGameControllerDelegate;
|
||||
import com.threerings.parlor.util.ParlorContext;
|
||||
|
||||
import com.threerings.micasa.util.MiCasaContext;
|
||||
|
||||
import com.samskivert.atlanti.Log;
|
||||
import com.samskivert.atlanti.data.AtlantiCodes;
|
||||
import com.samskivert.atlanti.data.AtlantiObject;
|
||||
import com.samskivert.atlanti.data.AtlantiTile;
|
||||
import com.samskivert.atlanti.data.Piecen;
|
||||
import com.samskivert.atlanti.util.TileUtil;
|
||||
|
||||
/**
|
||||
* The main coordinator of user interface activities on the client-side of
|
||||
* the game.
|
||||
*/
|
||||
public class AtlantiController extends GameController
|
||||
implements TurnGameController, AtlantiCodes, SetListener
|
||||
{
|
||||
/**
|
||||
* Creates our controller and prepares it for operation.
|
||||
*/
|
||||
public AtlantiController ()
|
||||
{
|
||||
addDelegate(_delegate = new TurnGameControllerDelegate(this));
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected void didInit ()
|
||||
{
|
||||
super.didInit();
|
||||
|
||||
// get a handle on our body object
|
||||
_self = (BodyObject)_ctx.getClient().getClientObject();
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected PlaceView createPlaceView ()
|
||||
{
|
||||
_panel = new AtlantiPanel((MiCasaContext)_ctx, this);
|
||||
return _panel;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void willEnterPlace (PlaceObject plobj)
|
||||
{
|
||||
super.willEnterPlace(plobj);
|
||||
|
||||
// get a casted reference to our game object
|
||||
_venobj = (AtlantiObject)plobj;
|
||||
|
||||
// find out what our index is and use that as our piecen color
|
||||
_selfIndex = ListUtil.indexOfEqual(_venobj.players, _self.username);
|
||||
if (_selfIndex != -1) {
|
||||
// use our player index as the piecen color directly
|
||||
_panel.board.setNewPiecenColor(_selfIndex);
|
||||
}
|
||||
|
||||
// grab the tiles and piecens from the game object and configure
|
||||
// the board with them
|
||||
_panel.board.setTiles(_venobj.tiles);
|
||||
_panel.board.setPiecens(_venobj.piecens);
|
||||
|
||||
// if it's our turn, set the tile to be placed
|
||||
if (_delegate.isOurTurn()) {
|
||||
_panel.board.setTileToBePlaced(_venobj.currentTile);
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void turnDidChange (Name turnHolder)
|
||||
{
|
||||
// if it's our turn, set the tile to be placed
|
||||
if (turnHolder.equals(_self.username)) {
|
||||
_panel.board.setTileToBePlaced(_venobj.currentTile);
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void attributeChanged (AttributeChangedEvent event)
|
||||
{
|
||||
super.attributeChanged(event);
|
||||
|
||||
// handle the setting of the board state
|
||||
if (event.getName().equals(AtlantiObject.TILES)) {
|
||||
_panel.board.setTiles(_venobj.tiles);
|
||||
|
||||
} else if (event.getName().equals(AtlantiObject.PIECENS)) {
|
||||
_panel.board.setPiecens(_venobj.piecens);
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void entryAdded (EntryAddedEvent event)
|
||||
{
|
||||
// we care about additions to TILES and PIECENS
|
||||
if (event.getName().equals(AtlantiObject.TILES)) {
|
||||
// a tile was added, add it to the board
|
||||
AtlantiTile tile = (AtlantiTile)event.getEntry();
|
||||
_panel.board.addTile(tile);
|
||||
|
||||
} else if (event.getName().equals(AtlantiObject.PIECENS)) {
|
||||
// a piecen was added, place it on the board
|
||||
Piecen piecen = (Piecen)event.getEntry();
|
||||
_panel.board.placePiecen(piecen);
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void entryUpdated (EntryUpdatedEvent event)
|
||||
{
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void entryRemoved (EntryRemovedEvent event)
|
||||
{
|
||||
if (event.getName().equals(AtlantiObject.PIECENS)) {
|
||||
// a piecen was removed, update the board
|
||||
_panel.board.clearPiecen(event.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public boolean handleAction (ActionEvent action)
|
||||
{
|
||||
if (action.getActionCommand().equals(TILE_PLACED)) {
|
||||
AtlantiTile tile = _panel.board.getPlacedTile();
|
||||
|
||||
// the user placed the tile into a valid location. grab the
|
||||
// placed tile from the board and submit it to the server
|
||||
Object[] args = new Object[] { tile };
|
||||
MessageEvent mevt = new MessageEvent(
|
||||
_venobj.getOid(), PLACE_TILE_REQUEST, args);
|
||||
_ctx.getDObjectManager().postEvent(mevt);
|
||||
|
||||
// if we have no piecens to place or if there are no unclaimed
|
||||
// features on the placed tile, we immediately disable piecen
|
||||
// placement in the board and expect that the server will end
|
||||
// our turn
|
||||
int pcount = TileUtil.countPiecens(_venobj.piecens, _selfIndex);
|
||||
if (pcount >= PIECENS_PER_PLAYER || !tile.hasUnclaimedFeature()) {
|
||||
_panel.board.cancelPiecenPlacement();
|
||||
_panel.noplace.setEnabled(false);
|
||||
|
||||
} else {
|
||||
// otherwise, enable the noplace button
|
||||
_panel.noplace.setEnabled(true);
|
||||
}
|
||||
|
||||
} else if (action.getActionCommand().equals(PIECEN_PLACED)) {
|
||||
// the user placed a piecen on the tile. grab the piecen from
|
||||
// the placed tile and submit it to the server
|
||||
Object[] args = new Object[] {
|
||||
_panel.board.getPlacedTile().piecen };
|
||||
MessageEvent mevt = new MessageEvent(
|
||||
_venobj.getOid(), PLACE_PIECEN_REQUEST, args);
|
||||
_ctx.getDObjectManager().postEvent(mevt);
|
||||
|
||||
// disable the noplace button
|
||||
_panel.noplace.setEnabled(false);
|
||||
|
||||
} else if (action.getActionCommand().equals(PLACE_NOTHING)) {
|
||||
// turn off piecen placement in the board
|
||||
_panel.board.cancelPiecenPlacement();
|
||||
|
||||
// the user doesn't want to place anything this turn. send a
|
||||
// place nothing request to the server
|
||||
MessageEvent mevt = new MessageEvent(
|
||||
_venobj.getOid(), PLACE_NOTHING_REQUEST, null);
|
||||
_ctx.getDObjectManager().postEvent(mevt);
|
||||
|
||||
// disable the noplace button
|
||||
_panel.noplace.setEnabled(false);
|
||||
|
||||
} else if (action.getActionCommand().equals(BACK_TO_LOBBY)) {
|
||||
// bail on out
|
||||
_ctx.getLocationDirector().moveBack();
|
||||
|
||||
} else {
|
||||
return super.handleAction(action);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Our turn game delegate. */
|
||||
protected TurnGameControllerDelegate _delegate;
|
||||
|
||||
/** A reference to our game panel. */
|
||||
protected AtlantiPanel _panel;
|
||||
|
||||
/** A reference to our game panel. */
|
||||
protected AtlantiObject _venobj;
|
||||
|
||||
/** A reference to our body object. */
|
||||
protected BodyObject _self;
|
||||
|
||||
/** Our player index or -1 if we're not a player. */
|
||||
protected int _selfIndex;
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
//
|
||||
// $Id
|
||||
|
||||
package com.samskivert.atlanti.client;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.Frame;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.AncestorEvent;
|
||||
import javax.swing.event.AncestorListener;
|
||||
|
||||
import com.samskivert.swing.Controller;
|
||||
import com.samskivert.swing.ControllerProvider;
|
||||
import com.samskivert.swing.HGroupLayout;
|
||||
import com.samskivert.swing.VGroupLayout;
|
||||
|
||||
import com.threerings.media.image.ImageManager;
|
||||
import com.threerings.media.tile.TileManager;
|
||||
import com.threerings.resource.ResourceManager;
|
||||
|
||||
import com.threerings.crowd.data.PlaceObject;
|
||||
import com.threerings.crowd.client.PlaceView;
|
||||
|
||||
import com.threerings.micasa.client.ChatPanel;
|
||||
import com.threerings.micasa.util.MiCasaContext;
|
||||
|
||||
import com.samskivert.atlanti.Log;
|
||||
import com.samskivert.atlanti.data.AtlantiCodes;
|
||||
import com.samskivert.atlanti.data.AtlantiTile;
|
||||
import com.samskivert.atlanti.util.PiecenUtil;
|
||||
|
||||
/**
|
||||
* The top-level user interface component for the game display.
|
||||
*/
|
||||
public class AtlantiPanel extends JPanel
|
||||
implements PlaceView, ControllerProvider, AtlantiCodes
|
||||
{
|
||||
/** A reference to the board that is accessible to the controller. */
|
||||
public AtlantiBoard board;
|
||||
|
||||
/** A reference to our _noplace button. */
|
||||
public JButton noplace;
|
||||
|
||||
/**
|
||||
* Constructs a new game display.
|
||||
*/
|
||||
public AtlantiPanel (MiCasaContext ctx, AtlantiController controller)
|
||||
{
|
||||
// give ourselves a wee bit of a border
|
||||
setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
|
||||
|
||||
HGroupLayout gl = new HGroupLayout(HGroupLayout.STRETCH);
|
||||
gl.setOffAxisPolicy(HGroupLayout.STRETCH);
|
||||
setLayout(gl);
|
||||
|
||||
// create the board
|
||||
board = new AtlantiBoard();
|
||||
|
||||
// create a scroll area to contain the board
|
||||
JScrollPane scrolly = new JScrollPane(board);
|
||||
add(scrolly);
|
||||
|
||||
// create our side panel
|
||||
VGroupLayout sgl = new VGroupLayout(VGroupLayout.STRETCH);
|
||||
sgl.setOffAxisPolicy(VGroupLayout.STRETCH);
|
||||
sgl.setJustification(VGroupLayout.TOP);
|
||||
JPanel sidePanel = new JPanel(sgl);
|
||||
|
||||
// add a big fat label because we love it!
|
||||
JLabel vlabel = new JLabel("Atlantissonne!");
|
||||
vlabel.setFont(new Font("Helvetica", Font.BOLD, 24));
|
||||
vlabel.setForeground(Color.black);
|
||||
sidePanel.add(vlabel, VGroupLayout.FIXED);
|
||||
|
||||
// add a player info view to the side panel
|
||||
sidePanel.add(new JLabel("Scores:"), VGroupLayout.FIXED);
|
||||
sidePanel.add(new PlayerInfoView(), VGroupLayout.FIXED);
|
||||
|
||||
// add a turn indicator to the side panel
|
||||
sidePanel.add(new JLabel("Current turn:"), VGroupLayout.FIXED);
|
||||
sidePanel.add(new TurnIndicatorView(), VGroupLayout.FIXED);
|
||||
|
||||
// add a "place nothing" button
|
||||
noplace = new JButton("Place nothing");
|
||||
noplace.setEnabled(false);
|
||||
noplace.setActionCommand(PLACE_NOTHING);
|
||||
noplace.addActionListener(Controller.DISPATCHER);
|
||||
sidePanel.add(noplace, VGroupLayout.FIXED);
|
||||
|
||||
// add a chat box
|
||||
ChatPanel chat = new ChatPanel(ctx);
|
||||
chat.removeSendButton();
|
||||
sidePanel.add(chat);
|
||||
|
||||
// add a "back" button
|
||||
JButton back = new JButton("Back to lobby");
|
||||
back.setActionCommand(BACK_TO_LOBBY);
|
||||
back.addActionListener(Controller.DISPATCHER);
|
||||
sidePanel.add(back, VGroupLayout.FIXED);
|
||||
|
||||
// add our side panel to the main display
|
||||
add(sidePanel, HGroupLayout.FIXED);
|
||||
|
||||
// we'll need this later to provide it
|
||||
_controller = controller;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void addNotify ()
|
||||
{
|
||||
super.addNotify();
|
||||
|
||||
// we can't create our image manager until we have access to our
|
||||
// containing frame
|
||||
JRootPane rpane = getRootPane();
|
||||
ImageManager imgr = new ImageManager(_rmgr, rpane);
|
||||
TileManager tmgr = new TileManager(imgr);
|
||||
AtlantiTile.setManagers(imgr, tmgr);
|
||||
PiecenUtil.init(tmgr);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void willEnterPlace (PlaceObject plobj)
|
||||
{
|
||||
Log.info("Panel entered place.");
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void didLeavePlace (PlaceObject plobj)
|
||||
{
|
||||
Log.info("Panel left place.");
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public Controller getController ()
|
||||
{
|
||||
return _controller;
|
||||
}
|
||||
|
||||
/** A reference to our controller that we need to implement the {@link
|
||||
* ControllerProvider} interface. */
|
||||
protected AtlantiController _controller;
|
||||
|
||||
// this stuff is all a bit of a hack right now. by all rights, the
|
||||
// MiCasa game app should set up the resource manager, because it
|
||||
// knows about that sort of stuff, and make it available via the
|
||||
// MiCasa context and we may have some better place for the tile
|
||||
// manager to live. but it's late and i want to get this working, so
|
||||
// fooey.
|
||||
|
||||
/** Our resource manager. */
|
||||
protected static ResourceManager _rmgr = new ResourceManager("rsrc");
|
||||
}
|
||||
@@ -1,170 +0,0 @@
|
||||
//
|
||||
// $Id: PlayerInfoView.java,v 1.5 2002/12/12 05:51:54 mdb Exp $
|
||||
|
||||
package com.samskivert.atlanti.client;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.GridBagConstraints;
|
||||
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import com.threerings.util.Name;
|
||||
|
||||
import com.threerings.presents.dobj.AttributeChangeListener;
|
||||
import com.threerings.presents.dobj.AttributeChangedEvent;
|
||||
import com.threerings.presents.dobj.SetListener;
|
||||
import com.threerings.presents.dobj.EntryAddedEvent;
|
||||
import com.threerings.presents.dobj.EntryUpdatedEvent;
|
||||
import com.threerings.presents.dobj.EntryRemovedEvent;
|
||||
|
||||
import com.threerings.crowd.client.PlaceView;
|
||||
import com.threerings.crowd.data.PlaceObject;
|
||||
|
||||
import com.samskivert.atlanti.data.AtlantiCodes;
|
||||
import com.samskivert.atlanti.data.AtlantiObject;
|
||||
import com.samskivert.atlanti.data.Feature;
|
||||
import com.samskivert.atlanti.util.TileUtil;
|
||||
|
||||
/**
|
||||
* Displays each of the players in the game, their piece color and their
|
||||
* score.
|
||||
*/
|
||||
public class PlayerInfoView
|
||||
extends JPanel
|
||||
implements PlaceView, AttributeChangeListener, SetListener
|
||||
{
|
||||
/**
|
||||
* Constructs a new player info panel, ready for insertion into the
|
||||
* game panel.
|
||||
*/
|
||||
public PlayerInfoView ()
|
||||
{
|
||||
setLayout(new GridBagLayout());
|
||||
|
||||
// we don't add our player info until we know how many players are
|
||||
// in the game (which we find out once we enter the game room)
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void willEnterPlace (PlaceObject plobj)
|
||||
{
|
||||
// we want to grab a reference to the game object and add
|
||||
// ourselves as an attribute change listener
|
||||
_atlobj = (AtlantiObject)plobj;
|
||||
_atlobj.addListener(this);
|
||||
|
||||
// we need score and piecen labels arrays so that we can keep
|
||||
// track of per player information
|
||||
_scoreLabels = new JLabel[_atlobj.players.length];
|
||||
_piecenLabels = new JLabel[_atlobj.players.length];
|
||||
|
||||
// now that we're here, we can add an entry for every player
|
||||
for (int i = 0; i < _atlobj.players.length; i++) {
|
||||
addPlayer(i, _atlobj.players[i]);
|
||||
}
|
||||
|
||||
// if we have scores, update them
|
||||
if (_atlobj.scores != null) {
|
||||
updateScores();
|
||||
// and the piecen count
|
||||
updatePiecenCount();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a player to the display.
|
||||
*/
|
||||
protected void addPlayer (int idx, Name username)
|
||||
{
|
||||
GridBagConstraints c = new GridBagConstraints();
|
||||
|
||||
// create a label for their username
|
||||
c.fill = GridBagConstraints.HORIZONTAL;
|
||||
c.weightx = 1.0; // use up extra space on this label
|
||||
JLabel unlabel = new JLabel(username.toString());
|
||||
unlabel.setForeground(Feature.PIECEN_COLOR_MAP[idx]);
|
||||
add(unlabel, c);
|
||||
|
||||
// create a label for their score
|
||||
c.weightx = 0.0; // size label to its preferred width
|
||||
c.ipadx = 5; // 5 pixels between this label and its neighbors
|
||||
c.fill = GridBagConstraints.NONE;
|
||||
_scoreLabels[idx] = new JLabel("0");
|
||||
_scoreLabels[idx].setForeground(Color.black);
|
||||
add(_scoreLabels[idx], c);
|
||||
|
||||
// create a label for their piecen count
|
||||
c.gridwidth = GridBagConstraints.REMAINDER;
|
||||
c.ipadx = 0; // turn off padding
|
||||
_piecenLabels[idx] = new JLabel("(0)");
|
||||
_piecenLabels[idx].setForeground(Feature.PIECEN_COLOR_MAP[idx]);
|
||||
add(_piecenLabels[idx], c);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void didLeavePlace (PlaceObject plobj)
|
||||
{
|
||||
// remove our listening self
|
||||
_atlobj.removeListener(this);
|
||||
_atlobj = null;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void attributeChanged (AttributeChangedEvent event)
|
||||
{
|
||||
// we care about the scores (which change)
|
||||
if (event.getName().equals(AtlantiObject.SCORES)) {
|
||||
updateScores();
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void entryAdded (EntryAddedEvent event)
|
||||
{
|
||||
updatePiecenCount();
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void entryUpdated (EntryUpdatedEvent event)
|
||||
{
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void entryRemoved (EntryRemovedEvent event)
|
||||
{
|
||||
updatePiecenCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the scores from the game object and updates the view.
|
||||
*/
|
||||
protected void updateScores ()
|
||||
{
|
||||
for (int i = 0; i < _atlobj.scores.length; i++) {
|
||||
_scoreLabels[i].setText(Integer.toString(_atlobj.scores[i]));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the count of remaining piecens for all of the players.
|
||||
*/
|
||||
protected void updatePiecenCount ()
|
||||
{
|
||||
for (int i = 0; i < _atlobj.scores.length; i++) {
|
||||
int pcount = TileUtil.countPiecens(_atlobj.piecens, i);
|
||||
int pleft = AtlantiCodes.PIECENS_PER_PLAYER - pcount;
|
||||
_piecenLabels[i].setText("(" + pleft + ")");
|
||||
}
|
||||
}
|
||||
|
||||
/** A reference to the game object. */
|
||||
protected AtlantiObject _atlobj;
|
||||
|
||||
/** References to our score label components. */
|
||||
protected JLabel[] _scoreLabels;
|
||||
|
||||
/** References to our piecen label components. */
|
||||
protected JLabel[] _piecenLabels;
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
//
|
||||
// $Id: TileLabel.java,v 1.2 2002/12/12 05:51:54 mdb Exp $
|
||||
|
||||
package com.samskivert.atlanti.client;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
|
||||
import com.samskivert.atlanti.data.AtlantiTile;
|
||||
import com.samskivert.atlanti.data.TileCodes;
|
||||
|
||||
/**
|
||||
* Displays a single tile in a Swing component.
|
||||
*/
|
||||
public class TileLabel extends JComponent
|
||||
implements TileCodes
|
||||
{
|
||||
/**
|
||||
* Configures the component to display the specified tile.
|
||||
*
|
||||
* @param tile a reference to the tile to display or null if no tile
|
||||
* should be displayed.
|
||||
*/
|
||||
public void setTile (AtlantiTile tile)
|
||||
{
|
||||
_tile = tile;
|
||||
repaint();
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void paintComponent (Graphics g)
|
||||
{
|
||||
super.paintComponent(g);
|
||||
|
||||
// simply paint the tile if we have one
|
||||
if (_tile != null) {
|
||||
_tile.paint((Graphics2D)g, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public Dimension getPreferredSize ()
|
||||
{
|
||||
return new Dimension(TILE_WIDTH, TILE_HEIGHT);
|
||||
}
|
||||
|
||||
/** The tile we are displaying. */
|
||||
protected AtlantiTile _tile;
|
||||
}
|
||||
@@ -1,140 +0,0 @@
|
||||
//
|
||||
// $Id: TurnIndicatorView.java,v 1.5 2002/12/12 06:07:49 mdb Exp $
|
||||
|
||||
package com.samskivert.atlanti.client;
|
||||
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import com.samskivert.swing.VGroupLayout;
|
||||
|
||||
import com.threerings.presents.dobj.AttributeChangeListener;
|
||||
import com.threerings.presents.dobj.AttributeChangedEvent;
|
||||
|
||||
import com.threerings.crowd.data.PlaceObject;
|
||||
import com.threerings.crowd.client.PlaceView;
|
||||
|
||||
import com.samskivert.atlanti.data.AtlantiObject;
|
||||
|
||||
/**
|
||||
* Displays who the current turn holder is as well as the tile they are
|
||||
* currently placing.
|
||||
*/
|
||||
public class TurnIndicatorView extends JPanel
|
||||
implements PlaceView, AttributeChangeListener
|
||||
{
|
||||
/**
|
||||
* Creates a new turn indicator view which in turn creates its
|
||||
* subcomponents.
|
||||
*/
|
||||
public TurnIndicatorView ()
|
||||
{
|
||||
setLayout(new VGroupLayout());
|
||||
|
||||
// add our turn holder display
|
||||
_whoLabel = new JLabel();
|
||||
add(_whoLabel);
|
||||
|
||||
// and add our tile display
|
||||
_tileLabel = new TileLabel();
|
||||
add(_tileLabel);
|
||||
|
||||
// and add a tile's remaining label
|
||||
_countLabel = new JLabel();
|
||||
add(_countLabel);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void willEnterPlace (PlaceObject plobj)
|
||||
{
|
||||
// we want to grab a reference to the game object and add
|
||||
// ourselves as an attribute change listener
|
||||
_atlobj = (AtlantiObject)plobj;
|
||||
_atlobj.addListener(this);
|
||||
|
||||
// update our displays
|
||||
updateCurrentTile();
|
||||
updateGameState();
|
||||
updateTurnHolder();
|
||||
updateRemainingTiles();
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void didLeavePlace (PlaceObject plobj)
|
||||
{
|
||||
// remove our listening self
|
||||
_atlobj.removeListener(this);
|
||||
_atlobj = null;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void attributeChanged (AttributeChangedEvent event)
|
||||
{
|
||||
if (event.getName().equals(AtlantiObject.CURRENT_TILE)) {
|
||||
// update the current tile display
|
||||
updateCurrentTile();
|
||||
|
||||
} else if (event.getName().equals(AtlantiObject.STATE)) {
|
||||
// update the game state display
|
||||
updateGameState();
|
||||
// update the tiles remaining
|
||||
updateRemainingTiles();
|
||||
|
||||
} else if (event.getName().equals(AtlantiObject.TURN_HOLDER)) {
|
||||
// update the turn holder
|
||||
updateTurnHolder();
|
||||
|
||||
// update the tiles remaining when the turn changes
|
||||
updateRemainingTiles();
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateGameState ()
|
||||
{
|
||||
switch (_atlobj.state) {
|
||||
case AtlantiObject.AWAITING_PLAYERS:
|
||||
_whoLabel.setText("Awaiting players...");
|
||||
_tileLabel.setTile(null);
|
||||
break;
|
||||
case AtlantiObject.GAME_OVER:
|
||||
_whoLabel.setText("Game over.");
|
||||
_tileLabel.setTile(null);
|
||||
break;
|
||||
case AtlantiObject.CANCELLED:
|
||||
_whoLabel.setText("Cancelled.");
|
||||
_tileLabel.setTile(null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateTurnHolder ()
|
||||
{
|
||||
if (_atlobj.state == AtlantiObject.IN_PLAY) {
|
||||
_whoLabel.setText(_atlobj.turnHolder.toString());
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateCurrentTile ()
|
||||
{
|
||||
// display the tile to be placed
|
||||
_tileLabel.setTile(_atlobj.currentTile);
|
||||
}
|
||||
|
||||
protected void updateRemainingTiles ()
|
||||
{
|
||||
_countLabel.setText("Tiles remaining: " +
|
||||
Math.max(71-_atlobj.tiles.size(), 0));
|
||||
}
|
||||
|
||||
/** The label displaying whose turn it is. */
|
||||
protected JLabel _whoLabel;
|
||||
|
||||
/** The label displaying the tile to be placed. */
|
||||
protected TileLabel _tileLabel;
|
||||
|
||||
/** The label displaying the number of tiles remaining. */
|
||||
protected JLabel _countLabel;
|
||||
|
||||
/** A reference to the game object. */
|
||||
protected AtlantiObject _atlobj;
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
//
|
||||
// $Id: AtlantiCodes.java,v 1.6 2002/12/12 05:51:54 mdb Exp $
|
||||
|
||||
package com.samskivert.atlanti.data;
|
||||
|
||||
/**
|
||||
* Constants used by the Atlanti game code.
|
||||
*/
|
||||
public interface AtlantiCodes
|
||||
{
|
||||
/** The message bundle identifier for translation messages. */
|
||||
public static final String ATLANTI_MESSAGE_BUNDLE = "atlanti";
|
||||
|
||||
/** The number of piecens provided to each player. */
|
||||
public static final int PIECENS_PER_PLAYER = 7;
|
||||
|
||||
/** The name of the command posted by the {@link AtlantiBoard} when
|
||||
* the user places a tile into a valid position. */
|
||||
public static final String TILE_PLACED = "tile_placed";
|
||||
|
||||
/** The name of the command posted by the {@link AtlantiBoard} when
|
||||
* the user places a piecen onto an unclaimed feature. */
|
||||
public static final String PIECEN_PLACED = "piecen_placed";
|
||||
|
||||
/** The name of the command posted by the "place nothing" button in
|
||||
* the side bar. */
|
||||
public static final String PLACE_NOTHING = "place_nothing";
|
||||
|
||||
/** The message submitted by the client to the server when they have
|
||||
* chosen where they wish to place their tile. */
|
||||
public static final String PLACE_TILE_REQUEST = "place_tile";
|
||||
|
||||
/** The message submitted by the client to the server when they have
|
||||
* chosen where they wish to place their piecen. */
|
||||
public static final String PLACE_PIECEN_REQUEST = "place_piecen";
|
||||
|
||||
/** The message submitted by the client to the server when they decide
|
||||
* that they don't want to (or can't) place any piecen this turn. */
|
||||
public static final String PLACE_NOTHING_REQUEST = "place_nothing";
|
||||
|
||||
/** The name of the command posted by the "Back to lobby" button in
|
||||
* the side bar. */
|
||||
public static final String BACK_TO_LOBBY = "back_to_lobby";
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
//
|
||||
// $Id: AtlantiConfig.java,v 1.4 2002/12/12 05:51:54 mdb Exp $
|
||||
|
||||
package com.samskivert.atlanti.data;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.threerings.io.ObjectInputStream;
|
||||
import com.threerings.io.ObjectOutputStream;
|
||||
|
||||
import com.threerings.parlor.data.TableConfig;
|
||||
import com.threerings.parlor.game.GameConfig;
|
||||
|
||||
import com.samskivert.atlanti.client.AtlantiConfigurator;
|
||||
import com.samskivert.atlanti.client.AtlantiController;
|
||||
|
||||
/**
|
||||
* Describes the configuration parameters for the game.
|
||||
*/
|
||||
public class AtlantiConfig extends GameConfig
|
||||
implements TableConfig
|
||||
{
|
||||
// documentation inherited
|
||||
public Class getControllerClass ()
|
||||
{
|
||||
return AtlantiController.class;
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public Class getConfiguratorClass ()
|
||||
{
|
||||
return AtlantiConfigurator.class;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public String getManagerClassName ()
|
||||
{
|
||||
return "com.samskivert.atlanti.server.AtlantiManager";
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public int getMinimumPlayers ()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public int getMaximumPlayers ()
|
||||
{
|
||||
return 5;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public int getDesiredPlayers ()
|
||||
{
|
||||
return _desiredPlayers;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void setDesiredPlayers (int desiredPlayers)
|
||||
{
|
||||
_desiredPlayers = desiredPlayers;
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void writeObject (ObjectOutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
out.defaultWriteObject();
|
||||
out.writeInt(_desiredPlayers);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void readObject (ObjectInputStream in)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
in.defaultReadObject();
|
||||
_desiredPlayers = in.readInt();
|
||||
}
|
||||
|
||||
/** The desired number of players for this game or -1 if there is no
|
||||
* specific desired number of players. */
|
||||
protected int _desiredPlayers;
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
//
|
||||
// $Id: AtlantiObject.dobj,v 1.2 2002/12/12 05:51:54 mdb Exp $
|
||||
|
||||
package com.samskivert.atlanti.data;
|
||||
|
||||
import com.threerings.presents.dobj.DSet;
|
||||
import com.threerings.util.Name;
|
||||
|
||||
import com.threerings.parlor.game.GameObject;
|
||||
import com.threerings.parlor.turn.TurnGameObject;
|
||||
|
||||
/**
|
||||
* The distributed object used to maintain state for the game.
|
||||
*/
|
||||
public class AtlantiObject extends GameObject
|
||||
implements TurnGameObject
|
||||
{
|
||||
/** The username of the current turn holder. */
|
||||
public Name turnHolder;
|
||||
|
||||
/** A set containing all of the tiles that are in play in this
|
||||
* game. */
|
||||
public DSet tiles = new DSet();
|
||||
|
||||
/** The tile being placed by the current turn holder. This value is
|
||||
* only valid while it is someone's turn. */
|
||||
public AtlantiTile currentTile = AtlantiTile.STARTING_TILE;
|
||||
|
||||
/** A set containing all of the piecens that are placed on the
|
||||
* board. */
|
||||
public DSet piecens = new DSet();
|
||||
|
||||
/** The scores for each player. */
|
||||
public int[] scores;
|
||||
|
||||
// documentation inherited from interface
|
||||
public Name[] getPlayers ()
|
||||
{
|
||||
return players;
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public String getTurnHolderFieldName ()
|
||||
{
|
||||
return TURN_HOLDER;
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public Name getTurnHolder ()
|
||||
{
|
||||
return turnHolder;
|
||||
}
|
||||
}
|
||||
@@ -1,216 +0,0 @@
|
||||
//
|
||||
// $Id: AtlantiObject.java,v 1.10 2003/03/23 02:22:51 mdb Exp $
|
||||
|
||||
package com.samskivert.atlanti.data;
|
||||
|
||||
import com.threerings.presents.dobj.DSet;
|
||||
import com.threerings.util.Name;
|
||||
|
||||
import com.threerings.parlor.game.GameObject;
|
||||
import com.threerings.parlor.turn.TurnGameObject;
|
||||
|
||||
/**
|
||||
* The distributed object used to maintain state for the game.
|
||||
*/
|
||||
public class AtlantiObject extends GameObject
|
||||
implements TurnGameObject
|
||||
{
|
||||
/** The field name of the <code>turnHolder</code> field. */
|
||||
public static final String TURN_HOLDER = "turnHolder";
|
||||
|
||||
/** The field name of the <code>tiles</code> field. */
|
||||
public static final String TILES = "tiles";
|
||||
|
||||
/** The field name of the <code>currentTile</code> field. */
|
||||
public static final String CURRENT_TILE = "currentTile";
|
||||
|
||||
/** The field name of the <code>piecens</code> field. */
|
||||
public static final String PIECENS = "piecens";
|
||||
|
||||
/** The field name of the <code>scores</code> field. */
|
||||
public static final String SCORES = "scores";
|
||||
|
||||
/** The username of the current turn holder. */
|
||||
public Name turnHolder;
|
||||
|
||||
/** A set containing all of the tiles that are in play in this
|
||||
* game. */
|
||||
public DSet tiles = new DSet();
|
||||
|
||||
/** The tile being placed by the current turn holder. This value is
|
||||
* only valid while it is someone's turn. */
|
||||
public AtlantiTile currentTile = AtlantiTile.STARTING_TILE;
|
||||
|
||||
/** A set containing all of the piecens that are placed on the
|
||||
* board. */
|
||||
public DSet piecens = new DSet();
|
||||
|
||||
/** The scores for each player. */
|
||||
public int[] scores;
|
||||
|
||||
// documentation inherited from interface
|
||||
public Name[] getPlayers ()
|
||||
{
|
||||
return players;
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public String getTurnHolderFieldName ()
|
||||
{
|
||||
return TURN_HOLDER;
|
||||
}
|
||||
|
||||
// documentation inherited from interface
|
||||
public Name getTurnHolder ()
|
||||
{
|
||||
return turnHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that the <code>turnHolder</code> field be set to the specified
|
||||
* value. The local value will be updated immediately and an event
|
||||
* will be propagated through the system to notify all listeners that
|
||||
* the attribute did change. Proxied copies of this object (on
|
||||
* clients) will apply the value change when they received the
|
||||
* attribute changed notification.
|
||||
*/
|
||||
public void setTurnHolder (Name turnHolder)
|
||||
{
|
||||
requestAttributeChange(TURN_HOLDER, turnHolder);
|
||||
this.turnHolder = turnHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that the specified entry be added to the
|
||||
* <code>tiles</code> set. The set will not change until the event is
|
||||
* actually propagated through the system.
|
||||
*/
|
||||
public void addToTiles (DSet.Entry elem)
|
||||
{
|
||||
requestEntryAdd(TILES, elem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that the entry matching the supplied key be removed from
|
||||
* the <code>tiles</code> set. The set will not change until the
|
||||
* event is actually propagated through the system.
|
||||
*/
|
||||
public void removeFromTiles (Comparable key)
|
||||
{
|
||||
requestEntryRemove(TILES, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that the specified entry be updated in the
|
||||
* <code>tiles</code> set. The set will not change until the event is
|
||||
* actually propagated through the system.
|
||||
*/
|
||||
public void updateTiles (DSet.Entry elem)
|
||||
{
|
||||
requestEntryUpdate(TILES, elem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that the <code>tiles</code> field be set to the
|
||||
* specified value. Generally one only adds, updates and removes
|
||||
* entries of a distributed set, but certain situations call for a
|
||||
* complete replacement of the set value. The local value will be
|
||||
* updated immediately and an event will be propagated through the
|
||||
* system to notify all listeners that the attribute did
|
||||
* change. Proxied copies of this object (on clients) will apply the
|
||||
* value change when they received the attribute changed notification.
|
||||
*/
|
||||
public void setTiles (DSet tiles)
|
||||
{
|
||||
requestAttributeChange(TILES, tiles);
|
||||
this.tiles = tiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that the <code>currentTile</code> field be set to the specified
|
||||
* value. The local value will be updated immediately and an event
|
||||
* will be propagated through the system to notify all listeners that
|
||||
* the attribute did change. Proxied copies of this object (on
|
||||
* clients) will apply the value change when they received the
|
||||
* attribute changed notification.
|
||||
*/
|
||||
public void setCurrentTile (AtlantiTile currentTile)
|
||||
{
|
||||
requestAttributeChange(CURRENT_TILE, currentTile);
|
||||
this.currentTile = currentTile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that the specified entry be added to the
|
||||
* <code>piecens</code> set. The set will not change until the event is
|
||||
* actually propagated through the system.
|
||||
*/
|
||||
public void addToPiecens (DSet.Entry elem)
|
||||
{
|
||||
requestEntryAdd(PIECENS, elem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that the entry matching the supplied key be removed from
|
||||
* the <code>piecens</code> set. The set will not change until the
|
||||
* event is actually propagated through the system.
|
||||
*/
|
||||
public void removeFromPiecens (Comparable key)
|
||||
{
|
||||
requestEntryRemove(PIECENS, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that the specified entry be updated in the
|
||||
* <code>piecens</code> set. The set will not change until the event is
|
||||
* actually propagated through the system.
|
||||
*/
|
||||
public void updatePiecens (DSet.Entry elem)
|
||||
{
|
||||
requestEntryUpdate(PIECENS, elem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that the <code>piecens</code> field be set to the
|
||||
* specified value. Generally one only adds, updates and removes
|
||||
* entries of a distributed set, but certain situations call for a
|
||||
* complete replacement of the set value. The local value will be
|
||||
* updated immediately and an event will be propagated through the
|
||||
* system to notify all listeners that the attribute did
|
||||
* change. Proxied copies of this object (on clients) will apply the
|
||||
* value change when they received the attribute changed notification.
|
||||
*/
|
||||
public void setPiecens (DSet piecens)
|
||||
{
|
||||
requestAttributeChange(PIECENS, piecens);
|
||||
this.piecens = piecens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that the <code>scores</code> field be set to the specified
|
||||
* value. The local value will be updated immediately and an event
|
||||
* will be propagated through the system to notify all listeners that
|
||||
* the attribute did change. Proxied copies of this object (on
|
||||
* clients) will apply the value change when they received the
|
||||
* attribute changed notification.
|
||||
*/
|
||||
public void setScores (int[] scores)
|
||||
{
|
||||
requestAttributeChange(SCORES, scores);
|
||||
this.scores = scores;
|
||||
}
|
||||
|
||||
/**
|
||||
* Requests that the <code>index</code>th element of
|
||||
* <code>scores</code> field be set to the specified value. The local
|
||||
* value will be updated immediately and an event will be propagated
|
||||
* through the system to notify all listeners that the attribute did
|
||||
* change. Proxied copies of this object (on clients) will apply the
|
||||
* value change when they received the attribute changed notification.
|
||||
*/
|
||||
public void setScoresAt (int value, int index)
|
||||
{
|
||||
requestElementUpdate(SCORES, new Integer(value), index);
|
||||
this.scores[index] = value;
|
||||
}
|
||||
}
|
||||
@@ -1,536 +0,0 @@
|
||||
//
|
||||
// $Id: AtlantiTile.java,v 1.17 2003/03/23 02:22:51 mdb Exp $
|
||||
|
||||
package com.samskivert.atlanti.data;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Color;
|
||||
import java.awt.Composite;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.Polygon;
|
||||
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.Point2D;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.List;
|
||||
import com.samskivert.util.IntTuple;
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import com.threerings.media.image.ImageManager;
|
||||
import com.threerings.media.tile.Tile;
|
||||
import com.threerings.media.tile.TileManager;
|
||||
import com.threerings.media.tile.UniformTileSet;
|
||||
|
||||
import com.threerings.io.ObjectInputStream;
|
||||
import com.threerings.presents.dobj.DSet;
|
||||
|
||||
import com.samskivert.atlanti.Log;
|
||||
import com.samskivert.atlanti.util.FeatureUtil;
|
||||
import com.samskivert.atlanti.util.PiecenUtil;
|
||||
import com.samskivert.atlanti.util.TileUtil;
|
||||
|
||||
/**
|
||||
* Represents a single tile in play on the game board.
|
||||
*
|
||||
* <p><em>Note:</em> this should really be split into a pure data class
|
||||
* and an associated visualization class in the
|
||||
* <code>atlanti.client</code> package.
|
||||
*/
|
||||
public class AtlantiTile
|
||||
implements DSet.Entry, TileCodes, Cloneable, Comparable
|
||||
{
|
||||
/** The starting tile. */
|
||||
public static final AtlantiTile STARTING_TILE =
|
||||
new AtlantiTile(CITY_ONE_ROAD_STRAIGHT, false, NORTH, 0, 0);
|
||||
|
||||
/** Activate this to render a piecen on every feature (useful for the
|
||||
* tile geometry test). */
|
||||
public static boolean piecenDebug = false;
|
||||
|
||||
/** The tile type. */
|
||||
public int type;
|
||||
|
||||
/** Whether this tile has a shield on it. */
|
||||
public boolean hasShield;
|
||||
|
||||
/** The tile's orientation. */
|
||||
public int orientation;
|
||||
|
||||
/** The tile's x and y coordinates. */
|
||||
public int x, y;
|
||||
|
||||
/** An array of claim group values that correspond to the features of
|
||||
* this tile. If a piecen has claimed a feature on this tile or that
|
||||
* connects to this tile, it will be represented here by a non-zero
|
||||
* claim group in the array slot that corresponds to the claimed
|
||||
* feature. */
|
||||
public transient int[] claims;
|
||||
|
||||
/** A reference to our static feature descriptions. */
|
||||
public transient Feature[] features;
|
||||
|
||||
/** A reference to the piecen on this tile or null if no piecen has
|
||||
* been placed on this tile. */
|
||||
public transient Piecen piecen;
|
||||
|
||||
/**
|
||||
* Constructs a tile with all of the supplied tile information.
|
||||
*/
|
||||
public AtlantiTile (int type, boolean hasShield, int orientation,
|
||||
int x, int y)
|
||||
{
|
||||
this.type = type;
|
||||
this.hasShield = hasShield;
|
||||
this.orientation = orientation;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
|
||||
// initialize our feature info
|
||||
initFeatures();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a tile with the type information set, but in the default
|
||||
* <code>NORTH</code> orientation and with no position.
|
||||
*/
|
||||
public AtlantiTile (int type, boolean hasShield)
|
||||
{
|
||||
this(type, hasShield, NORTH, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a blank tile, suitable for unserialization.
|
||||
*/
|
||||
public AtlantiTile ()
|
||||
{
|
||||
// nothing doing
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this tile has at leats one unclaimed feature.
|
||||
*/
|
||||
public boolean hasUnclaimedFeature ()
|
||||
{
|
||||
boolean unclaimed = false;
|
||||
for (int i = 0; i < claims.length; i++) {
|
||||
unclaimed = (unclaimed || (claims[i] == 0));
|
||||
}
|
||||
return unclaimed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks for a feature in this tile that matches the supplied feature
|
||||
* edge mask and returns the index of that feature in this tile's
|
||||
* {@link #claims} array.
|
||||
*
|
||||
* @return the index of the matching feature or -1 if no feature
|
||||
* matched.
|
||||
*/
|
||||
public int getFeatureIndex (int edgeMask)
|
||||
{
|
||||
// translate the feature mask into our orientation
|
||||
edgeMask = FeatureUtil.translateMask(edgeMask, -orientation);
|
||||
|
||||
// look for a feature with a matching edge mask
|
||||
for (int i = 0; i < features.length; i ++) {
|
||||
if ((features[i].edgeMask & edgeMask) != 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// no match
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the feature that contains the supplied mouse
|
||||
* coordinates (which will have been translated relative to the tile's
|
||||
* origin).
|
||||
*
|
||||
* @return the index of the feature that contains the mouse
|
||||
* coordinates. Some feature should always contain the mouse.
|
||||
*/
|
||||
public int getFeatureIndex (int mouseX, int mouseY)
|
||||
{
|
||||
// we search our features in reverse order because road features
|
||||
// overlap grass features geometrically and are known to be
|
||||
// specified after the grass features
|
||||
for (int i = features.length-1; i >= 0; i--) {
|
||||
if (features[i].contains(mouseX, mouseY, orientation)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// something is hosed; fake it
|
||||
Log.warning("Didn't find matching feature for mouse coordinates!? " +
|
||||
"[tile=" + this + ", mx=" + mouseX +
|
||||
", my=" + mouseY + "].");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks for a feature in this tile that matches the supplied feature
|
||||
* edge mask and returns the claim group to which that feature belongs
|
||||
* (which may be zero).
|
||||
*
|
||||
* @return the claim group to which the feature that matches the
|
||||
* supplied mask belongs, or zero if no feature matched the supplied
|
||||
* mask.
|
||||
*/
|
||||
public int getFeatureGroup (int edgeMask)
|
||||
{
|
||||
int fidx = getFeatureIndex(edgeMask);
|
||||
return fidx < 0 ? 0 : claims[fidx];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the claim group for the feature with the specified index. This
|
||||
* also updates the claim group for any piecen that was placed on that
|
||||
* feature as well.
|
||||
*
|
||||
* @param featureIndex the index of the feature to update.
|
||||
* @param claimGroup the claim group to associate with the feature.
|
||||
*/
|
||||
public void setClaimGroup (int featureIndex, int claimGroup)
|
||||
{
|
||||
// update the claim group slot for this feature
|
||||
claims[featureIndex] = claimGroup;
|
||||
|
||||
// if we have a piecen placed on the feature identified by this
|
||||
// feature index, we need to update its claim group as well
|
||||
if (piecen != null && piecen.featureIndex == featureIndex) {
|
||||
piecen.claimGroup = claimGroup;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Places the specified piecen on this tile. The {@link
|
||||
* Piecen#featureIndex} field is assumed to be initialized to the
|
||||
* feature index of this tile on which the piecen is to be placed.
|
||||
*
|
||||
* <p> Note that this will call {@link TileUtil#setClaimGroup} to
|
||||
* propagate the claiming of this feature to all neighboring tiles if
|
||||
* a non-null tiles array is supplied to the function.
|
||||
*
|
||||
* @param piecen the piecen to place on this tile (with an
|
||||
* appropriately configured feature index).
|
||||
* @param tiles a sorted list of all of the tiles on the board that
|
||||
* we can use to propagate our new claim group to all features
|
||||
* connected to this newly claimed feature or null if propagation of
|
||||
* the claim group is not desired at this time.
|
||||
*/
|
||||
public void setPiecen (Piecen piecen, List tiles)
|
||||
{
|
||||
int claimGroup = 0;
|
||||
|
||||
// if we're adding a piecen to a feature that's already claimed,
|
||||
// we want to inherit the claim number (this could happen when we
|
||||
// show up in an in progress game)
|
||||
if (claims[piecen.featureIndex] != 0) {
|
||||
Log.info("Requested to add a piecen to a feature " +
|
||||
"that has already been claimed [tile=" + this +
|
||||
", piecen=" + piecen + "]. Inheriting.");
|
||||
claimGroup = claims[piecen.featureIndex];
|
||||
|
||||
} else {
|
||||
// otherwise we generate a new claim group
|
||||
claimGroup = TileUtil.nextClaimGroup();
|
||||
Log.info("Creating claim group [cgroup=" + claimGroup +
|
||||
", tile=" + this + ", fidx=" + piecen.featureIndex + "].");
|
||||
}
|
||||
|
||||
// keep a reference to this piecen and configure its position
|
||||
this.piecen = piecen;
|
||||
piecen.x = x;
|
||||
piecen.y = y;
|
||||
|
||||
// assign a brand spanking new claim group to the feature and the
|
||||
// piecen and propagate it to neighboring features
|
||||
if (tiles != null) {
|
||||
TileUtil.setClaimGroup(
|
||||
tiles, this, piecen.featureIndex, claimGroup);
|
||||
// update our piecen with the claim group as well
|
||||
piecen.claimGroup = claimGroup;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears out any piecen reference that was previously set (does not
|
||||
* clear out its associated claim group, however).
|
||||
*/
|
||||
public void clearPiecen ()
|
||||
{
|
||||
piecen = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Paints this tile to the specified graphics context at its assigned
|
||||
* location, accounting for the supplied x and y offsets of the
|
||||
* origin.
|
||||
*
|
||||
* @param g the graphics context to use when painting the tile.
|
||||
* @param xoff the offset (in tile units) of the origin in the x
|
||||
* direction.
|
||||
* @param yoff the offset (in tile units) of the origin in the y
|
||||
* direction.
|
||||
*/
|
||||
public void paint (Graphics2D g, int xoff, int yoff)
|
||||
{
|
||||
int tidx = type-1;
|
||||
|
||||
// obtain our tile image
|
||||
if (_tileImage == null) {
|
||||
_tileImage = getTileImage(type);
|
||||
}
|
||||
|
||||
// compute our screen coordinates
|
||||
int sx = (x + xoff) * TILE_WIDTH;
|
||||
int sy = (y + yoff) * TILE_HEIGHT;
|
||||
|
||||
// translate to our screen coordinates
|
||||
g.translate(sx, sy);
|
||||
|
||||
// render our tile image
|
||||
if (_tileImage != null) {
|
||||
if (orientation > 0) {
|
||||
g.drawImage(_tileImage, _xforms[orientation], null);
|
||||
} else {
|
||||
g.drawImage(_tileImage, 0, 0, null);
|
||||
}
|
||||
|
||||
} else {
|
||||
Log.warning("No tile image!? [type=" + type +
|
||||
", img=" + _tileImage + "].");
|
||||
}
|
||||
|
||||
// // render our features
|
||||
// for (int i = 0; i < features.length; i++) {
|
||||
// // paint the feature
|
||||
// features[i].paint(g, orientation, claims[i]);
|
||||
// }
|
||||
|
||||
// if we have a shield, draw a square in the lower right
|
||||
if (hasShield) {
|
||||
Point2D sspot = FeatureUtil.getShieldSpot(orientation);
|
||||
Image image = getShieldImage();
|
||||
|
||||
if (image != null) {
|
||||
int iwidth = image.getWidth(null);
|
||||
int iheight = image.getHeight(null);
|
||||
Composite ocomp = g.getComposite();
|
||||
g.setComposite(ALPHA_PLACING);
|
||||
g.drawImage(image, (int)(sspot.getX() - iwidth/2),
|
||||
(int)(sspot.getY() - iheight/2), null);
|
||||
g.setComposite(ocomp);
|
||||
|
||||
} else {
|
||||
g.setColor(Color.orange);
|
||||
g.drawRect((int)(sspot.getX()-5),
|
||||
(int)(sspot.getY()-5), 10, 10);
|
||||
}
|
||||
}
|
||||
|
||||
// if we have a piecen on this tile, render it as well
|
||||
if (piecen != null || piecenDebug) {
|
||||
for (int i = 0; i < features.length; i++) {
|
||||
if (piecenDebug) {
|
||||
Image pimg = PiecenUtil.getPiecenImage(0);
|
||||
features[i].paintPiecen(g, orientation, pimg, 0);
|
||||
|
||||
} else if (piecen.featureIndex == i) {
|
||||
Image pimg = PiecenUtil.getPiecenImage(piecen.owner);
|
||||
features[i].paintPiecen(
|
||||
g, orientation, pimg, piecen.claimGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// // draw a rectangular outline
|
||||
// g.setColor(Color.black);
|
||||
// g.drawRect(0, 0, TILE_WIDTH-1, TILE_HEIGHT-1);
|
||||
|
||||
// translate back out
|
||||
g.translate(-sx, -sy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of this tile object.
|
||||
*/
|
||||
public Object clone ()
|
||||
{
|
||||
return new AtlantiTile(type, hasShield, orientation, x, y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to order tiles (which is done by board position).
|
||||
*/
|
||||
public int compareTo (Object other)
|
||||
{
|
||||
// we will either be compared to another tile, to a piecen or to a
|
||||
// coordinate object (int tuple)
|
||||
if (other == null) {
|
||||
return -1;
|
||||
|
||||
} else if (other instanceof AtlantiTile) {
|
||||
AtlantiTile tile = (AtlantiTile)other;
|
||||
return (tile.x == x) ? y - tile.y : x - tile.x;
|
||||
|
||||
} else if (other instanceof IntTuple) {
|
||||
IntTuple coord = (IntTuple)other;
|
||||
return (coord.left == x) ? y - coord.right : x - coord.left;
|
||||
|
||||
} else if (other instanceof Piecen) {
|
||||
Piecen piecen = (Piecen)other;
|
||||
return (piecen.x == x) ? y - piecen.y : x - piecen.x;
|
||||
|
||||
} else {
|
||||
// who knows...
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public boolean equals (Object other)
|
||||
{
|
||||
return (compareTo(other) == 0);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public Comparable getKey ()
|
||||
{
|
||||
// our key is our coordinates conflated into one integer
|
||||
return new Integer((x + 128) * 256 + y + 128);
|
||||
}
|
||||
|
||||
/**
|
||||
* After we've been unserialized we have to initialize some derived
|
||||
* fields.
|
||||
*/
|
||||
public void readObject (ObjectInputStream in)
|
||||
throws IOException, ClassNotFoundException
|
||||
{
|
||||
in.defaultReadObject();
|
||||
initFeatures();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes this tile's feature management data structures.
|
||||
*/
|
||||
protected void initFeatures ()
|
||||
{
|
||||
if (type > 0) {
|
||||
// grab a reference to our feature information
|
||||
features = FeatureUtil.getTileFeatures(type);
|
||||
|
||||
// create our claims array
|
||||
claims = new int[features.length];
|
||||
|
||||
} else {
|
||||
Log.warning("Requested to init features without valid type " +
|
||||
this + ".");
|
||||
Thread.dumpStack();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a string representation of this tile instance.
|
||||
*/
|
||||
public String toString ()
|
||||
{
|
||||
return "[type=" + type + ", shield=" + hasShield +
|
||||
", orient=" + ORIENT_NAMES[orientation] +
|
||||
", pos=" + x + "/" + y +
|
||||
", claims=" + StringUtil.toString(claims) +
|
||||
", piecen=" + piecen + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* Someone needs to configure this so that we can display tiles on
|
||||
* screen.
|
||||
*/
|
||||
public static void setManagers (ImageManager imgr, TileManager tmgr)
|
||||
{
|
||||
_imgr = imgr;
|
||||
_tmgr = tmgr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the image for the tile of the specified type.
|
||||
*/
|
||||
protected static Image getTileImage (int type)
|
||||
{
|
||||
// load up the tile set if we haven't already
|
||||
if (_tset == null) {
|
||||
_tset = _tmgr.loadTileSet(TILES_IMG_PATH,
|
||||
TILE_WIDTH, TILE_HEIGHT);
|
||||
}
|
||||
|
||||
// fetch the tile
|
||||
return _tset.getRawTileImage(type-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the shield image.
|
||||
*/
|
||||
protected static Image getShieldImage ()
|
||||
{
|
||||
// load up the tile set if we haven't already
|
||||
if (_stset == null) {
|
||||
_stset = _tmgr.loadTileSet(SHIELD_IMG_PATH,
|
||||
SHIELD_SIZE, SHIELD_SIZE);
|
||||
}
|
||||
|
||||
// fetch the tile
|
||||
return _stset.getRawTileImage(0);
|
||||
}
|
||||
|
||||
/** The tile image that we use to render this tile. */
|
||||
protected transient Image _tileImage;
|
||||
|
||||
/** Our image manager. */
|
||||
protected static ImageManager _imgr;
|
||||
|
||||
/** Our tile manager. */
|
||||
protected static TileManager _tmgr;
|
||||
|
||||
/** Our tile image tileset. */
|
||||
protected static UniformTileSet _tset;
|
||||
|
||||
/** Our shield image tileset. */
|
||||
protected static UniformTileSet _stset;
|
||||
|
||||
/** The path to our tileset image. */
|
||||
protected static final String TILES_IMG_PATH = "media/tiles.png";
|
||||
|
||||
/** The path to our shield image. */
|
||||
protected static final String SHIELD_IMG_PATH = "media/shield.png";
|
||||
|
||||
/** The size of the shield image (width and height). */
|
||||
protected static final int SHIELD_SIZE = 17;
|
||||
|
||||
/** Three affine transforms for rendering an image in three rotated
|
||||
* orientations. */
|
||||
protected static AffineTransform[] _xforms;
|
||||
|
||||
static {
|
||||
// the first element will be left blank
|
||||
_xforms = new AffineTransform[4];
|
||||
|
||||
// create our three orientation transforms
|
||||
AffineTransform xform = new AffineTransform();
|
||||
for (int orient = 1; orient < 4; orient++) {
|
||||
// rotate the xform into the next orientation
|
||||
xform.translate(TILE_WIDTH, 0);
|
||||
xform.rotate(Math.PI/2);
|
||||
// and save it
|
||||
_xforms[orient] = (AffineTransform)xform.clone();
|
||||
}
|
||||
}
|
||||
|
||||
/** For rendering shields with alpha. */
|
||||
protected static final Composite ALPHA_PLACING =
|
||||
AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.6f);
|
||||
}
|
||||
@@ -1,375 +0,0 @@
|
||||
//
|
||||
// $Id: Feature.java,v 1.6 2002/12/12 05:51:54 mdb Exp $
|
||||
|
||||
package com.samskivert.atlanti.data;
|
||||
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Color;
|
||||
import java.awt.Composite;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.Shape;
|
||||
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.GeneralPath;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.RoundRectangle2D;
|
||||
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import com.samskivert.atlanti.Log;
|
||||
import com.samskivert.atlanti.util.FeatureUtil;
|
||||
import com.samskivert.atlanti.util.TileUtil;
|
||||
|
||||
/**
|
||||
* Represents all of the necessary information for a particular feature of
|
||||
* a particular tile.
|
||||
*/
|
||||
public class Feature
|
||||
implements TileCodes
|
||||
{
|
||||
/** Maps piecen color codes to colors. */
|
||||
public static Color[] PIECEN_COLOR_MAP = {
|
||||
new Color(0x0246B7), // BLUE
|
||||
new Color(0x028A12), // GREEN
|
||||
new Color(0xF47A02), // ORANGE
|
||||
new Color(0xC20292), // MAGENTA
|
||||
new Color(0xB90202), // RED
|
||||
new Color(0xFECA11), // YELLOW
|
||||
};
|
||||
|
||||
/** The type of this feature. */
|
||||
public int type;
|
||||
|
||||
/** The edge mask associated with this feature. */
|
||||
public int edgeMask;
|
||||
|
||||
/** The location at which a piecen on this feature would be drawn (for
|
||||
* each of the four tile orientations. */
|
||||
public Point2D[] piecenSpots = new Point2D[4];
|
||||
|
||||
/** The polygons used to render and hit test this feature (one for
|
||||
* each orientation). */
|
||||
public GeneralPath[] polys = new GeneralPath[4];
|
||||
|
||||
/**
|
||||
* Constructs a feature with a feature description array containing
|
||||
* all of the necessary feature information.
|
||||
*/
|
||||
public Feature (int[] desc)
|
||||
{
|
||||
type = desc[0];
|
||||
edgeMask = desc[1];
|
||||
|
||||
// fetch our natural piecen spot, scale it and adjust for half units
|
||||
int px = (desc[2] * TILE_WIDTH) / 4;
|
||||
if (px < 0) {
|
||||
px *= -1;
|
||||
px -= TILE_WIDTH/8;
|
||||
}
|
||||
int py = (desc[3] * TILE_HEIGHT) / 4;
|
||||
if (py < 0) {
|
||||
py *= -1;
|
||||
py -= TILE_HEIGHT/8;
|
||||
}
|
||||
// oh, just a teeny hack for aesthetic shield placement
|
||||
if (type == -1) {
|
||||
px += 2; py += 2;
|
||||
}
|
||||
piecenSpots[NORTH] = new Point2D.Float(px, py);
|
||||
|
||||
// create our natural feature polygon
|
||||
if (type == ROAD) {
|
||||
// roads are handled specially; they are either one or two
|
||||
// segment roads
|
||||
if (desc.length == 8) {
|
||||
polys[NORTH] = roadSegmentToPolygon(
|
||||
desc[4], desc[5], desc[6], desc[7]);
|
||||
|
||||
} else if (desc.length == 10) {
|
||||
polys[NORTH] = roadSegmentToPolygon(
|
||||
desc[4], desc[5], desc[6], desc[7], desc[8], desc[9]);
|
||||
|
||||
} else {
|
||||
Log.warning("Feature constructed with bogus road geometry " +
|
||||
"[desc=" + StringUtil.toString(desc) + "].");
|
||||
}
|
||||
|
||||
} else {
|
||||
GeneralPath poly = new GeneralPath();
|
||||
for (int i = 4; i < desc.length; i += 2) {
|
||||
// scale the coords accordingly
|
||||
int fx = (desc[i] * TILE_WIDTH) / 4;
|
||||
int fy = (desc[i+1] * TILE_HEIGHT) / 4;
|
||||
if (i == 4) {
|
||||
poly.moveTo(fx, fy);
|
||||
} else {
|
||||
poly.lineTo(fx, fy);
|
||||
}
|
||||
}
|
||||
poly.closePath();
|
||||
polys[NORTH] = poly;
|
||||
}
|
||||
|
||||
// now create the three other orientations
|
||||
AffineTransform xform = new AffineTransform();
|
||||
for (int orient = 1; orient < 4; orient++) {
|
||||
// rotate the xform into the next orientation
|
||||
xform.translate(TILE_WIDTH, 0);
|
||||
xform.rotate(Math.PI/2);
|
||||
|
||||
// transform the polygon
|
||||
polys[orient] = (GeneralPath)polys[NORTH].clone();
|
||||
polys[orient].transform(xform);
|
||||
|
||||
// transform the piecen spot
|
||||
piecenSpots[orient] = new Point2D.Float();
|
||||
xform.transform(piecenSpots[NORTH], piecenSpots[orient]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the feature contains the supplied mouse coordinates
|
||||
* (which should be relative to the tile origin) given the supplied
|
||||
* orientation information.
|
||||
*/
|
||||
public boolean contains (int mouseX, int mouseY, int orientation)
|
||||
{
|
||||
return polys[orientation].contains(mouseX, mouseY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Paints this feature to the specified graphics context with the
|
||||
* specified orientation, accounting for the supplied x and y offsets
|
||||
* of the origin. The graphics context is assumed to be appropriately
|
||||
* translated so that we may render this feature relative to the
|
||||
* origin and have it painted in the proper place.
|
||||
*
|
||||
* @param g the graphics context to use when painting the feature.
|
||||
* @param orientation the orientation at which to paint this feature.
|
||||
* @param claimGroup the claim group to which this feature belongs (or
|
||||
* zero if it belongs to no claim group).
|
||||
*/
|
||||
public void paint (Graphics2D g, int orientation, int claimGroup)
|
||||
{
|
||||
// set the color according to the claim group
|
||||
g.setColor(claimGroup > 0 ? CLAIMED_COLOR_MAP[type] :
|
||||
COLOR_MAP[type]);
|
||||
|
||||
// now render the appropriate polygon for this orientation
|
||||
g.fill(polys[orientation]);
|
||||
|
||||
// // paint our features for debugging (they aren't rotated and thus
|
||||
// // are only valid in the natural orientation)
|
||||
// int w = TILE_WIDTH, hw = w/2, qw = hw/2, tqw = 3*qw;
|
||||
// int h = TILE_HEIGHT, hh = h/2, qh = hh/2, tqh = 3*qh;
|
||||
// g.setColor(Color.gray);
|
||||
|
||||
// if ((edgeMask & FeatureUtil.NORTH_F) != 0) {
|
||||
// g.drawLine(hw, 0, hw, qh);
|
||||
// }
|
||||
// if ((edgeMask & FeatureUtil.EAST_F) != 0) {
|
||||
// g.drawLine(tqw, hh, w, hh);
|
||||
// }
|
||||
// if ((edgeMask & FeatureUtil.SOUTH_F) != 0) {
|
||||
// g.drawLine(hw, tqh, hw, h);
|
||||
// }
|
||||
// if ((edgeMask & FeatureUtil.WEST_F) != 0) {
|
||||
// g.drawLine(0, hh, qw, hh);
|
||||
// }
|
||||
|
||||
// if ((edgeMask & FeatureUtil.NNE_F) != 0) {
|
||||
// g.drawLine(tqw, 0, tqw, qh);
|
||||
// }
|
||||
// if ((edgeMask & FeatureUtil.NNW_F) != 0) {
|
||||
// g.drawLine(qw, 0, qw, qh);
|
||||
// }
|
||||
// if ((edgeMask & FeatureUtil.SSE_F) != 0) {
|
||||
// g.drawLine(tqw, tqh, tqw, h);
|
||||
// }
|
||||
// if ((edgeMask & FeatureUtil.SSW_F) != 0) {
|
||||
// g.drawLine(qw, tqh, qw, h);
|
||||
// }
|
||||
|
||||
// if ((edgeMask & FeatureUtil.ENE_F) != 0) {
|
||||
// g.drawLine(tqw, qh, w, qh);
|
||||
// }
|
||||
// if ((edgeMask & FeatureUtil.ESE_F) != 0) {
|
||||
// g.drawLine(tqw, tqh, w, tqh);
|
||||
// }
|
||||
// if ((edgeMask & FeatureUtil.WNW_F) != 0) {
|
||||
// g.drawLine(0, qh, qw, qh);
|
||||
// }
|
||||
// if ((edgeMask & FeatureUtil.WSW_F) != 0) {
|
||||
// g.drawLine(0, tqh, qw, tqh);
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* Paints a piecen in a position indicating that it is placed on this
|
||||
* feature. The graphics context is assumed to be appropriately
|
||||
* translated so that we may render this feature relative to the
|
||||
* origin and have it painted in the proper place.
|
||||
*
|
||||
* @param g the graphics context to use when painting the feature.
|
||||
* @param orientation the orientation at which to paint this feature.
|
||||
* @param image the piecen image to be painted.
|
||||
* @param claimGroup the claim group to which this piecen belongs (or
|
||||
* zero if it belongs to no claim group).
|
||||
*/
|
||||
public void paintPiecen (Graphics2D g, int orientation, Image image,
|
||||
int claimGroup)
|
||||
{
|
||||
Point2D point = piecenSpots[orientation];
|
||||
int iwidth = image.getWidth(null);
|
||||
int iheight = image.getHeight(null);
|
||||
|
||||
// render the piecen image slightly transparent
|
||||
Composite ocomp = g.getComposite();
|
||||
g.setComposite(ALPHA_PLACING);
|
||||
g.drawImage(image, (int)(point.getX() - iwidth/2),
|
||||
(int)(point.getY() - iheight/2), null);
|
||||
g.setComposite(ocomp);
|
||||
|
||||
// // for now, draw the claim group next to the piecen
|
||||
// g.drawString(Integer.toString(claimGroup),
|
||||
// (float)(point.getX() - swidth/2 + 2),
|
||||
// (float)(point.getY() - sheight/2 - 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Massages a road segment (specified in tile feature coordinates)
|
||||
* into a polygon (in screen coordinates) that can be used to render
|
||||
* or hit test the road. The coordinates must obey the following
|
||||
* constraints: (x1 < x2 and y1 == y2) or (x1 == x2 and y1 < y2) or
|
||||
* (x1 < x2 and y1 > y2).
|
||||
*
|
||||
* @return a polygon representing the road segment (with origin at 0,
|
||||
* 0).
|
||||
*/
|
||||
protected static GeneralPath roadSegmentToPolygon (
|
||||
int x1, int y1, int x2, int y2)
|
||||
{
|
||||
// first convert the coordinates into screen coordinates
|
||||
x1 = (x1 * TILE_WIDTH) / 4;
|
||||
y1 = (y1 * TILE_HEIGHT) / 4;
|
||||
x2 = (x2 * TILE_WIDTH) / 4;
|
||||
y2 = (y2 * TILE_HEIGHT) / 4;
|
||||
|
||||
GeneralPath poly = new GeneralPath();
|
||||
int dx = 4, dy = 4;
|
||||
|
||||
// figure out what sort of line segment it is
|
||||
if (x1 == x2) { // vertical
|
||||
// make adjustments to ensure that we stay inside the tile
|
||||
// bounds
|
||||
if (y1 == 0) {
|
||||
y1 += dy;
|
||||
}
|
||||
if (y2 == TILE_HEIGHT) {
|
||||
y2 -= dy;
|
||||
}
|
||||
poly.moveTo(x1 - dx, y1 - dy);
|
||||
poly.lineTo(x1 + dx, y1 - dy);
|
||||
poly.lineTo(x2 + dx, y2 + dy);
|
||||
poly.lineTo(x2 - dx, y2 + dy);
|
||||
|
||||
} else if (y1 == y2) { // horizontal
|
||||
// make adjustments to ensure that we stay inside the tile
|
||||
// bounds
|
||||
if (x1 == 0) {
|
||||
x1 += dx;
|
||||
}
|
||||
if (x2 == TILE_WIDTH) {
|
||||
x2 -= dx;
|
||||
}
|
||||
poly.moveTo(x1 - dx, y1 - dy);
|
||||
poly.lineTo(x1 - dx, y1 + dy);
|
||||
poly.lineTo(x2 + dx, y2 + dy);
|
||||
poly.lineTo(x2 + dx, y2 - dy);
|
||||
|
||||
} else { // diagonal
|
||||
poly.moveTo(x1 - dx, y1);
|
||||
poly.lineTo(x1 + dx, y1);
|
||||
poly.lineTo(x2, y2 + dy);
|
||||
poly.lineTo(x2, y2 - dy);
|
||||
}
|
||||
|
||||
poly.closePath();
|
||||
return poly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Massages a road segment (specified in tile feature coordinates)
|
||||
* into a polygon (in screen coordinates) that can be used to render
|
||||
* or hit test the road. The coordinates must obey the following
|
||||
* constraints: (y1 == y2) and (y2 > y3) and (x2 == x3).
|
||||
*
|
||||
* @return a polygon representing the road segment (with origin at 0,
|
||||
* 0).
|
||||
*/
|
||||
protected static GeneralPath roadSegmentToPolygon (
|
||||
int x1, int y1, int x2, int y2, int x3, int y3)
|
||||
{
|
||||
// first convert the coordinates into screen coordinates
|
||||
x1 = (x1 * TILE_WIDTH) / 4;
|
||||
y1 = (y1 * TILE_HEIGHT) / 4;
|
||||
x2 = (x2 * TILE_WIDTH) / 4;
|
||||
y2 = (y2 * TILE_HEIGHT) / 4;
|
||||
x3 = (x3 * TILE_WIDTH) / 4;
|
||||
y3 = (y3 * TILE_HEIGHT) / 4;
|
||||
|
||||
GeneralPath poly = new GeneralPath();
|
||||
int dx = 4, dy = 4;
|
||||
|
||||
// figure out what sort of road segment it is
|
||||
if (x1 < x2) { // left turn
|
||||
poly.moveTo(x1, y1-dy);
|
||||
poly.lineTo(x2+dx, y2-dy);
|
||||
poly.lineTo(x3+dx, y3);
|
||||
poly.lineTo(x3-dx, y3);
|
||||
poly.lineTo(x2-dx, y2+dy);
|
||||
poly.lineTo(x1, y1+dy);
|
||||
|
||||
} else { // right turn
|
||||
poly.moveTo(x1, y1-dy);
|
||||
poly.lineTo(x2-dx, y2-dy);
|
||||
poly.lineTo(x3-dx, y3);
|
||||
poly.lineTo(x3+dx, y3);
|
||||
poly.lineTo(x2+dx, y2+dy);
|
||||
poly.lineTo(x1, y1+dy);
|
||||
}
|
||||
|
||||
poly.closePath();
|
||||
return poly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a string representation of this feature.
|
||||
*/
|
||||
public String toString ()
|
||||
{
|
||||
return "[type=" + FeatureUtil.typeToString(type) +
|
||||
", edgeMask=" + FeatureUtil.edgeMaskToString(edgeMask) + "]";
|
||||
}
|
||||
|
||||
/** Maps feature types to colors. */
|
||||
protected static Color[] COLOR_MAP = {
|
||||
Color.red, // CITY
|
||||
Color.green, // GRASS
|
||||
Color.black, // ROAD
|
||||
Color.yellow // CLOISTER
|
||||
};
|
||||
|
||||
/** Maps feature types to colors for claimed features. */
|
||||
protected static Color[] CLAIMED_COLOR_MAP = {
|
||||
Color.red.darker(), // CITY
|
||||
Color.green.darker(), // GRASS
|
||||
Color.darkGray, // ROAD
|
||||
Color.yellow.darker(), // CLOISTER
|
||||
};
|
||||
|
||||
/** For rendering piecens with alpha. */
|
||||
protected static final Composite ALPHA_PLACING =
|
||||
AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f);
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
//
|
||||
// $Id: Piecen.java,v 1.4 2002/12/12 05:51:54 mdb Exp $
|
||||
|
||||
package com.samskivert.atlanti.data;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
|
||||
import com.threerings.presents.dobj.DSet;
|
||||
|
||||
/**
|
||||
* A piecen is a person and a piece all rolled into one! Players can play
|
||||
* a single piecen on a tile feature as a part of their turn and that
|
||||
* piecen then claims that feature and all of the features that are
|
||||
* connected to it forming a claim group. Once a group of features has
|
||||
* been claimed, no further piecens can be placed on the group. Note,
|
||||
* however, that two or more separately claimed feature groups can be
|
||||
* joined by placing a tile that connects the previously disconnected
|
||||
* groups together. In that case, the groups are merged into a single
|
||||
* claim group and all the piecens that were part of the disparate groups
|
||||
* become claimees in the new group. At scoring time, the player with the
|
||||
* most piecens in a group gets the points for the group. If two or more
|
||||
* players have equal numbers of piecens in a group, they each get the
|
||||
* points for the group.
|
||||
*/
|
||||
public class Piecen
|
||||
implements DSet.Entry
|
||||
{
|
||||
/** A color constant. */
|
||||
public static final int RED = 0;
|
||||
|
||||
/** A color constant. */
|
||||
public static final int BLACK = 1;
|
||||
|
||||
/** A color constant. */
|
||||
public static final int BLUE = 2;
|
||||
|
||||
/** A color constant. */
|
||||
public static final int YELLOW = 3;
|
||||
|
||||
/** A color constant. */
|
||||
public static final int GREEN = 4;
|
||||
|
||||
/** The owner of this piecen. */
|
||||
public int owner;
|
||||
|
||||
/** The x and y coordinates of the tile on which this piecen is
|
||||
* placed. */
|
||||
public int x, y;
|
||||
|
||||
/** The index in the tile's feature array of the feature on which this
|
||||
* piecen is placed. */
|
||||
public int featureIndex;
|
||||
|
||||
/** The claim group to which this piecen belongs. */
|
||||
public int claimGroup;
|
||||
|
||||
/**
|
||||
* Construts a piecen with the specified configuration.
|
||||
*/
|
||||
public Piecen (int owner, int x, int y, int featureIndex)
|
||||
{
|
||||
this.owner = owner;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.featureIndex = featureIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a blank piecen, suitable for unserialization.
|
||||
*/
|
||||
public Piecen ()
|
||||
{
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public Comparable getKey ()
|
||||
{
|
||||
// our key is our coordinates conflated into one integer
|
||||
return new Integer((x + 128) * 256 + y + 128);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void writeTo (DataOutputStream out)
|
||||
throws IOException
|
||||
{
|
||||
out.writeInt(owner);
|
||||
out.writeInt(x);
|
||||
out.writeInt(y);
|
||||
out.writeInt(featureIndex);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void readFrom (DataInputStream in)
|
||||
throws IOException
|
||||
{
|
||||
owner = in.readInt();
|
||||
x = in.readInt();
|
||||
y = in.readInt();
|
||||
featureIndex = in.readInt();
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public boolean equals (Object other)
|
||||
{
|
||||
// we will either be compared to a tile or to a piecen
|
||||
if (other == null) {
|
||||
return false;
|
||||
|
||||
} else if (other instanceof AtlantiTile) {
|
||||
AtlantiTile tile = (AtlantiTile)other;
|
||||
return (tile.x == x) ? (y == tile.y) : false;
|
||||
|
||||
} else if (other instanceof Piecen) {
|
||||
Piecen piecen = (Piecen)other;
|
||||
return (piecen.x == x) ? (y == piecen.y) : false;
|
||||
|
||||
} else {
|
||||
// who knows...
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a string representation of this piecen.
|
||||
*/
|
||||
public String toString ()
|
||||
{
|
||||
return "[owner=" + owner + ", pos=" + x + "/" + y +
|
||||
", feat=" + featureIndex + ", claim=" + claimGroup + "]";
|
||||
}
|
||||
}
|
||||
@@ -1,127 +0,0 @@
|
||||
//
|
||||
// $Id: TileCodes.java,v 1.10 2002/12/12 05:51:54 mdb Exp $
|
||||
|
||||
package com.samskivert.atlanti.data;
|
||||
|
||||
/**
|
||||
* A repository for constants related to the tiles that are used in the
|
||||
* game of Atlantissonne.
|
||||
*/
|
||||
public interface TileCodes
|
||||
{
|
||||
/** A four-sided city tile. */
|
||||
public static final int CITY_FOUR = 1;
|
||||
|
||||
/** A three-sided city tile. */
|
||||
public static final int CITY_THREE = 2;
|
||||
|
||||
/** A three-sided city tile with a road. */
|
||||
public static final int CITY_THREE_ROAD = 3;
|
||||
|
||||
/** A two-sided city tile with city openings adjacent to one
|
||||
* another. */
|
||||
public static final int CITY_TWO = 4;
|
||||
|
||||
/** A two-sided city tile with city openings adjacent to one another
|
||||
* and a road connecting the other two sides. */
|
||||
public static final int CITY_TWO_ROAD = 5;
|
||||
|
||||
/** A two-sided city tile with city openings on opposite sides of the
|
||||
* tile. */
|
||||
public static final int CITY_TWO_ACROSS = 6;
|
||||
|
||||
/** A two-sided city tile with two separate city arcs adjacent to one
|
||||
* another and not connected to each other. */
|
||||
public static final int TWO_CITY_TWO = 7;
|
||||
|
||||
/** A two-sided city tile with two separate city arcs on opposite
|
||||
* sides of the tile. */
|
||||
public static final int TWO_CITY_TWO_ACROSS = 8;
|
||||
|
||||
/** A one-sided city tile. */
|
||||
public static final int CITY_ONE = 9;
|
||||
|
||||
/** A one-sided city tile with a city arc on top and a right facing
|
||||
* curved road segment beneath it. */
|
||||
public static final int CITY_ONE_ROAD_RIGHT = 10;
|
||||
|
||||
/** A one-sided city tile with a city arc on top and a left facing
|
||||
* curved road segment beneath it. */
|
||||
public static final int CITY_ONE_ROAD_LEFT = 11;
|
||||
|
||||
/** A one-sided city tile with a city arc on top and a road tee
|
||||
* beneath it. */
|
||||
public static final int CITY_ONE_ROAD_TEE = 12;
|
||||
|
||||
/** A one-sided city tile with a city arc on top and straight road
|
||||
* segment beneath it. */
|
||||
public static final int CITY_ONE_ROAD_STRAIGHT = 13;
|
||||
|
||||
/** A cloister tile. */
|
||||
public static final int CLOISTER_PLAIN = 14;
|
||||
|
||||
/** A cloister tile with a road extending from the cloister. */
|
||||
public static final int CLOISTER_ROAD = 15;
|
||||
|
||||
/** A four-way road intersection. */
|
||||
public static final int FOUR_WAY_ROAD = 16;
|
||||
|
||||
/** A three-way road intersection. */
|
||||
public static final int THREE_WAY_ROAD = 17;
|
||||
|
||||
/** A straight road segment. */
|
||||
public static final int STRAIGHT_ROAD = 18;
|
||||
|
||||
/** A curved road segment. */
|
||||
public static final int CURVED_ROAD = 19;
|
||||
|
||||
/** The number of different tile types. */
|
||||
public static final int TILE_TYPES = 19;
|
||||
|
||||
|
||||
/** A tile orientation constant indicating the tile is in its default
|
||||
* orientation. */
|
||||
public static final int NORTH = 0;
|
||||
|
||||
/** A tile orientation constant indicating the tile is rotated 90
|
||||
* degrees clockwise from its default orientation. */
|
||||
public static final int EAST = 1;
|
||||
|
||||
/** A tile orientation constant indicating the tile is rotated 180
|
||||
* degrees clockwise from its default orientation. */
|
||||
public static final int SOUTH = 2;
|
||||
|
||||
/** A tile orientation constant indicating the tile is rotated 270
|
||||
* degrees clockwise from its default orientation. */
|
||||
public static final int WEST = 3;
|
||||
|
||||
/** A mapping from orientation codes to a string representation. */
|
||||
public static final String[] ORIENT_NAMES = { "N", "E", "S", "W" };
|
||||
|
||||
|
||||
/** The tile image width in pixels. */
|
||||
public static int TILE_WIDTH = 64;
|
||||
|
||||
/** The tile image height in pixels. */
|
||||
public static int TILE_HEIGHT = 64;
|
||||
|
||||
|
||||
/** A tile edge constant indicating a city edge. */
|
||||
public static final int CITY = 0;
|
||||
|
||||
/** A tile edge constant indicating a grass edge. */
|
||||
public static final int GRASS = 1;
|
||||
|
||||
/** A tile edge constant indicating a road edge. */
|
||||
public static final int ROAD = 2;
|
||||
|
||||
/** A constant indicating a cloister. */
|
||||
public static final int CLOISTER = 3;
|
||||
|
||||
/** Human readable names to go along with the feature constants. */
|
||||
public static final String[] FEATURE_NAMES = {
|
||||
"island", "fishery", "boardwalk", "temple" };
|
||||
|
||||
/** A flag used to mark a tile as part of a completed city. */
|
||||
public static final int COMPLETED_CITY = 0x01;
|
||||
}
|
||||
@@ -1,763 +0,0 @@
|
||||
//
|
||||
// $Id: AtlantiManager.java,v 1.26 2004/08/28 02:17:06 mdb Exp $
|
||||
|
||||
package com.samskivert.atlanti.server;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import com.samskivert.util.HashIntMap;
|
||||
import com.samskivert.util.StringUtil;
|
||||
|
||||
import com.threerings.presents.dobj.EntryAddedEvent;
|
||||
import com.threerings.presents.dobj.EntryRemovedEvent;
|
||||
import com.threerings.presents.dobj.EntryUpdatedEvent;
|
||||
import com.threerings.presents.dobj.DSet;
|
||||
import com.threerings.presents.dobj.SetListener;
|
||||
import com.threerings.presents.dobj.MessageEvent;
|
||||
|
||||
import com.threerings.presents.dobj.MessageEvent;
|
||||
|
||||
import com.threerings.crowd.chat.server.SpeakProvider;
|
||||
import com.threerings.crowd.data.PlaceObject;
|
||||
|
||||
import com.threerings.crowd.data.PlaceConfig;
|
||||
import com.threerings.crowd.server.PlaceManager;
|
||||
|
||||
import com.threerings.parlor.game.GameManager;
|
||||
import com.threerings.parlor.turn.TurnGameManager;
|
||||
|
||||
import com.samskivert.atlanti.Log;
|
||||
import com.samskivert.atlanti.data.AtlantiCodes;
|
||||
import com.samskivert.atlanti.data.AtlantiObject;
|
||||
import com.samskivert.atlanti.data.AtlantiTile;
|
||||
import com.samskivert.atlanti.data.Feature;
|
||||
import com.samskivert.atlanti.data.Piecen;
|
||||
import com.samskivert.atlanti.data.TileCodes;
|
||||
import com.samskivert.atlanti.util.FeatureUtil;
|
||||
import com.samskivert.atlanti.util.TileUtil;
|
||||
|
||||
/**
|
||||
* The main coordinator of the Atlantissonne game on the server side.
|
||||
*/
|
||||
public class AtlantiManager extends GameManager
|
||||
implements TurnGameManager, AtlantiCodes, SetListener
|
||||
{
|
||||
public AtlantiManager ()
|
||||
{
|
||||
addDelegate(_delegate = new AtlantiManagerDelegate(this));
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
protected Class getPlaceObjectClass ()
|
||||
{
|
||||
return AtlantiObject.class;
|
||||
}
|
||||
|
||||
public int getTilesInBox ()
|
||||
{
|
||||
return _tilesInBox.size();
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void didInit ()
|
||||
{
|
||||
super.didInit();
|
||||
|
||||
// register our message handlers
|
||||
registerMessageHandler(PLACE_TILE_REQUEST, new PlaceTileHandler());
|
||||
registerMessageHandler(
|
||||
PLACE_PIECEN_REQUEST, new PlacePiecenHandler());
|
||||
registerMessageHandler(
|
||||
PLACE_NOTHING_REQUEST, new PlaceNothingHandler());
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void didStartup ()
|
||||
{
|
||||
super.didStartup();
|
||||
|
||||
// grab our own casted game object reference
|
||||
_atlobj = (AtlantiObject)_gameobj;
|
||||
}
|
||||
|
||||
/**
|
||||
* In preparation for starting the game, we clear out the tile set and
|
||||
* put the starting tile into place.
|
||||
*/
|
||||
protected void gameWillStart ()
|
||||
{
|
||||
super.gameWillStart();
|
||||
|
||||
// generate a shuffled tile list
|
||||
_tilesInBox = TileUtil.getStandardTileSet();
|
||||
Collections.shuffle(_tilesInBox);
|
||||
|
||||
// // shave off most of the tiles for the moment
|
||||
// while (_tilesInBox.size() > 15) {
|
||||
// _tilesInBox.remove(0);
|
||||
// }
|
||||
|
||||
// clear out our board tiles
|
||||
_tiles.clear();
|
||||
|
||||
// create a claim group vector
|
||||
_claimGroupVector = new int[getPlayerCount()];
|
||||
|
||||
// clear out the scores
|
||||
_atlobj.setScores(new int[getPlayerCount()]);
|
||||
|
||||
// clear out the tile and piecen set
|
||||
_atlobj.setTiles(new DSet());
|
||||
_atlobj.setPiecens(new DSet());
|
||||
|
||||
// and add the starting tile
|
||||
AtlantiTile start = TileUtil.getStartingTile();
|
||||
_atlobj.addToTiles(start);
|
||||
_tiles.add(start);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void turnWillStart ()
|
||||
{
|
||||
// let the players know what the next tile is that should be
|
||||
// played
|
||||
AtlantiTile tile = (AtlantiTile)_tilesInBox.remove(0);
|
||||
_atlobj.setCurrentTile(tile);
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void turnDidStart ()
|
||||
{
|
||||
// nothing doing
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void turnDidEnd ()
|
||||
{
|
||||
// if there are no tiles left, we end the game
|
||||
if (_tilesInBox.size() == 0) {
|
||||
endGame();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* At the end of the game, we need to compute the final scores.
|
||||
*/
|
||||
protected void gameDidEnd ()
|
||||
{
|
||||
super.gameDidEnd();
|
||||
|
||||
// compute the final scores by iterating over each tile and
|
||||
// scoring its features
|
||||
Piecen[] piecens = getPiecens();
|
||||
Iterator iter = _atlobj.tiles.entries();
|
||||
while (iter.hasNext()) {
|
||||
AtlantiTile tile = (AtlantiTile)iter.next();
|
||||
scoreFeatures(tile, piecens, true);
|
||||
}
|
||||
|
||||
// lastly, we have to score the farms (cue the ominous drums)...
|
||||
scoreFarms();
|
||||
|
||||
// update the final scores
|
||||
_atlobj.setScores(_atlobj.scores);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of piecens based on the contents of the piecens
|
||||
* set in the game object, suitable for passing to {@link
|
||||
* #scoreFeatures}.
|
||||
*/
|
||||
protected Piecen[] getPiecens ()
|
||||
{
|
||||
// create a piecen array that we can manipulate while scoring
|
||||
Piecen[] piecens = new Piecen[_atlobj.piecens.size()];
|
||||
Iterator iter = _atlobj.piecens.entries();
|
||||
for (int i = 0; iter.hasNext(); i++) {
|
||||
piecens[i] = (Piecen)iter.next();
|
||||
}
|
||||
return piecens;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scores the features on this tile.
|
||||
*
|
||||
* @param tile the tile whose features should be scored.
|
||||
* @param piecens an array of the pieces on the board which we can
|
||||
* manipulate directly without having to wait for entry removed
|
||||
* events to be dispatched.
|
||||
* @param finalTally during the final tally, we score differently and
|
||||
* we don't remove piecens from the board as we score them.
|
||||
*/
|
||||
protected void scoreFeatures (
|
||||
AtlantiTile tile, Piecen[] piecens, boolean finalTally)
|
||||
{
|
||||
// potentially score all features on the tile
|
||||
for (int i = 0; i < tile.features.length; i++) {
|
||||
// we only need to worry about ROAD and CITY features because
|
||||
// those are the only features on this tile that we might have
|
||||
// completed
|
||||
Feature f = tile.features[i];
|
||||
if (f.type != TileCodes.CITY && f.type != TileCodes.ROAD) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// see if any piecens are even on a feature in this group
|
||||
int cgroup = tile.claims[i];
|
||||
int[] cgv = getClaimGroupVector(cgroup, piecens);
|
||||
if (cgv == null) {
|
||||
// if not, we don't have anything to score
|
||||
// Log.info("Not scoring unclaimed feature " +
|
||||
// "[ttype=" + tile.type + ", feat=" + f +
|
||||
// ", cgroup=" + cgroup + "].");
|
||||
continue;
|
||||
}
|
||||
|
||||
// we do have something to score, so we compute the score for
|
||||
// this feature
|
||||
int score = TileUtil.computeFeatureScore(_tiles, tile, i);
|
||||
|
||||
// if the score is positive, it's a completed feature and we
|
||||
// score it regardless, we score incomplete features only
|
||||
// during the final tally
|
||||
if (score > 0 || finalTally) {
|
||||
String qual = (score > 0) ? "Completed" : "Incomplete";
|
||||
|
||||
// convert the score into a positive value
|
||||
score = Math.abs(score);
|
||||
|
||||
// adjust and report the scores
|
||||
StringBuffer names = new StringBuffer();
|
||||
for (int p = 0; p < cgv.length; p++) {
|
||||
// adjust the score
|
||||
_atlobj.scores[p] += (score * cgv[p]);
|
||||
|
||||
// append the scorers name to the list
|
||||
if (cgv[p] > 0) {
|
||||
if (names.length() > 0) {
|
||||
names.append(", ");
|
||||
}
|
||||
names.append(getPlayerName(p));
|
||||
}
|
||||
}
|
||||
|
||||
String message = qual + " " + TileCodes.FEATURE_NAMES[f.type] +
|
||||
" scored " + score + " points for " + names + ".";
|
||||
SpeakProvider.sendInfo(
|
||||
_atlobj, ATLANTI_MESSAGE_BUNDLE, message);
|
||||
|
||||
Log.info("New scores: " + StringUtil.toString(_atlobj.scores));
|
||||
|
||||
// broadcast the new scores if this isn't the final tally
|
||||
if (!finalTally) {
|
||||
_atlobj.setScores(_atlobj.scores);
|
||||
}
|
||||
|
||||
// and free up the scored piecens
|
||||
removePiecens(cgroup, piecens, finalTally);
|
||||
|
||||
} else {
|
||||
// Log.info("Not scoring incomplete feature " +
|
||||
// "[ttype=" + tile.type + ", feat=" + f +
|
||||
// ", score=" + score + "].");
|
||||
}
|
||||
}
|
||||
|
||||
// we also may have completed a cloister, so we check that as well
|
||||
for (int dx = -1; dx < 2; dx++) {
|
||||
for (int dy = -1; dy < 2; dy++) {
|
||||
// find our neighbor and make sure they exist
|
||||
AtlantiTile neighbor =
|
||||
TileUtil.findTile(_tiles, tile.x + dx, tile.y + dy);
|
||||
if (neighbor == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// scan their features arrays for claimed cloisters
|
||||
for (int i = 0; i < neighbor.features.length; i++) {
|
||||
Feature f = neighbor.features[i];
|
||||
Piecen p = neighbor.piecen;
|
||||
|
||||
// is a cloister
|
||||
if (f.type != TileCodes.CLOISTER) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// tile has a piecen
|
||||
if (p == null) {
|
||||
// Log.info("Skipping non-piecen having " +
|
||||
// "cloister tile [tile=" + neighbor +
|
||||
// ", feat=" + f + "].");
|
||||
continue;
|
||||
}
|
||||
|
||||
// piecen is on cloister feature
|
||||
if (neighbor.claims[i] != p.claimGroup) {
|
||||
// Log.info("Skipping cloister tile with piecen on " +
|
||||
// "non-cloister [tile=" + neighbor +
|
||||
// ", feat=" + f + "].");
|
||||
continue;
|
||||
}
|
||||
|
||||
// score the cloister
|
||||
int score = TileUtil.computeFeatureScore(
|
||||
_tiles, neighbor, i);
|
||||
|
||||
// if it's completed or if we're doing the final
|
||||
// tally, we score it
|
||||
if (score > 0 || finalTally) {
|
||||
String qual = (score > 0) ?
|
||||
"complete" : "incomplete";
|
||||
|
||||
// coerce the score into positive land
|
||||
score = Math.abs(score);
|
||||
|
||||
// deliver a chat notification to tell the
|
||||
// players about the score
|
||||
String message = getPlayerName(p.owner) + " scored " +
|
||||
score + " points for " + qual + " temple.";
|
||||
SpeakProvider.sendInfo(
|
||||
_atlobj, ATLANTI_MESSAGE_BUNDLE, message);
|
||||
|
||||
// add the score to the owning player
|
||||
_atlobj.scores[p.owner] += score;
|
||||
|
||||
// only broadcast the updated scores if this isn't
|
||||
// the final tally
|
||||
if (!finalTally) {
|
||||
_atlobj.setScores(_atlobj.scores);
|
||||
}
|
||||
|
||||
// and clear out the piecen (only removing it from
|
||||
// the piecen set if we're not in the final tally)
|
||||
removePiecen(p, !finalTally);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scores the farms, which is the final act of scoring.
|
||||
*/
|
||||
protected void scoreFarms ()
|
||||
{
|
||||
HashIntMap cities = new HashIntMap();
|
||||
int[] cityScores = new int[getPlayerCount()];
|
||||
|
||||
// clear out the claims for incompleted cities and claim unclaimed
|
||||
// completed cities
|
||||
TileUtil.prepCitiesForScoring(_tiles);
|
||||
|
||||
// do the big process-ola
|
||||
int tsize = _tiles.size();
|
||||
for (int i = 0; i < tsize; i++) {
|
||||
AtlantiTile tile = (AtlantiTile)_tiles.get(i);
|
||||
|
||||
// iterate over all of the city features in this tile
|
||||
for (int f = 0; f < tile.features.length; f++) {
|
||||
// get the claim group for this feature
|
||||
int cityClaim = tile.claims[f];
|
||||
|
||||
// skip unclaimed and non-city features
|
||||
if (tile.features[f].type != TileCodes.CITY ||
|
||||
cityClaim == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// get the list associated with this claim group
|
||||
int[] claims = (int[])cities.get(cityClaim);
|
||||
if (claims == null) {
|
||||
// create a claim vector if we've not got one. if a
|
||||
// city had 35 separately claimed farms around it, all
|
||||
// the piecens in the game would be in play and the
|
||||
// city would not have been claimed which would be an
|
||||
// extremely pathological case, but we love pathology
|
||||
// (especially when we don't have a resizable int list
|
||||
// class handy)
|
||||
claims = new int[35];
|
||||
cities.put(cityClaim, claims);
|
||||
}
|
||||
|
||||
// iterate over all of the grass features that are
|
||||
// connected to city features on this tile and add their
|
||||
// claim groups the list for this city feature
|
||||
int[] grasses = FeatureUtil.CITY_GRASS_MAP[tile.type-1];
|
||||
for (int g = 0; g < grasses.length; g++) {
|
||||
int farmClaim = tile.claims[grasses[g]];
|
||||
|
||||
// only worry about claimed grass regions
|
||||
if (farmClaim == 0) {
|
||||
Log.info("Ignoring unclaimed farm group " +
|
||||
"[tile=" + tile +
|
||||
", fidx=" + grasses[g] + "].");
|
||||
continue;
|
||||
}
|
||||
|
||||
// and the farm claim group to the list
|
||||
for (int c = 0; c < claims.length; c++) {
|
||||
// don't add the farm claim twice
|
||||
if (claims[c] == farmClaim) {
|
||||
break;
|
||||
} else if (claims[c] == 0) {
|
||||
claims[c] = farmClaim;
|
||||
Log.info("Noting city/farm abuttal " +
|
||||
"[tile=" + tile +
|
||||
", cityClaim=" + cityClaim +
|
||||
", farmClaim=" + farmClaim + "].");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now for each city, we look to see who has the most piecens that
|
||||
// are connected to the city by farms
|
||||
Iterator iter = cities.keys();
|
||||
while (iter.hasNext()) {
|
||||
int cityClaim = ((Integer)iter.next()).intValue();
|
||||
int[] farmClaims = (int[])cities.get(cityClaim);
|
||||
int[] pcount = new int[getPlayerCount()];
|
||||
int max = 0;
|
||||
|
||||
Iterator piter = _atlobj.piecens.entries();
|
||||
while (piter.hasNext()) {
|
||||
Piecen p = (Piecen)piter.next();
|
||||
// see if the piecen is on any of the farms
|
||||
for (int c = 0; c < farmClaims.length; c++) {
|
||||
if (p.claimGroup == farmClaims[c]) {
|
||||
Log.info("Counting piecen [cityClaim=" + cityClaim +
|
||||
", farmClaim=" + farmClaims[c] +
|
||||
", piecen=" + p + "].");
|
||||
// increment their count and track the max
|
||||
if (max < ++pcount[p.owner]) {
|
||||
max = pcount[p.owner];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Log.info("Counted city [cityClaim=" + cityClaim +
|
||||
", counts=" + StringUtil.toString(pcount) + "].");
|
||||
|
||||
// ignore this city if no one has any farmers nearby
|
||||
if (max == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// now score four points for every player that has the max
|
||||
for (int i = 0; i < pcount.length; i++) {
|
||||
if (pcount[i] == max) {
|
||||
Log.info("Scoring city for player [cgroup=" + cityClaim +
|
||||
", player=" + getPlayerName(i) +
|
||||
", pcount=" + pcount[i] + "].");
|
||||
cityScores[i] += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now report the scoring and transfer the counts to the score
|
||||
// array
|
||||
for (int i = 0; i < getPlayerCount(); i++) {
|
||||
if (cityScores[i] > 0) {
|
||||
_atlobj.scores[i] += cityScores[i];
|
||||
String message = getPlayerName(i) + " scores " +
|
||||
cityScores[i] + " points for fisheries.";
|
||||
SpeakProvider.sendInfo(
|
||||
_atlobj, ATLANTI_MESSAGE_BUNDLE, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an int array with zeros and ones in the appropriate places
|
||||
* so that a score can be multiplied by a player's position in the
|
||||
* vector to determine whether or not they receive any points for the
|
||||
* scoring of a particular claim group.
|
||||
*
|
||||
* <p> Note that this function returns a static (to this instance)
|
||||
* vector, so it cannot be called again without overwriting values
|
||||
* returned previously.
|
||||
*
|
||||
* @param claimGroup the claim group that we're scoring.
|
||||
* @param piecens an array to use when looking for matching piecens.
|
||||
*
|
||||
* @return an array for the specified claim group or null if no
|
||||
* players have a piecen claiming the specified claim group.
|
||||
*/
|
||||
protected int[] getClaimGroupVector (int claimGroup, Piecen[] piecens)
|
||||
{
|
||||
// clear out the vector
|
||||
Arrays.fill(_claimGroupVector, 0);
|
||||
|
||||
// iterate over the piecens
|
||||
int max = 0;
|
||||
for (int i = 0; i < piecens.length; i++) {
|
||||
Piecen piecen = piecens[i];
|
||||
if (piecen == null) {
|
||||
continue;
|
||||
} else if (piecen.claimGroup == claimGroup) {
|
||||
// color == player index... somewhat sketchy
|
||||
if (++_claimGroupVector[piecen.owner] > max) {
|
||||
// keep track of the highest scorer
|
||||
max = _claimGroupVector[piecen.owner];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now cut out everyone with scores less than the highest score
|
||||
for (int i = 0; i < _claimGroupVector.length; i++) {
|
||||
_claimGroupVector[i] = (_claimGroupVector[i] < max) ? 0 : 1;
|
||||
}
|
||||
|
||||
return (max == 0) ? null : _claimGroupVector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes piecens either from the supplied array or from the game
|
||||
* object piecen set if no array is supplied.
|
||||
*/
|
||||
protected void removePiecens (int claimGroup, Piecen[] piecens,
|
||||
boolean finalTally)
|
||||
{
|
||||
// we always clear the piecens from the array
|
||||
for (int i = 0; i < piecens.length; i++) {
|
||||
if (piecens[i] == null) {
|
||||
continue;
|
||||
} else if (piecens[i].claimGroup == claimGroup) {
|
||||
piecens[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
// if this isn't the final tally, we also clear 'em from the board
|
||||
if (!finalTally) {
|
||||
Object[] pvec = _atlobj.piecens.toArray(null);
|
||||
for (int ii = 0; ii < pvec.length; ii++) {
|
||||
Piecen p = (Piecen)pvec[ii];
|
||||
if (p.claimGroup == claimGroup) {
|
||||
removePiecen(p, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the piecen from the board and optionally removes it from
|
||||
* the piecen set.
|
||||
*
|
||||
* @param piecen the piecen to be removed.
|
||||
* @param removeFromPiecens if true, the piecen will also be removed
|
||||
* from the piecens set in the game object.
|
||||
*/
|
||||
protected void removePiecen (Piecen piecen, boolean removeFromPiecens)
|
||||
{
|
||||
// locate the tile that contains this piecen
|
||||
int tidx = _tiles.indexOf(piecen);
|
||||
if (tidx == -1) {
|
||||
Log.warning("Requested to remove piecen that is not " +
|
||||
"associated with any tile [piecen=" + piecen + "].");
|
||||
} else {
|
||||
AtlantiTile tile = (AtlantiTile)_tiles.get(tidx);
|
||||
// and clear the piecen
|
||||
tile.clearPiecen();
|
||||
}
|
||||
|
||||
// also remove from the piecens dset if requested
|
||||
if (removeFromPiecens) {
|
||||
_atlobj.removeFromPiecens(piecen.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void entryAdded (EntryAddedEvent event)
|
||||
{
|
||||
// we react to piecen additions by potentially scoring the placed
|
||||
// piecen. we allow the piecen to be added to the piecens set
|
||||
// before scoring so that the players can see the piecen pop up on
|
||||
// their screen and then disappear with a scoring notice rather
|
||||
// than never show up at all; plus it simplifies our code
|
||||
if (event.getName().equals(AtlantiObject.PIECENS)) {
|
||||
Piecen piecen = (Piecen)event.getEntry();
|
||||
|
||||
// make sure this is a valid placement
|
||||
AtlantiTile tile = (AtlantiTile)_atlobj.tiles.get(piecen.getKey());
|
||||
if (tile == null) {
|
||||
Log.warning("Can't find tile for piecen scoring " +
|
||||
piecen + ".");
|
||||
|
||||
} else {
|
||||
// check to see if we added the piecen to a completed
|
||||
// feature, in which case we score and remove it
|
||||
scoreFeatures(tile, getPiecens(), false);
|
||||
}
|
||||
|
||||
// now that we've scored the piecen, we can end the turn
|
||||
_delegate.endTurn();
|
||||
}
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void entryUpdated (EntryUpdatedEvent event)
|
||||
{
|
||||
}
|
||||
|
||||
// documentation inherited
|
||||
public void entryRemoved (EntryRemovedEvent event)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the user requests to place a tile.
|
||||
*/
|
||||
protected void handlePlaceTileRequest (MessageEvent event)
|
||||
{
|
||||
AtlantiTile tile = (AtlantiTile)event.getArgs()[0];
|
||||
int pidx = _delegate.getTurnHolderIndex();
|
||||
|
||||
// make sure it's this player's turn
|
||||
if (_playerOids[pidx] != event.getSourceOid()) {
|
||||
Log.warning("Requested to place tile by non-turn holder " +
|
||||
"[event=" + event +
|
||||
", turnHolder=" + _atlobj.turnHolder + "].");
|
||||
|
||||
// make sure this is a valid placement
|
||||
} else if (TileUtil.isValidPlacement(_tiles, tile)) {
|
||||
// add the tile to the list and resort it
|
||||
_tiles.add(tile);
|
||||
Collections.sort(_tiles);
|
||||
|
||||
// inherit its claim groups
|
||||
TileUtil.inheritClaims(_tiles, tile);
|
||||
|
||||
// add the tile to the tiles set
|
||||
_atlobj.addToTiles(tile);
|
||||
|
||||
// placing a piece may have completed road or city
|
||||
// features. if it did, we score them now
|
||||
scoreFeatures(tile, getPiecens(), false);
|
||||
|
||||
Log.info("Placed tile " + tile + ".");
|
||||
|
||||
// if the player has no free piecens or if there are no
|
||||
// unclaimed features on this tile, we end their turn
|
||||
// straight away
|
||||
int pcount = TileUtil.countPiecens(_atlobj.piecens, pidx);
|
||||
if (pcount >= PIECENS_PER_PLAYER ||
|
||||
!tile.hasUnclaimedFeature()) {
|
||||
_delegate.endTurn();
|
||||
}
|
||||
|
||||
} else {
|
||||
Log.warning("Received invalid placement " + event + ".");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the user requests to place a piecen.
|
||||
*/
|
||||
protected void handlePlacePiecenRequest (MessageEvent event)
|
||||
{
|
||||
Piecen piecen = (Piecen)event.getArgs()[0];
|
||||
AtlantiTile tile = (AtlantiTile)_atlobj.tiles.get(piecen.getKey());
|
||||
int pidx = _delegate.getTurnHolderIndex();
|
||||
int pcount = TileUtil.countPiecens(_atlobj.piecens, pidx);
|
||||
|
||||
// make sure it's this player's turn
|
||||
if (_playerOids[pidx] != event.getSourceOid()) {
|
||||
Log.warning("Requested to place piecen by non-turn holder " +
|
||||
"[event=" + event +
|
||||
", turnHolder=" + _atlobj.turnHolder + "].");
|
||||
|
||||
// do some checking before we place the piecen
|
||||
} else if (pcount >= PIECENS_PER_PLAYER) {
|
||||
Log.warning("Requested to place piecen for player that " +
|
||||
"has all of their piecens in play " +
|
||||
"[event=" + event + "].");
|
||||
|
||||
} else if (tile == null) {
|
||||
Log.warning("Can't find tile for requested piecen " +
|
||||
"placement " + piecen + ".");
|
||||
|
||||
} else if (tile.claims[piecen.featureIndex] != 0) {
|
||||
Log.warning("Requested to place piecen on claimed feature " +
|
||||
"[tile=" + tile + ", piecen=" + piecen + "].");
|
||||
|
||||
} else {
|
||||
// otherwise stick the piece in the tile to update the
|
||||
// claim groups
|
||||
tile.setPiecen(piecen, _tiles);
|
||||
|
||||
// and add the piecen to the game object. when we receive
|
||||
// the piecen added event, we'll score it and then end the
|
||||
// turn
|
||||
_atlobj.addToPiecens(piecen);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the user requests to forgo their piecen placement for
|
||||
* this turn.
|
||||
*/
|
||||
protected void handlePlaceNothingRequest (MessageEvent event)
|
||||
{
|
||||
int pidx = _delegate.getTurnHolderIndex();
|
||||
if (_playerOids[pidx] != event.getSourceOid()) {
|
||||
Log.warning("Requested to place nothing by non-turn holder " +
|
||||
"[event=" + event +
|
||||
", turnHolder=" + _atlobj.turnHolder + "].");
|
||||
|
||||
} else {
|
||||
// player doesn't want to place anything, so we just end
|
||||
// the turn
|
||||
_delegate.endTurn();
|
||||
}
|
||||
}
|
||||
|
||||
/** Handles place tile requests. */
|
||||
protected class PlaceTileHandler implements MessageHandler
|
||||
{
|
||||
public void handleEvent (MessageEvent event, PlaceManager pmgr)
|
||||
{
|
||||
handlePlaceTileRequest(event);
|
||||
}
|
||||
}
|
||||
|
||||
/** Handles place piecen requests. */
|
||||
protected class PlacePiecenHandler implements MessageHandler
|
||||
{
|
||||
public void handleEvent (MessageEvent event, PlaceManager pmgr)
|
||||
{
|
||||
handlePlacePiecenRequest(event);
|
||||
}
|
||||
}
|
||||
|
||||
/** Handles place nothing requests. */
|
||||
protected class PlaceNothingHandler implements MessageHandler
|
||||
{
|
||||
public void handleEvent (MessageEvent event, PlaceManager pmgr)
|
||||
{
|
||||
handlePlaceNothingRequest(event);
|
||||
}
|
||||
}
|
||||
|
||||
/** Our turn game delegate. */
|
||||
protected AtlantiManagerDelegate _delegate;
|
||||
|
||||
/** A casted reference to our Atlanti game object. */
|
||||
protected AtlantiObject _atlobj;
|
||||
|
||||
/** The (shuffled) list of tiles remaining to be played in this
|
||||
* game. */
|
||||
protected List _tilesInBox;
|
||||
|
||||
/** A sorted list of the tiles that have been placed on the board. */
|
||||
protected List _tiles = new ArrayList();
|
||||
|
||||
/** Used to score features groups. */
|
||||
protected int[] _claimGroupVector;
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
//
|
||||
// $Id: AtlantiManagerDelegate.java,v 1.2 2002/12/12 05:51:54 mdb Exp $
|
||||
|
||||
package com.samskivert.atlanti.server;
|
||||
|
||||
import com.threerings.parlor.turn.TurnGameManagerDelegate;
|
||||
|
||||
import com.samskivert.atlanti.data.AtlantiCodes;
|
||||
|
||||
/**
|
||||
* Handles the turn-based gameplay.
|
||||
*/
|
||||
public class AtlantiManagerDelegate extends TurnGameManagerDelegate
|
||||
implements AtlantiCodes
|
||||
{
|
||||
/**
|
||||
* Constructs the delegate and prepares it for operation.
|
||||
*/
|
||||
public AtlantiManagerDelegate (AtlantiManager vmgr)
|
||||
{
|
||||
super(vmgr);
|
||||
_amgr = vmgr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Continue the game until we're out of tiles.
|
||||
*/
|
||||
protected void setNextTurnHolder ()
|
||||
{
|
||||
// if we have tiles left, we move to the next player as normal
|
||||
if (_amgr.getTilesInBox() > 0) {
|
||||
super.setNextTurnHolder();
|
||||
} else {
|
||||
// if we don't, we ensure that a new turn isn't started by
|
||||
// setting _turnIdx to -1
|
||||
_turnIdx = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/** The manager for whom we're delegating. */
|
||||
protected AtlantiManager _amgr;
|
||||
}
|
||||
@@ -1,400 +0,0 @@
|
||||
//
|
||||
// $Id: FeatureUtil.java,v 1.6 2002/12/12 05:51:54 mdb Exp $
|
||||
|
||||
package com.samskivert.atlanti.util;
|
||||
|
||||
import java.awt.geom.Point2D;
|
||||
|
||||
import com.samskivert.atlanti.data.Feature;
|
||||
import com.samskivert.atlanti.data.TileCodes;
|
||||
|
||||
/**
|
||||
* Feature related constants and utility functions.
|
||||
*/
|
||||
public class FeatureUtil implements TileCodes
|
||||
{
|
||||
/** Bit mask for a north connecting feature. */
|
||||
public static final int NORTH_F = 0x1 << 0;
|
||||
|
||||
/** Bit mask for an east connecting feature. */
|
||||
public static final int EAST_F = 0x1 << 1;
|
||||
|
||||
/** Bit mask for a south connecting feature. */
|
||||
public static final int SOUTH_F = 0x1 << 2;
|
||||
|
||||
/** Bit mask for a west connecting feature. */
|
||||
public static final int WEST_F = 0x1 << 3;
|
||||
|
||||
/** Bit mask for a north by northeast connecting feature. */
|
||||
public static final int NNE_F = 0x1 << 4;
|
||||
|
||||
/** Bit mask for an east by northeast connecting feature. */
|
||||
public static final int ENE_F = 0x1 << 5;
|
||||
|
||||
/** Bit mask for an east by southeast connecting feature. */
|
||||
public static final int ESE_F = 0x1 << 6;
|
||||
|
||||
/** Bit mask for a south by southeast connecting feature. */
|
||||
public static final int SSE_F = 0x1 << 7;
|
||||
|
||||
/** Bit mask for a south by southwest connecting feature. */
|
||||
public static final int SSW_F = 0x1 << 8;
|
||||
|
||||
/** Bit mask for a west by southwest connecting feature. */
|
||||
public static final int WSW_F = 0x1 << 9;
|
||||
|
||||
/** Bit mask for a west by northwest connecting feature. */
|
||||
public static final int WNW_F = 0x1 << 10;
|
||||
|
||||
/** Bit mask for a north by northwest connecting feature. */
|
||||
public static final int NNW_F = 0x1 << 11;
|
||||
|
||||
/** A mapping from feature edge masks to tile directions and
|
||||
* corresponding feature edge masks. */
|
||||
public static final int[] ADJACENCY_MAP = new int[] {
|
||||
NORTH_F, NORTH, SOUTH_F,
|
||||
EAST_F, EAST, WEST_F,
|
||||
SOUTH_F, SOUTH, NORTH_F,
|
||||
WEST_F, WEST, EAST_F,
|
||||
NNW_F, NORTH, SSW_F,
|
||||
NNE_F, NORTH, SSE_F,
|
||||
ENE_F, EAST, WNW_F,
|
||||
ESE_F, EAST, WSW_F,
|
||||
SSE_F, SOUTH, NNE_F,
|
||||
SSW_F, SOUTH, NNW_F,
|
||||
WSW_F, WEST, ESE_F,
|
||||
WNW_F, WEST, ENE_F,
|
||||
};
|
||||
|
||||
/** A mapping for city tiles to the grass features that are adjacent
|
||||
* to the city tiles. */
|
||||
public static final int[][] CITY_GRASS_MAP = new int[][] {
|
||||
{ },
|
||||
{ 1 }, // CITY_THREE
|
||||
{ 1, 2 }, // CITY_THREE_ROAD
|
||||
{ 1 }, // CITY_TWO
|
||||
{ 1 }, // CITY_TWO_ROAD
|
||||
{ 1, 2 }, // CITY_TWO_ROAD_ACROSS
|
||||
{ 0 }, // TWO_CITY_TWO
|
||||
{ 0 }, // TWO_CITY_TWO_ACROSS
|
||||
{ 0 }, // CITY_ONE
|
||||
{ 0 }, // CITY_ONE_ROAD_RIGHT
|
||||
{ 0 }, // CITY_ONE_ROAD_LEFT
|
||||
{ 0 }, // CITY_ONE_ROAD_TEE
|
||||
{ 0 }, // CITY_ONE_ROAD_STRAIGHT
|
||||
{ },
|
||||
{ },
|
||||
{ },
|
||||
{ },
|
||||
{ },
|
||||
{ },
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the feature array for the tile of the specified type.
|
||||
*/
|
||||
public static Feature[] getTileFeatures (int type)
|
||||
{
|
||||
// create the features array
|
||||
Feature[] features = new Feature[TILE_FEATURES[type-1].length];
|
||||
|
||||
// initialize it with features from the repeated feature table or
|
||||
// with newly constructed features
|
||||
for (int i = 0; i < features.length; i++) {
|
||||
int[] desc = TILE_FEATURES[type-1][i];
|
||||
// if the description is a length one array, it is the index
|
||||
// into the reused feature table of the desired feature
|
||||
if (desc.length == 1) {
|
||||
features[i] = _reusedFeatures[desc[0]];
|
||||
} else {
|
||||
// otherwise it is the description of this unique feature
|
||||
features[i] = new Feature(desc);
|
||||
}
|
||||
}
|
||||
|
||||
return features;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the position of the shield on a tile of the given
|
||||
* orientation.
|
||||
*/
|
||||
public static Point2D getShieldSpot (int orientation)
|
||||
{
|
||||
return _shieldFeature.piecenSpots[orientation];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string describing the supplied type code.
|
||||
*/
|
||||
public static String typeToString (int type)
|
||||
{
|
||||
return TYPE_CODES[type];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string describing the supplied edge mask.
|
||||
*/
|
||||
public static String edgeMaskToString (int edgeMask)
|
||||
{
|
||||
StringBuffer buf = new StringBuffer();
|
||||
if ((edgeMask & NORTH_F) != 0) buf.append("NORTH_F|");
|
||||
if ((edgeMask & EAST_F) != 0) buf.append("EAST_F|");
|
||||
if ((edgeMask & SOUTH_F) != 0) buf.append("SOUTH_F|");
|
||||
if ((edgeMask & WEST_F) != 0) buf.append("WEST_F|");
|
||||
if ((edgeMask & NNW_F) != 0) buf.append("NNW_F|");
|
||||
if ((edgeMask & NNE_F) != 0) buf.append("NNE_F|");
|
||||
if ((edgeMask & SSW_F) != 0) buf.append("SSW_F|");
|
||||
if ((edgeMask & SSE_F) != 0) buf.append("SSE_F|");
|
||||
if ((edgeMask & WNW_F) != 0) buf.append("WNW_F|");
|
||||
if ((edgeMask & WSW_F) != 0) buf.append("WSW_F|");
|
||||
if ((edgeMask & ENE_F) != 0) buf.append("ENE_F|");
|
||||
if ((edgeMask & ESE_F) != 0) buf.append("ESE_F|");
|
||||
// strip off the trailing bar if there is one
|
||||
if (buf.length() > 0) {
|
||||
buf.deleteCharAt(buf.length()-1);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates the feature edge mask into the orientation specified.
|
||||
* For a forward translation, provide a positive valued orientation
|
||||
* constant. For a backward translation, provide a negative valued
|
||||
* orientation constant.
|
||||
*
|
||||
* @return the translated feature mask.
|
||||
*/
|
||||
public static int translateMask (int featureMask, int orientation)
|
||||
{
|
||||
int[] map = FEATURE_ORIENT_MAP[0];
|
||||
if ((featureMask & (NNE_F|ESE_F|SSW_F|WNW_F)) != 0) {
|
||||
map = FEATURE_ORIENT_MAP[1];
|
||||
} else if ((featureMask & (ENE_F|SSE_F|WSW_F|NNW_F)) != 0) {
|
||||
map = FEATURE_ORIENT_MAP[2];
|
||||
}
|
||||
return xlateMask(map, featureMask, orientation);
|
||||
}
|
||||
|
||||
/** {@link #translateMask} helper function. */
|
||||
protected static int xlateMask (
|
||||
int[] map, int featureMask, int orientation)
|
||||
{
|
||||
int index = 0;
|
||||
for (int i = 0; i < map.length; i++) {
|
||||
if (map[i] == featureMask) {
|
||||
return map[(i + 4 + orientation) % 4];
|
||||
}
|
||||
}
|
||||
return featureMask;
|
||||
}
|
||||
|
||||
/** A reused feature identifier. */
|
||||
protected static final int NESW_CITY = 0;
|
||||
|
||||
/** A reused feature identifier. */
|
||||
protected static final int NEW_CITY = 1;
|
||||
|
||||
/** A reused feature identifier. */
|
||||
protected static final int EW_CITY = 2;
|
||||
|
||||
/** A reused feature identifier. */
|
||||
protected static final int NW_CITY = 3;
|
||||
|
||||
/** A reused feature identifier. */
|
||||
protected static final int N_CITY = 4;
|
||||
|
||||
/** A reused feature identifier. */
|
||||
protected static final int E_CITY = 5;
|
||||
|
||||
/** A reused feature identifier. */
|
||||
protected static final int W_CITY = 6;
|
||||
|
||||
/** A reused feature identifier. */
|
||||
protected static final int E_ROAD = 7;
|
||||
|
||||
/** A reused feature identifier. */
|
||||
protected static final int S_ROAD = 8;
|
||||
|
||||
/** A reused feature identifier. */
|
||||
protected static final int W_ROAD = 9;
|
||||
|
||||
/** A reused feature identifier. */
|
||||
protected static final int S_GRASS = 10;
|
||||
|
||||
/** A reused feature identifier. */
|
||||
protected static final int SE_GRASS = 11;
|
||||
|
||||
/** A reused feature identifier. */
|
||||
protected static final int SW_GRASS = 12;
|
||||
|
||||
/** An array of features used more than once. */
|
||||
protected static final int[][] FEATURES = new int[][] {
|
||||
{ CITY, NORTH_F|EAST_F|SOUTH_F|WEST_F, // NESW_CITY
|
||||
2,2, 0,0, 4,0, 4,4, 0,4 },
|
||||
{ CITY, NORTH_F|EAST_F|WEST_F, // NEW_CITY
|
||||
2,2, 0,0, 4,0, 4,4, 3,3, 1,3, 0,4 },
|
||||
{ CITY, EAST_F|WEST_F, // EW_CITY
|
||||
2,2, 0,0, 1,1, 3,1, 4,0, 4,4, 3,3, 1,3, 0,4 },
|
||||
{ CITY, NORTH_F|WEST_F, // NW_CITY
|
||||
1,2, 0,0, 4,0, 0,4 },
|
||||
{ CITY, NORTH_F, // N_CITY
|
||||
2,-1, 0,0, 1,1, 3,1, 4,0 },
|
||||
{ CITY, EAST_F, // E_CITY
|
||||
-4,2, 4,0, 3,1, 3,3, 4,4 },
|
||||
{ CITY, WEST_F, // W_CITY
|
||||
-1,2, 0,0, 1,1, 1,3, 0,4 },
|
||||
{ ROAD, EAST_F, // E_ROAD
|
||||
3,2, 2,2, 4,2 },
|
||||
{ ROAD, SOUTH_F, // S_ROAD
|
||||
2,3, 2,2, 2,4 },
|
||||
{ ROAD, WEST_F, // W_ROAD
|
||||
1,2, 0,2, 2,2 },
|
||||
{ GRASS, SOUTH_F, // S_GRASS
|
||||
2,-4, 0,4, 1,3, 3,3, 4,4 },
|
||||
{ GRASS, ESE_F|SSE_F, // SE_GRASS
|
||||
-4,-4, 2,2, 4,2, 4,4, 2,4 },
|
||||
{ GRASS, WSW_F|SSW_F, // SW_GRASS
|
||||
-1,-4, 0,2, 2,2, 2,4, 0,4 },
|
||||
};
|
||||
|
||||
/** A feature that is used to obtain the position information for
|
||||
* rendering shields on city tiles that use shields. */
|
||||
protected static final int[] SHIELD_FEATURE = new int[]
|
||||
{ -1, NORTH_F|WEST_F, -1,-1, 0,0, 4,0, 0,4 };
|
||||
|
||||
/** A table describing the features of each tile. */
|
||||
protected static final int[][][] TILE_FEATURES = new int[][][] {
|
||||
// one must offset tile type by one when indexing into this array
|
||||
|
||||
{ { NESW_CITY } }, // CITY_FOUR
|
||||
|
||||
{ { NEW_CITY }, // CITY_THREE
|
||||
{ S_GRASS } },
|
||||
|
||||
{ { NEW_CITY }, // CITY_THREE_ROAD
|
||||
{ GRASS, SSW_F, 1,-4, 0,4, 1,3, 2,3, 2,4 },
|
||||
{ GRASS, SSE_F, 3,-4, 2,4, 2,3, 3,3, 4,4 },
|
||||
{ ROAD, SOUTH_F, 2,-4, 2,3, 2,4 } },
|
||||
|
||||
{ { NW_CITY }, // CITY_TWO
|
||||
{ GRASS, EAST_F|SOUTH_F, 3,-4, 0,4, 4,0, 4,4 } },
|
||||
|
||||
{ { NW_CITY }, // CITY_TWO_ROAD
|
||||
{ GRASS, ENE_F|SSW_F, -3,-2, 0,4, 4,0, 4,2, 2,4 },
|
||||
{ GRASS, ESE_F|SSE_F, -4,-4, 2,4, 4,2, 4,4 },
|
||||
{ ROAD, EAST_F|SOUTH_F, 3,3, 2,4, 4,2 } },
|
||||
|
||||
{ { EW_CITY }, // CITY_TWO_ACROSS
|
||||
{ GRASS, NORTH_F, 2,-1, 0,0, 1,1, 3,1, 4,0 },
|
||||
{ S_GRASS } },
|
||||
|
||||
{ { GRASS, WEST_F|SOUTH_F, // TWO_CITY_TWO
|
||||
-1,-3, 0,0, 4,0, 4,4, 0,4 },
|
||||
{ CITY, NORTH_F,
|
||||
2,-1, 0,0, 2,1, 4,0 },
|
||||
{ CITY, EAST_F,
|
||||
-4,2, 4,0, 3,2, 4,4 } },
|
||||
|
||||
{ { GRASS, NORTH_F|SOUTH_F, // TWO_CITY_TWO_ACROSS
|
||||
2,-4, 0,0, 4,0, 3,1, 3,3, 4,4, 0,4, 1,3, 1,1 },
|
||||
{ W_CITY },
|
||||
{ E_CITY } },
|
||||
|
||||
{ { GRASS, EAST_F|SOUTH_F|WEST_F, // CITY_ONE
|
||||
2,-3, 0,0, 1,1, 3,1, 4,0, 4,4, 0,4 },
|
||||
{ N_CITY } },
|
||||
|
||||
{ { GRASS, ENE_F|SSW_F|WEST_F, // CITY_ONE_ROAD_RIGHT
|
||||
1,2, 0,0, 1,1, 3,1, 4,0, 4,2, 2,2, 2,4, 0,4 },
|
||||
{ SE_GRASS },
|
||||
{ ROAD, EAST_F|SOUTH_F, 3,2, 4,2, 2,2, 2,4 },
|
||||
{ N_CITY } },
|
||||
|
||||
{ { GRASS, EAST_F|SSE_F|WNW_F, // CITY_ONE_ROAD_LEFT
|
||||
3,2, 0,0, 1,1, 3,1, 4,0, 4,4, 2,4, 2,2, 0,2 },
|
||||
{ SW_GRASS },
|
||||
{ ROAD, SOUTH_F|WEST_F, 1,2, 0,2, 2,2, 2,4 },
|
||||
{ N_CITY } },
|
||||
|
||||
{ { GRASS, ENE_F|WNW_F, // CITY_ONE_ROAD_TEE
|
||||
-1,1, 0,0, 1,1, 3,1, 4,0, 4,2, 0,2 },
|
||||
{ SE_GRASS },
|
||||
{ SW_GRASS },
|
||||
{ E_ROAD },
|
||||
{ S_ROAD },
|
||||
{ W_ROAD },
|
||||
{ N_CITY } },
|
||||
|
||||
{ { GRASS, ENE_F|WNW_F, // CITY_ONE_ROAD_STRAIGHT
|
||||
-1,1, 0,0, 1,1, 3,1, 4,0, 4,2, 0,2 },
|
||||
{ GRASS, ESE_F|SOUTH_F|WSW_F, 2,3, 0,2, 4,2, 4,4, 0,4 },
|
||||
{ ROAD, EAST_F|WEST_F, 2,2, 0,2, 4,2 },
|
||||
{ N_CITY } },
|
||||
|
||||
{ { GRASS, NORTH_F|EAST_F|SOUTH_F|WEST_F, // CLOISTER_PLAIN
|
||||
-1,-1, 0,0, 4,0, 4,4, 0,4 },
|
||||
{ CLOISTER, 0, 2,2, 1,1, 3,1, 3,3, 1,3 } },
|
||||
|
||||
{ { GRASS, NORTH_F|EAST_F|WEST_F|SSE_F|SSW_F, // CLOISTER_ROAD
|
||||
-1,-1, 0,0, 4,0, 4,4, 0,4 },
|
||||
{ CLOISTER, 0, 2,2, 1,1, 3,1, 3,3, 1,3 },
|
||||
{ ROAD, SOUTH_F, 2,-4, 2,3, 2,4 } },
|
||||
|
||||
{ { GRASS, WNW_F|NNW_F, // FOUR_WAY_ROAD
|
||||
-1,-1, 0,0, 2,0, 2,2, 0,2 },
|
||||
{ GRASS, NNE_F|ENE_F, -4,-1, 2,0, 4,0, 4,2, 2,2 },
|
||||
{ SE_GRASS },
|
||||
{ SW_GRASS },
|
||||
{ ROAD, NORTH_F, 2,1, 2,0, 2,2 },
|
||||
{ E_ROAD },
|
||||
{ S_ROAD },
|
||||
{ W_ROAD } },
|
||||
|
||||
{ { GRASS, WNW_F|NORTH_F|ENE_F, // THREE_WAY_ROAD
|
||||
2,-1, 0,0, 4,0, 4,2, 0,2 },
|
||||
{ SE_GRASS },
|
||||
{ SW_GRASS },
|
||||
{ E_ROAD },
|
||||
{ S_ROAD },
|
||||
{ W_ROAD } },
|
||||
|
||||
{ { GRASS, NNW_F|WEST_F|SSW_F, // STRAIGHT_ROAD
|
||||
-1,2, 0,0, 2,0, 2,4, 0,4 },
|
||||
{ GRASS, SSE_F|EAST_F|NNE_F, -4,2, 2,0, 4,0, 4,4, 2,4 },
|
||||
{ ROAD, NORTH_F|SOUTH_F, 2,2, 2,0, 2,4 } },
|
||||
|
||||
{ { GRASS, WNW_F|NORTH_F|EAST_F|SSE_F, // CURVED_ROAD
|
||||
3,1, 0,0, 4,0, 4,4, 2,4, 2,2, 0,2 },
|
||||
{ SW_GRASS },
|
||||
{ ROAD, SOUTH_F|WEST_F, 1,2, 0,2, 2,2, 2,4 } },
|
||||
};
|
||||
|
||||
/** Mapping table used to rotate feature facements. */
|
||||
protected static final int[][] FEATURE_ORIENT_MAP = new int[][] {
|
||||
// orientations rotate through one of three four-cycles
|
||||
{ NORTH_F, EAST_F, SOUTH_F, WEST_F },
|
||||
{ NNE_F, ESE_F, SSW_F, WNW_F },
|
||||
{ ENE_F, SSE_F, WSW_F, NNW_F },
|
||||
};
|
||||
|
||||
/** String representations of the feature type codes. */
|
||||
protected static final String[] TYPE_CODES = {
|
||||
"CITY", "GRASS", "ROAD", "CLOISTER" };
|
||||
|
||||
/** A table of features that are used on more than one tile. */
|
||||
protected static Feature[] _reusedFeatures;
|
||||
|
||||
/** The feature that provides the location information for shield
|
||||
* rendering. */
|
||||
protected static Feature _shieldFeature;
|
||||
|
||||
// create our reused features table
|
||||
static {
|
||||
_reusedFeatures = new Feature[FEATURES.length];
|
||||
for (int i = 0; i < FEATURES.length; i++) {
|
||||
_reusedFeatures[i] = new Feature(FEATURES[i]);
|
||||
}
|
||||
_shieldFeature = new Feature(SHIELD_FEATURE);
|
||||
}
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
//
|
||||
// $Id: PiecenUtil.java,v 1.4 2003/03/23 02:22:51 mdb Exp $
|
||||
|
||||
package com.samskivert.atlanti.util;
|
||||
|
||||
import java.awt.Image;
|
||||
|
||||
import com.threerings.media.tile.Tile;
|
||||
import com.threerings.media.tile.TileManager;
|
||||
import com.threerings.media.tile.UniformTileSet;
|
||||
|
||||
public class PiecenUtil
|
||||
{
|
||||
/**
|
||||
* Loads up the piecen images using the supplied tile manager.
|
||||
*/
|
||||
public static void init (TileManager tmgr)
|
||||
{
|
||||
UniformTileSet piecenSet = tmgr.loadTileSet(
|
||||
PIECEN_IMG_PATH, PIECEN_WIDTH, PIECEN_HEIGHT);
|
||||
_images = new Image[PIECEN_TYPES];
|
||||
for (int i = 0; i < PIECEN_TYPES; i++) {
|
||||
_images[i] = piecenSet.getRawTileImage(i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the piecen image for the specified piecen color.
|
||||
*/
|
||||
public static Image getPiecenImage (int color)
|
||||
{
|
||||
return _images[color];
|
||||
}
|
||||
|
||||
/** Our piecen images. */
|
||||
protected static Image[] _images;
|
||||
|
||||
/** The number of different colors of piecen. */
|
||||
protected static final int PIECEN_TYPES = 6;
|
||||
|
||||
/** The width of the piecen image in pixels. */
|
||||
protected static final int PIECEN_WIDTH = 16;
|
||||
|
||||
/** The height of the piecen image in pixels. */
|
||||
protected static final int PIECEN_HEIGHT = 16;
|
||||
|
||||
/** The path to the piecen image (relative to the resource
|
||||
* directory). */
|
||||
protected static final String PIECEN_IMG_PATH = "media/piecens.png";
|
||||
}
|
||||
@@ -1,734 +0,0 @@
|
||||
//
|
||||
// $Id: TileUtil.java,v 1.17 2002/12/12 05:51:55 mdb Exp $
|
||||
|
||||
package com.samskivert.atlanti.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import com.samskivert.util.IntTuple;
|
||||
|
||||
import com.threerings.presents.dobj.DSet;
|
||||
|
||||
import com.samskivert.atlanti.Log;
|
||||
import com.samskivert.atlanti.data.AtlantiTile;
|
||||
import com.samskivert.atlanti.data.Feature;
|
||||
import com.samskivert.atlanti.data.Piecen;
|
||||
import com.samskivert.atlanti.data.TileCodes;
|
||||
|
||||
/**
|
||||
* Utility functions relating to the Atlantissonne tiles.
|
||||
*/
|
||||
public class TileUtil implements TileCodes
|
||||
{
|
||||
/**
|
||||
* Returns an instance of the starting tile (properly cloned so that
|
||||
* it can be messed with by the server).
|
||||
*/
|
||||
public static AtlantiTile getStartingTile ()
|
||||
{
|
||||
return (AtlantiTile)AtlantiTile.STARTING_TILE.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list containing the standard tile set for the
|
||||
* Atlantissonne game. The list is a clone, so it can be bent, folded
|
||||
* and modified by the caller.
|
||||
*/
|
||||
public static List getStandardTileSet ()
|
||||
{
|
||||
// we need to deep copy the default tile set, so we can't just use
|
||||
// clone
|
||||
List tiles = new ArrayList();
|
||||
int tsize = TILE_SET.size();
|
||||
for (int i = 0; i < tsize; i++) {
|
||||
tiles.add(((AtlantiTile)TILE_SET.get(i)).clone());
|
||||
}
|
||||
return tiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scans the supplied tile set to determine which of the four
|
||||
* orientations of the supplied target tile would result in a valid
|
||||
* placement of that tile (valid placement meaning that all of its
|
||||
* edges match up with neighboring tiles, it abuts at least one tile
|
||||
* and it does not occupy the same space as any existing tile). The
|
||||
* position of the target tile is assumed to be the desired placement
|
||||
* position and the current orientation of the target tile is ignored.
|
||||
*
|
||||
* @param tiles a list of the tiles on the board.
|
||||
* @param target the tile whose valid orientations we wish to compute.
|
||||
*
|
||||
* @return an array of boolean values indicating whether or not the
|
||||
* tile can be placed in each of the cardinal directions (which match
|
||||
* up with the direction constants specified in {@link TileCodes}.
|
||||
*/
|
||||
public static boolean[] computeValidOrients (
|
||||
List tiles, AtlantiTile target)
|
||||
{
|
||||
// this contains a count of tiles that match up with the candidate
|
||||
// tile in each of its four orientations
|
||||
int[] matches = new int[4];
|
||||
|
||||
int tsize = tiles.size();
|
||||
for (int i = 0; i < tsize; i++) {
|
||||
AtlantiTile tile = (AtlantiTile)tiles.get(i);
|
||||
|
||||
// figure out where this tile is in relation to the candidate
|
||||
int xdiff = tile.x - target.x;
|
||||
int ydiff = tile.y - target.y;
|
||||
int sum = Math.abs(xdiff) + Math.abs(ydiff);
|
||||
|
||||
if (sum == 0) {
|
||||
// they overlap, nothing doing
|
||||
return new boolean[4];
|
||||
|
||||
} else if (sum == 1) {
|
||||
// they're neighbors, we may have a match
|
||||
int targetEdge = EDGE_MAP[(ydiff+1)*3 + xdiff+1];
|
||||
|
||||
// we want the edge of the placed tile that matches up
|
||||
// with the tile in the candidate location, but we also
|
||||
// need to take into account the orientation of the placed
|
||||
// tile
|
||||
int tileEdge = (targetEdge+(4-tile.orientation)+2) % 4;
|
||||
|
||||
// we iterate over the four possible orientations of the
|
||||
// target tile
|
||||
for (int o = 0; o < 4; o++) {
|
||||
// we compare the edge of the placed tile (which never
|
||||
// changes) with the edge of the target tile which is
|
||||
// adjusted based on the target tile's orientation
|
||||
if (getEdge(tile.type, tileEdge) ==
|
||||
getEdge(target.type, (targetEdge+(4-o)) % 4)) {
|
||||
// increment the edge matches
|
||||
matches[o]++;
|
||||
|
||||
} else {
|
||||
// if we have a mismatch, we want to ensure that
|
||||
// we screw this orientation up for good, so we
|
||||
// deduct a large value from the array to ensure
|
||||
// that it will remain less than zero regardless
|
||||
// of which of the other three tiles match in this
|
||||
// orientation
|
||||
matches[o] -= 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// for every orientation that we have a positive number of edge
|
||||
// matches, we have a valid orientation
|
||||
boolean[] orients = new boolean[4];
|
||||
for (int i = 0; i < matches.length; i++) {
|
||||
orients[i] = (matches[i] > 0);
|
||||
}
|
||||
return orients;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the position and orientation of the target tile is
|
||||
* legal given the placement of all of the existing tiles.
|
||||
*
|
||||
* @param tiles a list of the tiles already on the board.
|
||||
* @param target the tile whose validity we want to determine.
|
||||
*
|
||||
* @return true if the target tile is configured with a valid position
|
||||
* and orientation, false if it is not.
|
||||
*/
|
||||
public static boolean isValidPlacement (List tiles, AtlantiTile target)
|
||||
{
|
||||
boolean matchedAnEdge = false;
|
||||
|
||||
int tsize = tiles.size();
|
||||
for (int i = 0; i < tsize; i++) {
|
||||
AtlantiTile tile = (AtlantiTile)tiles.get(i);
|
||||
|
||||
// figure out where this tile is in relation to the candidate
|
||||
int xdiff = tile.x - target.x;
|
||||
int ydiff = tile.y - target.y;
|
||||
int sum = Math.abs(xdiff) + Math.abs(ydiff);
|
||||
|
||||
if (sum == 0) {
|
||||
// they overlap, nothing doing
|
||||
Log.warning("Tile overlaps another [candidate=" + target +
|
||||
", overlapped=" + tile + "].");
|
||||
return false;
|
||||
|
||||
} else if (sum == 1) {
|
||||
// they're neighbors, we may have a match
|
||||
int targetEdge = EDGE_MAP[(ydiff+1)*3 + xdiff+1];
|
||||
|
||||
// we want the edge of the placed tile that matches up
|
||||
// with the tile in the candidate location, but we also
|
||||
// need to take into account the orientation of the placed
|
||||
// tile
|
||||
int tileEdge = (targetEdge+(4-tile.orientation)+2) % 4;
|
||||
|
||||
// now rotate the target edge according to our orientation
|
||||
targetEdge = ((targetEdge+(4-target.orientation)) % 4);
|
||||
|
||||
// see if the edges match
|
||||
if (getEdge(tile.type, tileEdge) ==
|
||||
getEdge(target.type, targetEdge)) {
|
||||
// make a note that we matched at least one edge
|
||||
matchedAnEdge = true;
|
||||
|
||||
} else {
|
||||
// the edges don't match, nothing doing
|
||||
Log.warning("Edge mismatch [candidate=" + target +
|
||||
", tile=" + tile +
|
||||
", candidateEdge=" + targetEdge +
|
||||
", tileEdge=" + tileEdge + "].");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if we got this far, we didn't have any mismatches, so we need
|
||||
// only know that we matched at least one edge
|
||||
return matchedAnEdge;
|
||||
}
|
||||
|
||||
/**
|
||||
* When a tile is placed on the board, this method should be called on
|
||||
* it to propagate existing claims to the appropriate features on this
|
||||
* tile. It will determine if any city features are connected to
|
||||
* cities that are already claimed, and if any road features are
|
||||
* connected to roads that are already claimed and if any grassland is
|
||||
* connected to grassland that is claimed.
|
||||
*
|
||||
* <p> If, in the process of initializing the claims for this tile, we
|
||||
* discover that this tile connects two previously disconnected
|
||||
* claims, those claims will be joined. The affected tiles and piecens
|
||||
* will have their claim groups updated.
|
||||
*
|
||||
* @param tiles a sorted list of the tiles on the board (which need
|
||||
* not include the tile whose features are being configured).
|
||||
* @param tile the tile whose features should be configured.
|
||||
*/
|
||||
public static void inheritClaims (List tiles, AtlantiTile tile)
|
||||
{
|
||||
List flist = new ArrayList();
|
||||
|
||||
// for each feature in the tile, load up its claim group and make
|
||||
// sure all features in that group (which will include our new
|
||||
// feature) now have the same claim number
|
||||
for (int i = 0; i < tile.features.length; i ++) {
|
||||
int claimGroup = 0;
|
||||
|
||||
// clear out the tilefeatures list before enumerating
|
||||
flist.clear();
|
||||
|
||||
// enumerate the claim group for this feature
|
||||
enumerateGroup(tiles, tile, i, flist);
|
||||
|
||||
// find the first non-zero claim number
|
||||
for (int t = 0; t < flist.size(); t++) {
|
||||
TileFeature feat = (TileFeature)flist.get(t);
|
||||
int fcg = feat.tile.claims[feat.featureIndex];
|
||||
if (fcg != 0) {
|
||||
claimGroup = fcg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if we found no non-zero claim number, we've nothing to
|
||||
// inherit
|
||||
if (claimGroup == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// otherwise, assign our new claim number to all members of
|
||||
// the group (potentially causing some to inherit the new
|
||||
// claim number)
|
||||
for (int t = 0; t < flist.size(); t++) {
|
||||
TileFeature feat = (TileFeature)flist.get(t);
|
||||
// set the claim group in the tile
|
||||
feat.tile.claims[feat.featureIndex] = claimGroup;
|
||||
// also set the claim group on the piecen if the tile has
|
||||
// an associated piecen that is on this feature
|
||||
Piecen p = feat.tile.piecen;
|
||||
if (p != null && p.featureIndex == feat.featureIndex) {
|
||||
p.claimGroup = claimGroup;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the claim group for the specified feature in this tile and
|
||||
* propagates that claim group to all connected features.
|
||||
*
|
||||
* @param tiles a sorted list of the tiles on the board.
|
||||
* @param tile the tile that contains the feature whose claim group is
|
||||
* being set.
|
||||
* @param featureIndex the index of the feature.
|
||||
* @param claimGroup the claim group value to set.
|
||||
*/
|
||||
public static void setClaimGroup (
|
||||
List tiles, AtlantiTile tile, int featureIndex, int claimGroup)
|
||||
{
|
||||
// load up this feature group
|
||||
List flist = new ArrayList();
|
||||
enumerateGroup(tiles, tile, featureIndex, flist);
|
||||
|
||||
// and assign the claim number to all features in the group
|
||||
for (int t = 0; t < flist.size(); t++) {
|
||||
TileFeature feat = (TileFeature)flist.get(t);
|
||||
feat.tile.claims[feat.featureIndex] = claimGroup;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the score for the specified feature and returns it. If the
|
||||
* feature is complete (has no unconnected edges), the score will be
|
||||
* positive. If it is incomplete, the score will be negative.
|
||||
*
|
||||
* @param tiles a sorted list of the tiles on the board.
|
||||
* @param tile the tile that contains the feature whose score should
|
||||
* be computed.
|
||||
* @param featureIndex the index of the feature in the containing
|
||||
* tile.
|
||||
*
|
||||
* @return a positive score for a completed feature group, a negative
|
||||
* score for a partial feature group.
|
||||
*/
|
||||
public static int computeFeatureScore (
|
||||
List tiles, AtlantiTile tile, int featureIndex)
|
||||
{
|
||||
Feature feature = tile.features[featureIndex];
|
||||
|
||||
if (feature.type == CLOISTER) {
|
||||
// cloister's score specially
|
||||
return computeCloisterScore(tiles, tile);
|
||||
|
||||
} else if (feature.type == GRASS) {
|
||||
// grass doesn't score
|
||||
return 0;
|
||||
}
|
||||
|
||||
// if we're here, it's a road or city feature, which we score by
|
||||
// loading up the group and counting the number of tiles in it
|
||||
List flist = new ArrayList();
|
||||
boolean complete = enumerateGroup(tiles, tile, featureIndex, flist);
|
||||
|
||||
// we sort the group which will order the tile feature objects by
|
||||
// their tiles, ensuring that features on the same tile are next
|
||||
// to one another, so that we can only count them once
|
||||
Collections.sort(flist);
|
||||
|
||||
// now iterate over the list, counting only unique tiles
|
||||
int score = 0;
|
||||
AtlantiTile lastTile = null;
|
||||
int fsize = flist.size();
|
||||
for (int i = 0; i < fsize; i++) {
|
||||
TileFeature feat = (TileFeature)flist.get(i);
|
||||
if (feat.tile != lastTile) {
|
||||
score++;
|
||||
lastTile = feat.tile;
|
||||
}
|
||||
}
|
||||
|
||||
// for city groups, we need to add a bonus of one for every tile
|
||||
// that contains a shield and mutiply by two if the city is
|
||||
// complete and larger than two tiles
|
||||
if (feature.type == CITY) {
|
||||
for (int t = 0; t < flist.size(); t++) {
|
||||
TileFeature feat = (TileFeature)flist.get(t);
|
||||
if (feat.tile.hasShield) {
|
||||
score++;
|
||||
}
|
||||
}
|
||||
if (complete && score > 2) {
|
||||
score *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
// incomplete scores are reported in the negative
|
||||
return complete ? score : -score;
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function for {@link
|
||||
* #computeFeatureScore(List,AtlantiTile,int)}.
|
||||
*/
|
||||
protected static int computeCloisterScore (List tiles, AtlantiTile tile)
|
||||
{
|
||||
int score = 0;
|
||||
|
||||
// all we need to know are how many neighbors this guy has (we
|
||||
// count ourselves as well, just for code simplicity)
|
||||
for (int dx = -1; dx < 2; dx++) {
|
||||
for (int dy = -1; dy < 2; dy++) {
|
||||
if (findTile(tiles, tile.x + dx, tile.y + dy) != null) {
|
||||
score++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// incomplete cloisters return a negative score
|
||||
return (score == 9) ? 9 : -score;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears out the claim group information for incomplete cities so
|
||||
* that we can ignore them during farm scoring. Assigns new claim
|
||||
* group values to any completed cities that were unclaimed.
|
||||
*
|
||||
* @param tiles a sorted list of tiles on the board.
|
||||
*/
|
||||
public static void prepCitiesForScoring (List tiles)
|
||||
{
|
||||
List flist = new ArrayList();
|
||||
|
||||
// iterate over the tiles, marking every city completed or not
|
||||
int tsize = tiles.size();
|
||||
for (int i = 0; i < tsize; i++) {
|
||||
AtlantiTile tile = (AtlantiTile)tiles.get(i);
|
||||
|
||||
// iterate over each feature on this tile
|
||||
for (int f = 0; f < tile.features.length; f++) {
|
||||
// skip non-city features
|
||||
if (tile.features[f].type != TileCodes.CITY) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// clear out the feature group list before processing
|
||||
flist.clear();
|
||||
|
||||
// enumerate the features in the group with this feature
|
||||
if (enumerateGroup(tiles, tile, f, flist)) {
|
||||
// if it's complete, we want to ensure that all of
|
||||
// these features have a claim number
|
||||
if (tile.claims[f] != 0) {
|
||||
// it's complete and has a claim number. move on
|
||||
continue;
|
||||
}
|
||||
|
||||
// assign the claim number to all features in the group
|
||||
int claimGroup = nextClaimGroup();
|
||||
for (int t = 0; t < flist.size(); t++) {
|
||||
TileFeature feat = (TileFeature)flist.get(t);
|
||||
feat.tile.claims[feat.featureIndex] = claimGroup;
|
||||
if (t == 0) {
|
||||
Log.info("Claiming complete city " +
|
||||
"[claim=" + feat.tile.claims[
|
||||
feat.featureIndex] + "].");
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// it's incomplete, so we want to clear out the claim
|
||||
// number from all tiles in the group
|
||||
for (int t = 0; t < flist.size(); t++) {
|
||||
TileFeature feat = (TileFeature)flist.get(t);
|
||||
if (t == 0) {
|
||||
Log.info("Clearing incomplete city " +
|
||||
"[claim=" + feat.tile.claims[
|
||||
feat.featureIndex] + "].");
|
||||
}
|
||||
feat.tile.claims[feat.featureIndex] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerates all of the features that are in the group of which the
|
||||
* specified feature is a member.
|
||||
*
|
||||
* @param tiles a sorted list of the tiles on the board.
|
||||
* @param tile the tile that contains the feature whose group is to be
|
||||
* enumerated.
|
||||
* @param featureIndex the index of the feature whose group is to be
|
||||
* enumerated.
|
||||
* @param group the list into which instances of {@link TileFeature}
|
||||
* will be placed that represent the features that are members of the
|
||||
* group.
|
||||
*
|
||||
* @return true if the group is complete (has no unconnected
|
||||
* features), false if it is not.
|
||||
*/
|
||||
protected static boolean enumerateGroup (
|
||||
List tiles, AtlantiTile tile, int featureIndex, List group)
|
||||
{
|
||||
// create a tilefeature for this feature
|
||||
TileFeature feat = new TileFeature(tile, featureIndex);
|
||||
|
||||
// determine whether or not this feature is already in the group
|
||||
if (group.contains(feat)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// otherwise add this feature to the group and process this
|
||||
// feature's neighbors
|
||||
group.add(feat);
|
||||
|
||||
boolean complete = true;
|
||||
int ftype = tile.features[featureIndex].type;
|
||||
int fmask = tile.features[featureIndex].edgeMask;
|
||||
|
||||
// iterate over all of the possible adjacency possibilities
|
||||
for (int c = 0; c < FeatureUtil.ADJACENCY_MAP.length; c += 3) {
|
||||
int mask = FeatureUtil.ADJACENCY_MAP[c];
|
||||
int opp_mask = FeatureUtil.ADJACENCY_MAP[c+2];
|
||||
|
||||
// if this feature doesn't have this edge, skip it
|
||||
if ((fmask & mask) == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// look up our neighbor
|
||||
AtlantiTile neighbor = null;
|
||||
int dir = FeatureUtil.ADJACENCY_MAP[c+1];
|
||||
dir = (dir + tile.orientation) % 4;
|
||||
switch (dir) {
|
||||
case NORTH: neighbor = findTile(tiles, tile.x, tile.y-1); break;
|
||||
case EAST: neighbor = findTile(tiles, tile.x+1, tile.y); break;
|
||||
case SOUTH: neighbor = findTile(tiles, tile.x, tile.y+1); break;
|
||||
case WEST: neighbor = findTile(tiles, tile.x-1, tile.y); break;
|
||||
}
|
||||
|
||||
// make sure we have a neighbor in this direction
|
||||
if (neighbor == null) {
|
||||
// if we don't have a neighbor in a direction that we
|
||||
// need, we're an incomplete feature. alas
|
||||
complete = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
// translate the target mask into our orientation
|
||||
mask = FeatureUtil.translateMask(mask, tile.orientation);
|
||||
opp_mask = FeatureUtil.translateMask(opp_mask, tile.orientation);
|
||||
|
||||
// obtain the index of the feature on the opposing tile
|
||||
int nFeatureIndex = neighbor.getFeatureIndex(opp_mask);
|
||||
if (nFeatureIndex < 0) {
|
||||
Log.warning("Tile mismatch while grouping [tile=" + tile +
|
||||
"featIdx=" + featureIndex +
|
||||
", neighbor=" + neighbor +
|
||||
", nFeatIdx=" + nFeatureIndex +
|
||||
", srcEdge=" + mask +
|
||||
", destEdge=" + opp_mask + "].");
|
||||
continue;
|
||||
}
|
||||
|
||||
// add this feature and its neighbors to the group
|
||||
if (!enumerateGroup(tiles, neighbor, nFeatureIndex, group)) {
|
||||
// if our neighbor was incomplete, we become incomplete.
|
||||
// as dr. evil might say, "you incomplete me."
|
||||
complete = false;
|
||||
}
|
||||
}
|
||||
|
||||
return complete;
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates and returns the tile with the specified coordinates.
|
||||
*
|
||||
* @param tiles a sorted list of tiles.
|
||||
*
|
||||
* @return the tile with the requested coordinates or null if no tile
|
||||
* exists at those coordinates.
|
||||
*/
|
||||
public static AtlantiTile findTile (List tiles, int x, int y)
|
||||
{
|
||||
IntTuple coord = new IntTuple(x, y);
|
||||
int tidx = Collections.binarySearch(tiles, coord);
|
||||
return (tidx >= 0) ? (AtlantiTile)tiles.get(tidx) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of piecens on the board owned the specified
|
||||
* player. This can be used when we need to count piecens and the
|
||||
* server potentially hasn't gotten around to processing piecen
|
||||
* removal events quite yet.
|
||||
*
|
||||
* @param tiles a list of the tiles on the board.
|
||||
* @param playerIndex the index of the player whose piecen count is
|
||||
* desired.
|
||||
*/
|
||||
public static int countPiecens (List tiles, int playerIndex)
|
||||
{
|
||||
int count = 0;
|
||||
for (int i = 0; i < tiles.size(); i++) {
|
||||
AtlantiTile tile = (AtlantiTile)tiles.get(i);
|
||||
if (tile.piecen != null &&
|
||||
tile.piecen.owner == playerIndex) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of piecens on the board owned the specified
|
||||
* player.
|
||||
*
|
||||
* @param piecens the piecens set from the game object.
|
||||
* @param playerIndex the index of the player whose piecen count is
|
||||
* desired.
|
||||
*/
|
||||
public static int countPiecens (DSet piecens, int playerIndex)
|
||||
{
|
||||
int count = 0;
|
||||
Iterator iter = piecens.entries();
|
||||
while (iter.hasNext()) {
|
||||
if (((Piecen)iter.next()).owner == playerIndex) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the edge type for specified edge of the specified tile
|
||||
* type.
|
||||
*
|
||||
* @param tileType the type of the tile in question.
|
||||
* @param edge the direction constant indicating the edge in which we
|
||||
* are interested.
|
||||
*
|
||||
* @return the edge constant for the edge in question.
|
||||
*/
|
||||
public static int getEdge (int tileType, int edge)
|
||||
{
|
||||
return TILE_EDGES[4*tileType + edge];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next unused claim group value.
|
||||
*/
|
||||
public static int nextClaimGroup ()
|
||||
{
|
||||
return ++_claimGroupCounter;
|
||||
}
|
||||
|
||||
/** Used to generate our standard tile set. */
|
||||
protected static void addTiles (int count, List list, AtlantiTile tile)
|
||||
{
|
||||
for (int i = 0; i < count; i++) {
|
||||
list.add(tile);
|
||||
}
|
||||
}
|
||||
|
||||
/** Used to keep track of actual features on tiles. */
|
||||
protected static final class TileFeature implements Comparable
|
||||
{
|
||||
/** The tile that contains the feature. */
|
||||
public AtlantiTile tile;
|
||||
|
||||
/** The index of the feature in the tile. */
|
||||
public int featureIndex;
|
||||
|
||||
/** Constructs a new tile feature. */
|
||||
public TileFeature (AtlantiTile tile, int featureIndex)
|
||||
{
|
||||
this.tile = tile;
|
||||
this.featureIndex = featureIndex;
|
||||
}
|
||||
|
||||
/** Properly implement equality. */
|
||||
public boolean equals (Object other)
|
||||
{
|
||||
if (other == null ||
|
||||
!(other instanceof TileFeature)) {
|
||||
return false;
|
||||
|
||||
} else {
|
||||
TileFeature feat = (TileFeature)other;
|
||||
return (feat.tile == tile &&
|
||||
feat.featureIndex == featureIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/** We sort based on our tiles. */
|
||||
public int compareTo (Object other)
|
||||
{
|
||||
return tile.compareTo(((TileFeature)other).tile);
|
||||
}
|
||||
|
||||
/** Generate a string representation. */
|
||||
public String toString ()
|
||||
{
|
||||
return "[tile=" + tile + ", fidx=" + featureIndex + "]";
|
||||
}
|
||||
}
|
||||
|
||||
/** Used to generate claim group values. */
|
||||
protected static int _claimGroupCounter;
|
||||
|
||||
/** Used to figure out which edges match up to which when comparing
|
||||
* adjacent tiles. */
|
||||
protected static final int[] EDGE_MAP = {
|
||||
-1, NORTH, -1,
|
||||
WEST, -1, EAST,
|
||||
-1, SOUTH, -1
|
||||
};
|
||||
|
||||
/** A table indicating which tiles have which edges. */
|
||||
protected static final int[] TILE_EDGES = {
|
||||
-1, -1, -1, -1, // null tile
|
||||
CITY, CITY, CITY, CITY, // CITY_FOUR
|
||||
CITY, CITY, GRASS, CITY, // CITY_THREE
|
||||
CITY, CITY, ROAD, CITY, // CITY_THREE_ROAD
|
||||
CITY, GRASS, GRASS, CITY, // CITY_TWO
|
||||
CITY, ROAD, ROAD, CITY, // CITY_TWO_ROAD
|
||||
GRASS, CITY, GRASS, CITY, // CITY_TWO_ACROSS
|
||||
CITY, CITY, GRASS, GRASS, // TWO_CITY_TWO
|
||||
GRASS, CITY, GRASS, CITY, // TWO_CITY_TWO_ACROSS
|
||||
CITY, GRASS, GRASS, GRASS, // CITY_ONE
|
||||
CITY, ROAD, ROAD, GRASS, // CITY_ONE_ROAD_RIGHT
|
||||
CITY, GRASS, ROAD, ROAD, // CITY_ONE_ROAD_LEFT
|
||||
CITY, ROAD, ROAD, ROAD, // CITY_ONE_ROAD_TEE
|
||||
CITY, ROAD, GRASS, ROAD, // CITY_ONE_ROAD_STRAIGHT
|
||||
GRASS, GRASS, GRASS, GRASS, // CLOISTER_PLAIN
|
||||
GRASS, GRASS, ROAD, GRASS, // CLOISTER_ROAD
|
||||
ROAD, ROAD, ROAD, ROAD, // FOUR_WAY_ROAD
|
||||
GRASS, ROAD, ROAD, ROAD, // THREE_WAY_ROAD
|
||||
ROAD, GRASS, ROAD, GRASS, // STRAIGHT_ROAD
|
||||
GRASS, GRASS, ROAD, ROAD, // CURVED_ROAD
|
||||
};
|
||||
|
||||
/** The standard tile set for a game of Atlantissonne. */
|
||||
protected static ArrayList TILE_SET = new ArrayList();
|
||||
|
||||
// create our standard tile set
|
||||
static {
|
||||
addTiles(1, TILE_SET, new AtlantiTile(CITY_FOUR, true));
|
||||
|
||||
addTiles(3, TILE_SET, new AtlantiTile(CITY_THREE, false));
|
||||
addTiles(1, TILE_SET, new AtlantiTile(CITY_THREE, true));
|
||||
addTiles(1, TILE_SET, new AtlantiTile(CITY_THREE_ROAD, false));
|
||||
addTiles(2, TILE_SET, new AtlantiTile(CITY_THREE_ROAD, true));
|
||||
|
||||
addTiles(3, TILE_SET, new AtlantiTile(CITY_TWO, false));
|
||||
addTiles(2, TILE_SET, new AtlantiTile(CITY_TWO, true));
|
||||
addTiles(3, TILE_SET, new AtlantiTile(CITY_TWO_ROAD, false));
|
||||
addTiles(2, TILE_SET, new AtlantiTile(CITY_TWO_ROAD, true));
|
||||
addTiles(1, TILE_SET, new AtlantiTile(CITY_TWO_ACROSS, false));
|
||||
addTiles(2, TILE_SET, new AtlantiTile(CITY_TWO_ACROSS, true));
|
||||
|
||||
addTiles(2, TILE_SET, new AtlantiTile(TWO_CITY_TWO, false));
|
||||
addTiles(3, TILE_SET, new AtlantiTile(TWO_CITY_TWO_ACROSS, false));
|
||||
|
||||
addTiles(5, TILE_SET, new AtlantiTile(CITY_ONE, false));
|
||||
addTiles(3, TILE_SET, new AtlantiTile(CITY_ONE_ROAD_RIGHT, false));
|
||||
addTiles(3, TILE_SET, new AtlantiTile(CITY_ONE_ROAD_LEFT, false));
|
||||
addTiles(3, TILE_SET, new AtlantiTile(CITY_ONE_ROAD_TEE, false));
|
||||
addTiles(3, TILE_SET, new AtlantiTile(CITY_ONE_ROAD_STRAIGHT, false));
|
||||
|
||||
addTiles(4, TILE_SET, new AtlantiTile(CLOISTER_PLAIN, false));
|
||||
addTiles(2, TILE_SET, new AtlantiTile(CLOISTER_ROAD, false));
|
||||
|
||||
addTiles(1, TILE_SET, new AtlantiTile(FOUR_WAY_ROAD, false));
|
||||
addTiles(4, TILE_SET, new AtlantiTile(THREE_WAY_ROAD, false));
|
||||
addTiles(8, TILE_SET, new AtlantiTile(STRAIGHT_ROAD, false));
|
||||
addTiles(9, TILE_SET, new AtlantiTile(CURVED_ROAD, false));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user