diff --git a/Assignment 4/src/ca/cosc3p91/a4/game/GameEngine.java b/Assignment 4/src/ca/cosc3p91/a4/game/GameEngine.java index 45f958a..e062fd3 100644 --- a/Assignment 4/src/ca/cosc3p91/a4/game/GameEngine.java +++ b/Assignment 4/src/ca/cosc3p91/a4/game/GameEngine.java @@ -19,7 +19,7 @@ public class GameEngine { public static final double IRON_FACTOR = 1; public static final double WOOD_FACTOR = 0.1; - private final float pillageFactor = 0.5f; + private float pillageFactor = 0.5f; private int currentTime; @@ -31,22 +31,22 @@ public class GameEngine { } public void attackVillage(Map attacking, Map defending) { -// int defenseiveCounter = 1; -// int inhabCounter = 0; -// for (Building b : map.contains) -// if (b instanceof DefenseBuilding) -// defenseiveCounter++; -// for (Inhabitant i : map.inhabitants) -// if (i instanceof Infantry) -// inhabCounter++; -// pillageFactor = (float) inhabCounter / (float) defenseiveCounter; -// if (pillageFactor < 0) -// pillageFactor = 0; -// if (pillageFactor > 1) -// pillageFactor = 1; -// this.map.getTownHall().addWood((int) (map.getTownHall().getCurrentWood() * pillageFactor)); -// this.map.getTownHall().addIron((int) (map.getTownHall().getCurrentIron() * pillageFactor)); -// this.map.getTownHall().addGold((int) (map.getTownHall().getCurrentGold() * pillageFactor)); + int defenseiveCounter = 1; + int inhabCounter = 0; + for (Building b : defending.contains) + if (b instanceof DefenseBuilding) + defenseiveCounter++; + for (Inhabitant i : defending.inhabitants) + if (i instanceof Infantry) + inhabCounter++; + pillageFactor = (float) inhabCounter / (float) defenseiveCounter; + if (pillageFactor < 0) + pillageFactor = 0; + if (pillageFactor > 1) + pillageFactor = 1; + attacking.getTownHall().addWood((int) (defending.getTownHall().getCurrentWood() * pillageFactor)); + attacking.getTownHall().addIron((int) (defending.getTownHall().getCurrentIron() * pillageFactor)); + attacking.getTownHall().addGold((int) (defending.getTownHall().getCurrentGold() * pillageFactor)); ChallengeAdapter adapter = new ChallengeAdapter(attacking); adapter.attack(defending); } @@ -155,17 +155,19 @@ public class GameEngine { return map.build(new Tile(), type); } - public boolean train (Map map, String inhabitantArgs) { + public boolean train (Map map, String inhabitantArgs) throws TrainingErrorException { InhabitantFactory ifactory = new InhabitantFactory(); Inhabitant type = ifactory.getInhabitant(inhabitantArgs); + if (type == null) + throw new TrainingErrorException("Invalid training type!"); return map.train(type); } - public synchronized boolean upgradeBuilding (Map map, int buildingIndex) { + public synchronized boolean upgradeBuilding (Map map, int buildingIndex) throws UpgradingErrorException { return map.upgradeBuilding(buildingIndex); } - public boolean upgradeInhabitant (Map map, int inhabitantIndex) { + public synchronized boolean upgradeInhabitant (Map map, int inhabitantIndex) { return map.upgradeInhabitant(inhabitantIndex); } @@ -287,4 +289,16 @@ public class GameEngine { } } + public static class TrainingErrorException extends Exception { + public TrainingErrorException(String message){ + super(message); + } + } + + public static class UpgradingErrorException extends Exception { + public UpgradingErrorException(String message){ + super(message); + } + } + } diff --git a/Assignment 4/src/ca/cosc3p91/a4/game/Map.java b/Assignment 4/src/ca/cosc3p91/a4/game/Map.java index fc0eaa6..5cd37f3 100644 --- a/Assignment 4/src/ca/cosc3p91/a4/game/Map.java +++ b/Assignment 4/src/ca/cosc3p91/a4/game/Map.java @@ -54,17 +54,20 @@ public class Map implements Serializable { return false; } - public boolean upgradeBuilding(int buildingIndex) { + public boolean upgradeBuilding(int buildingIndex) throws GameEngine.UpgradingErrorException { - if (buildingIndex >= contains.size() || buildingIndex < 0) return false; + if (buildingIndex >= contains.size() || buildingIndex < 0) + return false; Building b = contains.get(buildingIndex); int currentLevel = b.getLevel(); CasaDeNarino hall = getTownHall(); - if (currentLevel >= 2) return false; - else if (b instanceof Farm) return true; + if (currentLevel >= 2) + return false; + else if (b instanceof Farm) + return true; int goldCost = b.getUpgradeStage().getCost(SaulGoodMine.resource); int ironCost = b.getUpgradeStage().getCost(IronMine.resource); @@ -86,7 +89,8 @@ public class Map implements Serializable { } else { b.upgrade(VillageHallStages.villageStages[currentLevel + 1]); } - } else return false; + } else + return false; return true; } diff --git a/Assignment 4/src/ca/cosc3p91/a4/userinterface/GameDisplay.java b/Assignment 4/src/ca/cosc3p91/a4/userinterface/GameDisplay.java index 72f3c0b..bee8258 100644 --- a/Assignment 4/src/ca/cosc3p91/a4/userinterface/GameDisplay.java +++ b/Assignment 4/src/ca/cosc3p91/a4/userinterface/GameDisplay.java @@ -86,13 +86,14 @@ public class GameDisplay { } public void printGameMenu() { - System.out.println("\n~ Player Options:\n" + + System.out.println("\n\033[36m~ Player Options:\n" + "1. Build {command: '1 '}\n" + "2. Train inhabitants {command: '2 '}\n"+ "3. Upgrade {command: '3 i'} / {command: '3 b'}\n"+ - "4. Explore\n"+ + "4. Explore Player Villages\n"+ "5. Print Village Stats\n"+ "6. Quit\n" + - "7. Attack last explored\n"); + "7. Attack last explored/generated\n" + + "8. Generate Village\033[0m\n"); } } \ No newline at end of file diff --git a/Assignment 4/src/ca/cosc3p91/a4/util/network/Client.java b/Assignment 4/src/ca/cosc3p91/a4/util/network/Client.java index 3d601d5..0f3822f 100644 --- a/Assignment 4/src/ca/cosc3p91/a4/util/network/Client.java +++ b/Assignment 4/src/ca/cosc3p91/a4/util/network/Client.java @@ -36,6 +36,8 @@ public class Client implements Runnable { sendMessage(new Message.Sent(PacketTable.CONNECT, ourClientID, ++lastMessageID)); + view.printGameMenu(); + while (running) { String prompt; if ((prompt = view.nextInput()) != null) { @@ -65,9 +67,18 @@ public class Client implements Runnable { case '3': messageType = PacketTable.UPGRADE; break; + case '4': + messageType = PacketTable.EXPLORE; + break; case '5': messageType = PacketTable.PRINT_MAP_DATA; break; + case '7': + messageType = PacketTable.ATTACK; + break; + case '8': + messageType = PacketTable.GENERATE; + break; default: System.err.println("> Invalid command input!"); return; @@ -121,7 +132,7 @@ public class Client implements Runnable { System.out.println("MessageID: " + ms.getKey()); break; case PacketTable.MESSAGE: - System.out.println(stream.readUTF()); + System.out.println("\033[93m" + stream.readUTF() + "\033[0m"); break; case PacketTable.BEGIN_MAP_DATA: expectedLines = stream.readInt(); @@ -134,7 +145,7 @@ public class Client implements Runnable { currentLines++; if (currentLines >= expectedLines) { for (String line : lineBuffer){ - System.out.println(line); + System.out.println("\033[92m" + line + "\033[0m"); } } break; diff --git a/Assignment 4/src/ca/cosc3p91/a4/util/network/PacketTable.java b/Assignment 4/src/ca/cosc3p91/a4/util/network/PacketTable.java index 146ec39..c97302a 100644 --- a/Assignment 4/src/ca/cosc3p91/a4/util/network/PacketTable.java +++ b/Assignment 4/src/ca/cosc3p91/a4/util/network/PacketTable.java @@ -28,4 +28,7 @@ public class PacketTable { public static final byte BEGIN_MAP_DATA = 0x9; // server -> client // messageHeader, line number (int), UTF8 String (the line) public static final byte MAP_LINE_DATA = 0xA; // server -> client + public static final byte EXPLORE = 0xB; + public static final byte ATTACK = 0xC; + public static final byte GENERATE = 0xD; } diff --git a/Assignment 4/src/ca/cosc3p91/a4/util/network/Server.java b/Assignment 4/src/ca/cosc3p91/a4/util/network/Server.java index 0dd00d4..f3f175a 100644 --- a/Assignment 4/src/ca/cosc3p91/a4/util/network/Server.java +++ b/Assignment 4/src/ca/cosc3p91/a4/util/network/Server.java @@ -27,7 +27,7 @@ public class Server implements Runnable { private final Thread ioThread; // private static volatile long lastSentMessageID = 0; - private GameEngine mainEngine; + private final GameEngine mainEngine; private volatile boolean running = true; @@ -62,7 +62,7 @@ public class Server implements Runnable { if (packetID == PacketTable.CONNECT){ long cid = ++clientAssignmentID; System.out.println("A client has connected, his clientID is " + cid); - clients.put(cid, new ConnectedClient(socket, mainEngine, cid, messageID, receivePacket.getAddress(), receivePacket.getPort())); + clients.put(cid, new ConnectedClient(this, mainEngine, cid, messageID, receivePacket.getAddress(), receivePacket.getPort())); continue; } if (client == null) @@ -95,7 +95,7 @@ public class Server implements Runnable { private final ReentrantLock requestLock = new ReentrantLock(); private final AtomicBoolean allowUpdate; private final java.util.Map sentMessages = Collections.synchronizedMap(new HashMap<>()); - private final DatagramSocket serverSocket; + private final Server server; private final long clientID; private volatile boolean running = true; private final Thread processingThread; @@ -103,9 +103,10 @@ public class Server implements Runnable { private final GameEngine usingEngine; private long lastSentMessageID = 0; private final Map clientMap; + private Map exploringMap; - public ConnectedClient(DatagramSocket serverSocket, GameEngine engine, long clientID, long messageID, InetAddress address, int port){ - this.serverSocket = serverSocket; + public ConnectedClient(Server server, GameEngine engine, long clientID, long messageID, InetAddress address, int port){ + this.server = server; this.address = address; this.port = port; this.clientID = clientID; @@ -162,14 +163,63 @@ public class Server implements Runnable { } break; case PacketTable.TRAIN: - usingEngine.train(clientMap, request.getReader().readUTF()); + try { + String type = request.getReader().readUTF().trim(); + if (usingEngine.train(clientMap, type)) + sendAndLogLn("Client " + clientID + " has successfully trained " + type + "!"); + else + sendAndLogLn("Client " + clientID + " has insufficient funds to train " + type + "!"); + } catch (GameEngine.TrainingErrorException e){ + sendAndLogLn(e.getMessage()); + } break; case PacketTable.UPGRADE: - usingEngine.upgradeBuilding(clientMap, Integer.parseInt(request.getReader().readUTF())); + try { + String type = request.getReader().readUTF(); + int val = Integer.parseInt( + type.replace("b", "") + .replace(" ", "") + .replace("i", "") + .trim()); + boolean status = false; + if (type.contains("b")) + status = usingEngine.upgradeBuilding(clientMap, val); + else + status = usingEngine.upgradeInhabitant(clientMap, val); + if (status) + sendAndLogLn("Client " + clientID + " has successfully upgraded " + type + "!"); + else + sendAndLogLn("Client " + clientID + " was unable to upgrade " + type + "!"); + } catch (GameEngine.UpgradingErrorException e){ + sendAndLogLn(e.getMessage()); + } break; case PacketTable.PRINT_MAP_DATA: sendMapData(usingEngine.view.getVillageStateTable(clientMap, "Home Village")); break; + case PacketTable.EXPLORE: + Random rand = new Random(); + int clients = server.clients.size(); + int pos = rand.nextInt(clients); + while (pos == clientID) + pos = rand.nextInt(clients); + Iterator> entries = server.clients.entrySet().iterator(); + for (int i = 0; i < pos; i++) + entries.next(); + exploringMap = entries.next().getValue().clientMap; + sendMapData(usingEngine.view.getVillageStateTable(exploringMap, "Other Village")); + break; + case PacketTable.GENERATE: + exploringMap = usingEngine.generateMap(clientMap); + sendMapData(usingEngine.view.getVillageStateTable(exploringMap, "Other Village")); + break; + case PacketTable.ATTACK: + if (exploringMap != null) + usingEngine.attackVillage(clientMap, exploringMap); + else + sendAndLogLn("Error: Explored map is null. Did you explored/generated last command?"); + exploringMap = null; + break; } if (request.getPacketID() != PacketTable.ACK) sendMessage(new Message.Sent(PacketTable.ACK, clientID, request.getMessageID())); @@ -264,7 +314,7 @@ public class Server implements Runnable { DatagramPacket request = new DatagramPacket(data, data.length, address, port); try { System.out.println("Sending message with ID " + message.getMessageID() + " to client: " + message.getClientID() + " of type " + message.getPacketID()); - serverSocket.send(request); + server.socket.send(request); } catch (IOException e) { e.printStackTrace(); }