Hello,
I strongly need your assistance what is needed to modify in order the board to inherit the complete functionality of the game.
The clienthandler class contains all the methods for playing the game on the terminal
[please check the code]
Thanks in advance for any help !
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
public class SG_Board extends JPanel implements ActionListener{
protected CommonInfo comn; // Data common to all Tiles and Positions.
protected ImageIcon boardImage; // Holds the board graphic.
protected int totalPositions; // Depth x Width.
protected int maximumTiles; // The number of tiles as designated
// by the user.
protected int currentTileID; // First "current" tile.
protected int previousTileID; // Was previously the "current" tile.
// Tile ID's start at 1 rather than 0!
protected Tile tileArray[];
protected Position posArray[];
private Insets boardPanelInsets;
private Image myImage ;
protected Graphics myGraphic;
protected boolean firstTime = true;
public final int INERT_TILE_ID= 99999; // Used to put positions off limits.
private boolean drawGrid = true;
// Draw's a grid over the board image, if 'true'
// Alternatively, the grid may already be in
// the background graphic.
// ---------------------------------------------------------------------
public SG_Board() {
}
// ---------------------------------------------------------------------
public SG_Board (String fileName, // int buffer,
int x0, int y0,
int posnsWide, int posnsDown,
int posnPixelsWide, int posnPixelsDown){
JPanel smallMap = new JPanel();
boardImage = new ImageIcon(fileName);
boardPanelInsets = getInsets();
// Add the Panels insets to the users desired x0,y0
// ie. Allows for borders, automatically.
x0 = x0 + boardPanelInsets.left;
y0 = y0 + boardPanelInsets.top;
comn = new CommonInfo();
comn.init(x0,y0,posnsWide,posnsDown,posnPixelsWide,posnPixelsDown);
this.setPreferredSize(new Dimension(comn.getStartX(),comn.getStartY() ));
currentTileID = 0; //ie. tile ID's start at 1 rather than 0!
previousTileID = 0;
totalPositions = posnsWide * posnsDown;
posArray = new Position[totalPositions];
System.out.println("");
System.out.println("posnsWide="+ posnsWide);
System.out.println("posnsDown="+ posnsDown);
System.out.println("totalPositions="+totalPositions);
// Now initialise the Positions - which places
// them in their positions.
int i,row,column;
setLayout(null);
for (i=0; i < totalPositions; i++)
{
row = (i / comn.getDimensionWidth() ) + 1; //Nb. board coords start at (1,1)
column = (i % comn.getDimensionWidth() ) + 1;
posArray[i] = new Position();
posArray[i].init(column,row,i+1,comn); //Position ID's start at 1.
}
}
// ---------------------------------------------------------------------
/** Method for user to specifiy in advance, the total number of Tiles
* in the game. This method creates them on the heap.
*/
public void setNoOfTiles(int totalTiles){
maximumTiles = totalTiles;
tileArray = new Tile[totalTiles];
for (int i=0; i < maximumTiles; i++){
tileArray[i] = new Tile();
tileArray[i].setID(i+1); //Tile ID's start at 1 instead of zero.
tileArray[i].setOpaque(false);
}
}
// ---------------------------------------------------------------------
/** Method for the user to give a specific tile, its starting position
* in 'board coordinates', and the file name of the graphic icon to
* be displayed, representing a specific tile.
* Remember, the Tile IDs start at One, not Zero (as do the boardCoords).
*/
public void setTile(int tileID, int boardCoordX,int boardCoordY,String iconName){
int positionIndex =0;
if (tileArray[tileID] != null) {
tileArray[tileID].setIcon(new ImageIcon(iconName));
positionIndex = (boardCoordY)*comn.getDimensionWidth()
+ boardCoordX; //Nb. board coords start at (1,1)
System.out.println(posArray.length+":"+positionIndex);
System.out.println(tileArray.length+"-"+tileID);
tileArray[tileID].placeIt(boardCoordX, boardCoordY,
posArray[positionIndex]);
// Now reshape and locate the buttons ...
int x1,y1;
x1 = comn.getStartX() + ((tileArray[tileID].boardCoordX)
* comn.getApositionWidth() );
y1 = comn.getStartY() + ((tileArray[tileID].boardCoordY)
* comn.getApositionHeight() );
//tileArray[tileID-1].setLocation(x1,y1);
tileArray[tileID].reshape(x1+1,y1+1,comn.getApositionWidth(),comn.getApositionHeight());
this.add(tileArray[tileID]);
addNotify(); //Notifies Layout manager that the layout may
//has changed and needs resetting.
// Set it as default currentTile... last in, is it.
currentTileID = tileID;
// enact it for default event handling within the SG_Board...
// The string is used to identify it in event handling.
tileArray[tileID].setActionCommand("@aTileInPlay");
tileArray[tileID].addActionListener(this);
}
}
// ---------------------------------------------------------------------
/** Method for the user to take a pre-existing/externally declared
* Tile, and insert it into the tileArray, while also
* giving it starting board-coordinates,
* and the file name of the graphic icon to
* be displayed, representing a specific tile.
* Remember, the Tile IDs start at One, not Zero.
* Tile_id's were assigned by an earlier call to setID()
* from within 'setNoOfTiles(...)'. Nb. This method is untested.
*/
public void insertTile(int tileID, int boardCoordX,int boardCoordY,
Tile preDefinedTile) {
int positionIndex =0;
if (tileID <= maximumTiles){ // Don't insert more than initial tileArray.
tileArray[tileID] = preDefinedTile;
if (tileArray[tileID] != null) {
positionIndex = (boardCoordY) * comn.getDimensionWidth()
+ boardCoordX; //Nb. board coords start at (1,1)
tileArray[tileID].placeIt(boardCoordX, boardCoordY,
posArray[positionIndex]);
// Now reshape and locate the buttons ...
int x1, y1;
x1 = comn.getStartX() +
( (tileArray[tileID].boardCoordX) * comn.getApositionWidth());
y1 = comn.getStartY() +
( (tileArray[tileID].boardCoordY) * comn.getApositionHeight());
tileArray[tileID].reshape(x1 + 1, y1 + 1, comn.getApositionWidth(),
comn.getApositionHeight());
this.add(tileArray[tileID]);
addNotify(); //Notifies Layout manager that the layout
//has changed and needs resetting.
// Set it as default currentTile... last in, is it.
currentTileID = tileID;
// enact it for default event handling within the SG_Board...
tileArray[tileID].setActionCommand("@aTileInPlay");
tileArray[tileID].addActionListener(this);
}
}
}
// ---------------------------------------------------------------------
/**
* Returns the number (ID) of the resident Tile (1-XXX).
* using the board coordinates passed in as a parameter.
*/
public int getCurrentResidentID(Point boardCoordinates){
return
posArray[((boardCoordinates.y)*comn.getDimensionWidth())+boardCoordinates.x].currentTile();
}
// ---------------------------------------------------------------------
/**
* Marks a 'position' as off limits with regard to moving a tile there.
public void setPositionOffLimits(int boardCoordX, int boardCoordY){
Point boardCoordinates = new Point( boardCoordX, boardCoordY );
setCurrentResidentID(boardCoordinates,INERT_TILE_ID);
}*/
// ---------------------------------------------------------------------
/**
* Sets the number (ID) of the resident Tile (1-XXX).
* using the board coordinates passed in as a parameter, to
* change the right posArray[] item.
*/
public void setCurrentResidentID(Point boardCoordinates, int newResidentID){
posArray[((boardCoordinates.y)*comn.getDimensionWidth())+boardCoordinates.x].setCurrentResidentID(newResidentID);
}
// ---------------------------------------------------------------------
/**
* Method upOne
* Moves a tile up 1 position on the board, from its 'current' position.
* The tiles board coordinates are adjusted accordingly. The tile will
* not be moved off the board. The (0,0) coord, is given when a tile is
* initialised, and means that the tile is not currently on the board.
* The (1,1) coord, is the top left corner.
* There is a similar function in Tile, but the one here uses board coordinate
* directly.
* @param comn
*/
public void upOne (Tile tileOnTheMove){
int x1,y1; //first coords. for a tile
if (tileOnTheMove.boardCoordY > 1) { //Yes, there is a line above.
// But is the board position above currently vacant? ...
Point boardCoordinates = new Point();
Point newBoardCoordinates = new Point();
tileOnTheMove.getBoardCoordinates(boardCoordinates);
newBoardCoordinates.x = boardCoordinates.x;
newBoardCoordinates.y = boardCoordinates.y;
int occupier = getCurrentResidentID(newBoardCoordinates);
if (occupier == 0 && (occupier!=INERT_TILE_ID)){ // Then it is unoccupied!
tileOnTheMove.boardCoordY--; //Adjust that tiles board coordinates.
x1 = comn.getStartX() + ((tileOnTheMove.boardCoordX) * comn.getApositionWidth());
y1 = comn.getStartY() + ((tileOnTheMove.boardCoordY) * comn.getApositionHeight());
tileOnTheMove.reshape(x1+1,y1+1,comn.getApositionWidth(),comn.getApositionHeight());
addNotify();
//update the state of the appropriate board 'position's - both.
setCurrentResidentID(newBoardCoordinates,tileOnTheMove.getID());
setCurrentResidentID(boardCoordinates,0);
}
}
}
// ---------------------------------------------------------------------
/**
* Method downOne.
* Moves a tile down 1 position on the board, from its 'current' position.
* The tiles board coordinates are adjusted accordingly.
* There is a similar function in Tile, but the one here uses board coordinate
* directly.
*/
public void downOne (Tile tileOnTheMove){
int x1,y1; //first coords. for a tile
if ((tileOnTheMove.boardCoordY > 0) && (tileOnTheMove.boardCoordY < comn.getDimensionHeight())) {
//Yes, there is a line below.
// But is the board position below currently vacant? ...
Point boardCoordinates = new Point();
Point newBoardCoordinates = new Point();
tileOnTheMove.getBoardCoordinates(boardCoordinates);
newBoardCoordinates.x = boardCoordinates.x;
newBoardCoordinates.y = boardCoordinates.y+1;
int occupier = getCurrentResidentID(newBoardCoordinates);
if (occupier == 0 && (occupier!=INERT_TILE_ID)){ // Then it is unoccupied!
tileOnTheMove.boardCoordY++; //Adjust that tiles board coordinates.
x1 = comn.getStartX() + ((tileOnTheMove.boardCoordX - 1) * comn.getApositionWidth());
y1 = comn.getStartY() + ((tileOnTheMove.boardCoordY - 1) * comn.getApositionHeight());
tileOnTheMove.reshape(x1+1,y1+1,comn.getApositionWidth()-1,comn.getApositionHeight()-1);
addNotify();
//update the state of the appropriate board 'position's - both.
setCurrentResidentID(newBoardCoordinates,tileOnTheMove.getID());
setCurrentResidentID(boardCoordinates,0);
}
}
}
// ---------------------------------------------------------------------
/**
* Method leftOne.
* Moves a tile left 1 position on the board, from its 'current' position.
* The tiles board coordinates are adjusted accordingly.
* There is a similar function in Tile, but the one here uses board coordinate
* directly.
*/
public void leftOne (Tile tileOnTheMove){
int x1,y1; //first coords. for a tile
if (tileOnTheMove.boardCoordX > 1) { //Yes, there is a line at left.
// But is the board position at left side currently vacant? ...
Point boardCoordinates = new Point();
Point newBoardCoordinates = new Point();
tileOnTheMove.getBoardCoordinates(boardCoordinates);
newBoardCoordinates.x = boardCoordinates.x;
newBoardCoordinates.y = boardCoordinates.y;
int occupier = getCurrentResidentID(newBoardCoordinates);
if (occupier == 0 && (occupier!=INERT_TILE_ID)){ // Then it is unoccupied!
tileOnTheMove.boardCoordX--; //Adjust that tiles board coordinates.
x1 = comn.getStartX() + ((tileOnTheMove.boardCoordX) * comn.getApositionWidth());
y1 = comn.getStartY() + ((tileOnTheMove.boardCoordY) * comn.getApositionHeight());
tileOnTheMove.reshape(x1+1,y1+1,comn.getApositionWidth(),comn.getApositionHeight());
addNotify();
//update the state of the appropriate board 'position's - both.
setCurrentResidentID(newBoardCoordinates,tileOnTheMove.getID());
setCurrentResidentID(boardCoordinates,0);
}
}
}
// ---------------------------------------------------------------------
/**
* Method rightOne.
* Moves a tile right 1 position on the board, from its 'current' position.
* The tiles board coordinates are adjusted accordingly.
* There is a similar function in Tile, but the one here uses board coordinate
* directly.
*/
public void rightOne (Tile tileOnTheMove){
int x1,y1; //first coords. for a tile
if (tileOnTheMove.boardCoordX > 0 &&(tileOnTheMove.boardCoordX < comn.getDimensionWidth())) {
//Yes, there is a line at right.
// But is the board position at right side currently vacant? ...
Point boardCoordinates = new Point();
Point newBoardCoordinates = new Point();
tileOnTheMove.getBoardCoordinates(boardCoordinates);
newBoardCoordinates.x = boardCoordinates.x+1;
newBoardCoordinates.y = boardCoordinates.y;
int occupier = getCurrentResidentID(newBoardCoordinates);
if (occupier == 0 && (occupier!=INERT_TILE_ID)){ // Then it is unoccupied!
tileOnTheMove.boardCoordX++; //Adjust that tiles board coordinates.
x1 = comn.getStartX() + ((tileOnTheMove.boardCoordX) * comn.getApositionWidth());
y1 = comn.getStartY() + ((tileOnTheMove.boardCoordY) * comn.getApositionHeight());
tileOnTheMove.reshape(x1+1,y1+1,comn.getApositionWidth(),comn.getApositionHeight());
addNotify();
//update the state of the appropriate board 'position's - both.
setCurrentResidentID(newBoardCoordinates,tileOnTheMove.getID());
setCurrentResidentID(boardCoordinates,0);
//posArray[1].setCurrentResidentID(currentTileID);
}
}
}
// ---------------------------------------------------------------------
/**
* Method goTo - allow a tile to 'jump' to any unoccupied position.
* Moves a tile to a new position on the board, from its 'current' position.
* The tiles board coordinates are adjusted accordingly. The tile will
* not be moved off the board. The (0,0) coord, is given when a tile is
* initialised, and means that the tile is not currently on the board.
* The (1,1) coord, is the top left corner.
* @param comn
public void goTo (Tile tileOnTheMove, int newX, int newY){
int x1,y1; //first coords. for a tile
// Is the goto board position above currently vacant? ...
Point boardCoordinates = new Point();
Point newBoardCoordinates = new Point();
tileOnTheMove.getBoardCoordinates(boardCoordinates);
if (newX > 0 && newX <= comn.getDimensionWidth() &&
newY > 0 && newY <= comn.getDimensionHeight()){ // on the board?
newBoardCoordinates.x = newX;
newBoardCoordinates.y = newY;
int occupier = getCurrentResidentID(newBoardCoordinates);
if (occupier == 0 && (occupier!=INERT_TILE_ID)){ // Then it is unoccupied!
tileOnTheMove.boardCoordX=newX; //Adjust that tiles board coordinates.
tileOnTheMove.boardCoordY=newY; //Adjust that tiles board coordinates.
x1 = comn.getStartX() + ((tileOnTheMove.boardCoordX) * comn.getApositionWidth());
y1 = comn.getStartY() + ((tileOnTheMove.boardCoordY) * comn.getApositionHeight());
tileOnTheMove.reshape(x1+1,y1+1,comn.getApositionWidth(),comn.getApositionHeight());
addNotify();
//update the state of the appropriate board 'position's - both.
setCurrentResidentID(newBoardCoordinates,tileOnTheMove.getID());
setCurrentResidentID(boardCoordinates,0);
}
}
}*/
// ---------------------------------------------------------------------
/**
* Method that sources the tile that was clicked on, while on
* the playing board, and sets the fields: previousTileID, currentTileID.
* @param evt
*/
public void makeTileCurrent (java.awt.event.ActionEvent evt)
{
Tile eventGeneratingTile = (Tile) evt.getSource();
previousTileID = currentTileID;
currentTileID = eventGeneratingTile.id;
}
// ---------------------------------------------------------------------
public void actionPerformed(ActionEvent e)
{
String buttonTop = e.getActionCommand();
if (buttonTop.compareTo("@aTileInPlay") == 0) {
// Its a tile on the board, and we want it to become the currentTile.
//makeTileCurrent(e);
}
else if (buttonTop.compareTo("GoToTarget") == 0) {
if (currentTileID > 0) {
//goTo(tileArray[currentTileID],posArray[0].currentTarget.x,posArray[0].currentTarget.y);
}
}
// System.out.println("The button pressed was: "+(String)buttonTop);
}
// ---------------------------------------------------------------------
public void createGraphic(Image myImage, Graphics myGraphic, int width, int height){
// Create a graphics image to paint on...
myImage = createImage(width, height);
myGraphic = myImage.getGraphics();
}
// ---------------------------------------------------------------------
/**
* Overrides the inherited paint.
*/
public void paint(Graphics g){
super.paint(g);
/*
if (firstTime){
myGraphic = g.create(0,0,640,480);
firstTime = false;
}
else
g = myGraphic;
*/
}
// ---------------------------------------------------------------------
/**
* Overrides the inherited paintComponent.
*/
public void paintComponent(Graphics g){
super.paintComponent(g);
Insets boardPanelInsets = getInsets();
//Paint all of the tiles...
boardImage.paintIcon(this,g,comn.getStartX(),comn.getStartY());
int i,row,column;
if (drawGrid){ // You can set or unset grid drawing methods: setDrawGridOn()/Off()
for (i = 0; i < totalPositions; i++) {
posArray[i].draw(g, this, comn); // Pass the graphic context
}
}
int x1, y1;
for (int j=0; j < maximumTiles; j++) {
//tileArray[j].paint(g);
}
}
// ---------------------------------------------------------------------
/**
* Overrides the inherited getPreferredSize.
*/
public Dimension getPreferredSize(){
Insets inS = getInsets();
return new Dimension(boardImage.getIconWidth()+inS.left+inS.right,
boardImage.getIconHeight()+inS.top+inS.bottom);
}
// ---------------------------------------------------------------------
/**
* Swaps positions of tiles 'currentTileID' & 'previousTileID'
* and redisplays their respective graphics in the new positions.
public void swapTiles(){
int pos1,pos2,x1,y1,x2,y2;
if (currentTileID > 0 && previousTileID > 0)
{
// Find the 2 tiles current positions...
pos1 = tileArray[currentTileID].currentPos(comn);
pos2 = tileArray[previousTileID].currentPos(comn);
x1 = tileArray[currentTileID].boardCoordX;
x2 = tileArray[previousTileID].boardCoordX;
y1 = tileArray[currentTileID].boardCoordY;
y2 = tileArray[previousTileID].boardCoordY;
// Now swap their respective positions...
posArray[pos1].setCurrentResidentID(previousTileID);
posArray[pos2].setCurrentResidentID(currentTileID);
tileArray[currentTileID].boardCoordX = x2;
tileArray[previousTileID].boardCoordX = x1;
tileArray[currentTileID].boardCoordY = y2;
tileArray[previousTileID].boardCoordY = y1;
int x3,y3;
x3 = comn.getStartX() + ((x1) * comn.getApositionWidth());
y3 = comn.getStartY() + ((y1) * comn.getApositionHeight());
tileArray[previousTileID].reshape(x3+1,y3+1,comn.getApositionWidth(),comn.getApositionHeight());
x3 = comn.getStartX() + ((x2) * comn.getApositionWidth());
y3 = comn.getStartY() + ((y2) * comn.getApositionHeight());
tileArray[currentTileID].reshape(x3+1,y3+1,comn.getApositionWidth(),comn.getApositionHeight());
addNotify();
}
}*/
// ---------------------------------------------------------------------
/**
* Randomly swapps the current tiles amongst themselves.
public void randomShuffle(){
// scrambles the image.
Random aRandomNo = new Random();
for (int i=0; i < maximumTiles; i++)
{
currentTileID = aRandomNo.nextInt(maximumTiles)+1;
previousTileID = aRandomNo.nextInt(maximumTiles)+1;
while (previousTileID == currentTileID) {
previousTileID = aRandomNo.nextInt(maximumTiles)+1;
}
swapTiles();
}
}*/
// ---------------------------------------------------------------------
/**
* This mutator method sets the currentTileID to the ID that is
* passed in as a parameter.
* Remember, TileID's begin at 1, while the array of tiles
* begins at 0 - this is a 'game convention' vs a Java convention.
* It would be very useful to call this method, before calling the
* goTo(tileID
*/
public void setCurrentTileID(int newCurrentTileID){
if (newCurrentTileID <= maximumTiles && newCurrentTileID > 0){
if (newCurrentTileID != currentTileID) previousTileID = currentTileID;
currentTileID = newCurrentTileID;
}
}
// ---------------------------------------------------------------------
/**
* This accessor method retrieves the currentTileID.
* Useful for example, if you don't know what the currentTileID is,
* but you want to use it, in a call such as to the goTo(...) method.
*/
public int getCurrentTileID(){
return currentTileID;
}
// ---------------------------------------------------------------------
/**
* Sets the boolean data member 'drawGrid'to true, which in turn
* activates the drawing of a grid over the background graphic, which
* matches the grid of 'Position's.
public void setDrawGridOn(){
drawGrid = true;
}*/
// ---------------------------------------------------------------------
/**
* Sets the boolean data member 'drawGrid'to false, which in turn
* deactivates the drawing of a grid over the background graphic.
*/
public void setDrawGridOff(){
drawGrid = false;
}
// ---------------------------------------------------------------------
}
class ClientHandler extends ConnectionBase
{
String name = "Dave" + this.hashCode();
LODServer server;
int x = 0;
int y = 0;
int lantern = 0;
int sword = 0;
int armour = 0;
int treasure = 0;
int hp = 3;
boolean dead = false;
boolean isMyTurn = false;
int ap = 0;
synchronized void startTurn () throws InterruptedException {
try {
server.playerTurn.acquire();
} catch (InterruptedException e) {
throw(e);
}
ap = 6 - (lantern + sword + armour);
isMyTurn = true;
serverStartTurn();
return;
}
void clientHello(String newName) {
name = newName;
return;
}
void clientLook() {
if ((server.gameStarted == false) || (dead == true)) {
return;
} else {
serverLookReplyBegin();
int distance = 2 + lantern;
for (int i = -distance; i <= distance; ++i) {
String line = "";
for (int j = -distance; j <= distance; ++j) {
char content = '?';
int targetX = x + j;
int targetY = y + i;
if (Math.abs(i) + Math.abs(j) > distance + 1) {
content = 'X';
} else if ((targetX < 0) || (targetX >= server.mapWidth) ||
(targetY < 0) || (targetY >= server.mapHeight)) {
content = '#';
} else {
switch (server.map[targetY][targetX]) {
case LODServer.EMPTY : content = '.'; break;
case LODServer.HEALTH : content = 'H'; break;
case LODServer.LANTERN : content = 'L'; break;
case LODServer.SWORD : content = 'S'; break;
case LODServer.ARMOUR : content = 'A'; break;
case LODServer.EXIT : content = 'E'; break;
case LODServer.WALL : content = '#'; break;
default :
if (server.map[targetY][targetX] > 0) {
content = 'G';
} else {
System.err.println("Invalid map location : [" + targetY + "][" + targetX + "] = " + server.map[targetY][targetX]);
System.exit(1);
}
}
for (ClientHandler c : server.clients) {
if (c != this) {
if ((c.x == targetX) && (c.y == targetY)) {
content = 'P';
}
}
}
}
line += content;
}
serverLookReply(line);
}
}
}
void clientShout(String message) {
if (server.gameStarted == false) {
return;
} else {
for (ClientHandler c : server.clients) {
if (c != this) {
c.serverMessage(name + " : " + message);
}
}
return;
}
}
void clientPickup() {
String failMessage = "";
if ((isMyTurn) && (ap > 0)) {
switch (server.map[y][x]) {
case LODServer.EXIT :
case LODServer.EMPTY :
failMessage = "Nothing to pick up";
break;
case LODServer.HEALTH :
ap = 0;
server.map[y][x] = LODServer.EMPTY;
serverSucceed();
++hp;
serverHitMod(1);
sendChangeNotifications();
return;
//break; // Commented out as never reached
case LODServer.LANTERN :
if (lantern == 0) {
--ap;
server.map[y][x] = LODServer.EMPTY;
serverSucceed();
lantern = 1;
sendChangeNotifications();
return;
} else {
failMessage = "Already have a lantern";
}
break;
case LODServer.SWORD :
if (sword == 0) {
--ap;
server.map[y][x] = LODServer.EMPTY;
serverSucceed();
sword = 1;
sendChangeNotifications();
return;
} else {
failMessage = "Already have a sword";
}
break;
case LODServer.ARMOUR :
if (armour == 0) {
--ap;
server.map[y][x] = LODServer.EMPTY;
serverSucceed();
armour = 1;
sendChangeNotifications();
return;
} else {
failMessage = "Already have a armour";
}
break;
default :
if (server.map[y][x] > 0) {
--ap;
int treasurePickedUp = server.map[y][x];
server.map[y][x] = LODServer.EMPTY;
serverSucceed();
treasure += treasurePickedUp;
serverTreasureMod(treasurePickedUp);
sendChangeNotifications();
return;
} else {
System.err.println("Pickup at strange map location : [" + y + "][" + x + "] = " + server.map[y][x]);
System.exit(1);
}
}
} else {
if (!isMyTurn) {
failMessage = "Faulty client : PICKUP outside of turn";
} else {
failMessage = "No action points left";
}
}
serverFail(failMessage);
return;
}
void clientMove(char direction) {
String failMessage;
if ((isMyTurn) && (ap > 0)) {
int targetX = x;
int targetY = y;
switch (direction) {
case 'N' : --targetY; break;
case 'S' : ++targetY; break;
case 'E' : ++targetX; break;
case 'W' : --targetX; break;
default : // Shouldn't happen
System.err.println("Internal error in connection base.");
System.err.println("'" + direction + "' is not a direction.");
System.exit(1);
}
if ((targetX >= 0) && (targetX < server.mapWidth) &&
(targetY >= 0) && (targetY < server.mapHeight)) {
if (server.map[targetY][targetX] != LODServer.WALL) {
boolean targetEmpty = true;
for (ClientHandler c : server.clients) {
if ((c != this) && (c.x == targetX) && (c.y == targetY)) {
targetEmpty = false;
}
}
if (targetEmpty) {
--ap;
x = targetX;
y = targetY;
serverSucceed();
sendChangeNotifications();
return;
} else {
failMessage = "Can not move into another player";
}
} else {
failMessage = "Can not move into a wall";
}
} else {
// Needs to be the same as above or
// otherwise lets people know where
// the edges of the labyrinth are.
failMessage = "Can not move into a wall";
}
} else {
if (!isMyTurn) {
// Only happens with faulty clients
failMessage = "Faulty client : MOVE outside of turn";
} else {
failMessage = "No action points left";
}
}
// Fail unless there is an explict reason why we succeed
serverFail(failMessage);
return;
}
// Handles the client message ATTACK
void clientAttack(char direction) {
String failMessage;
// Can only attack if it is this player's turn
// and they have action points left
if ((isMyTurn) && (ap > 0)) {
// Work out which square we're targeting
int targetX = x;
int targetY = y;
switch (direction) {
case 'N' : --targetY; break;
case 'S' : ++targetY; break;
case 'E' : ++targetX; break;
case 'W' : --targetX; break;
default : // Shouldn't happen
System.err.println("Internal error in connection base.");
System.err.println("'" + direction + "' is not a direction.");
System.exit(1);
}
// Work out which player that is
ClientHandler target = null;
for (ClientHandler c : server.clients) {
if ((c.x == targetX) && (c.y == targetY)) {
target = c;
break;
}
}
// If there is another player in the target square
if (target != null) {
// There is a 75% chance of hitting
if (Math.random() < 0.75) {
// Reduce the target's hitpoints
int damage = 1 + sword - target.armour;
target.hp -= damage;
// Notify them of the change
target.serverMessage("You where hit by " + name +
" for " + damage + " points of damage");
target.serverHitMod(-damage);
// Notify the attacker of a successful attack
serverSucceed();
// If the target has been killed
if (target.hp <= 0) {
target.serverMessage(name + " has killed you");
target.die();
}
return;
} else {
// This message is not required by the spec
// but adds to the playability of the game
target.serverMessage("You dodged " + name + "'s attack");
failMessage = "They dodged your attack";
}
} else {
failMessage = "No one there to attack";
}
} else {
if (!isMyTurn) {
// Only happens with faulty clients
failMessage = "Faulty client : ATTACK outside of turn";
} else {
failMessage = "No action points left";
}
}
// Fail unless there is an explict reason why we succeed
serverFail(failMessage);
return;
}
// Handles the client message ENDTURN
void clientEndTurn() {
// Check to see if this player has won
if ((treasure >= server.goal) && (server.map[y][x] == LODServer.EXIT)) {
server.gameFinished = true;
}
// Mark that it is no longer this player's turn
isMyTurn = false;
// Release the semaphore
// (thus the LODServer can acquire it, and
// make it the next player's go).
server.playerTurn.release();
return;
}
// Not a message; what to do if the client disconnects
void clientDisconnected() {
die();
// Disconnecting may occur during the player's turn,
// unlike the other causes of death.
if (isMyTurn) {
// Act as if an ENDTURN message had been sent
clientEndTurn();
}
}
// Not a message; what to do if a player disconnects or is killed
void die() {
// Unlike horror film bad guys, ClientHandlers only die once
if (!dead) {
dead = true;
// Drop any gold carried
server.map[y][x] = treasure * LODServer.TREASURE;
// BUG!
// Dropping gold will (correctly) destroy any item
// (i.e. sword, armour, lantern, health)
// however, it currently also (incorrectly) destroys
// any other gold or the exit if they are on the square
// that the gold is dropped on.
// The correct solution to this probably involves
// separate matrices for locations (walls, exits, etc.)
// items/treasure.
server.clients.remove(this);
// Note this does not disconnect the client
// but they will not get another turn
// nor effect the map,
// they can only shout and listen to messages
// To disconnect them as well:
// shutdown();
// Inform other players of their demise
for (ClientHandler c : server.clients) {
c.serverMessage(name + " is no more!");
}
sendChangeNotifications();
}
}
// A helper function which sends CHANGE messages
// when an actions changes the map
void sendChangeNotifications () {
for (ClientHandler c : server.clients) {
c.serverChangeNotification();
}
}
}