package net.fe.overworldStage; import java.io.IOException; import java.io.InputStream; import java.io.ObjectInputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Set; import net.fe.Command; import net.fe.FEMultiplayer; import net.fe.Party; import net.fe.Player; import net.fe.RunesBg; import net.fe.Session; import net.fe.SoundTrack; import net.fe.editor.Level; import net.fe.editor.SpawnPoint; import net.fe.network.message.CommandMessage; import net.fe.network.message.EndTurn; import net.fe.overworldStage.context.Idle; import net.fe.overworldStage.context.TradeContext; import net.fe.overworldStage.context.WaitForMessages; import net.fe.transition.OverworldEndTransition; import net.fe.unit.Item; import net.fe.unit.MapAnimation; import net.fe.unit.Unit; import net.fe.unit.UnitIdentifier; import org.lwjgl.input.Keyboard; import org.newdawn.slick.Color; import org.newdawn.slick.util.ResourceLoader; import chu.engine.Entity; import chu.engine.Game; import chu.engine.KeyboardEvent; import chu.engine.anim.AudioPlayer; public class ClientOverworldStage extends OverworldStage { private OverworldContext context; public final Cursor cursor; UnitInfo unitInfo; private Menu<?> menu; private boolean onControl; private float[] repeatTimers; private int movX, movY; private Unit selectedUnit; protected ArrayList<Object> currentCmdString; public int camX; public int camY; public int camMaxX; public int camMaxY; public static final float TILE_DEPTH = 0.95f; public static final float ZONE_DEPTH = 0.9f; public static final float PATH_DEPTH = 0.8f; public static final float UNIT_DEPTH = 0.6f; public static final float UNIT_MAX_DEPTH = 0.5f; public static final float CHAT_DEPTH = 0.3f; public static final float MENU_DEPTH = 0.2f; public static final float CURSOR_DEPTH = 0.15f; public static final int RIGHT_AXIS = 480 - ObjectiveInfo.WIDTH/2 -2; public ClientOverworldStage(Session s) { super(s); camX = camY = 0; camMaxX = Math.max(0,grid.width*16-368); camMaxY = Math.max(0,grid.height*16-240); cursor = new Cursor(2, 2); addEntity(cursor); unitInfo = new UnitInfo(); Color c= new Color(FEMultiplayer.getLocalPlayer().getParty().getColor()); c.r = Math.max(c.r, 0.5f); c.g = Math.max(c.g, 0.5f); c.b = Math.max(c.b, 0.5f); addEntity(new RunesBg(c)); addEntity(unitInfo); addEntity(new TerrainInfo(cursor)); addEntity(new OverworldChat(this.chat)); addEntity(new ObjectiveInfo()); setControl(true); if(getCurrentPlayer().equals(FEMultiplayer.getLocalPlayer())) { context = new Idle(this, getCurrentPlayer()); addEntity(new TurnDisplay(true, Party.TEAM_BLUE)); SoundTrack.loop("overworld"); } else { context = new WaitForMessages(this); addEntity(new TurnDisplay(false, Party.TEAM_RED)); SoundTrack.loop("enemy"); } repeatTimers = new float[4]; currentCmdString = new ArrayList<Object>(); } public void setMenu(Menu<?> m){ removeEntity(menu); menu = m; if(m!=null){ addEntity(menu); } } public Menu<?> getMenu(){ return menu; } public void reset(){ context.cleanUp(); removeExtraneousEntities(); new Idle(this, getCurrentPlayer()).startContext(); } public void removeExtraneousEntities(Entity... keep){ List<Entity> keeps = Arrays.asList(keep); for(Entity e: entities){ if(!(e instanceof DoNotDestroy || keeps.contains(e))){ removeEntity(e); } } } public void includeInView(Node... coords) { // If all coords are visible in the current view, don't do anything boolean allVisible = true; for(Node n : coords) { if(n.x < camX/16 || n.x > camX/16+23 || n.y < camY/16 || n.y > camY/16+15) allVisible = false; } if(allVisible) return; int maxUp, maxLeft, maxRight, maxDown; maxUp = maxLeft = Integer.MAX_VALUE; maxRight = maxDown = Integer.MIN_VALUE; for(Node n : coords) { if(n.x < maxLeft) maxLeft = n.x; if(n.x > maxRight) maxRight = n.x; if(n.y < maxUp) maxUp = n.y; if(n.y > maxDown) maxDown = n.y; } if(camX/16+23 < maxRight) { camX = (maxRight-23)*16; } else if(camX/16 > maxLeft) { camX = maxLeft*16; } if(camY/16+15 < maxDown) { camY = (maxDown-15)*16; } else if(camY/16 > maxUp) { camY = maxUp*16; } } public void render(){ // Renderer.scale(2, 2); super.render(); } @Override public void beginStep() { super.beginStep(); for (Entity e : entities) { e.beginStep(); } MapAnimation.updateAll(); if (onControl) { List<KeyboardEvent> keys = Game.getKeys(); if (Keyboard.isKeyDown(Keyboard.KEY_UP) && repeatTimers[0] == 0) { context.onUp(); repeatTimers[0] = 0.12f; } if (Keyboard.isKeyDown(Keyboard.KEY_DOWN) && repeatTimers[1] == 0) { context.onDown(); repeatTimers[1] = 0.12f; } if (Keyboard.isKeyDown(Keyboard.KEY_LEFT) && repeatTimers[2] == 0) { context.onLeft(); repeatTimers[2] = 0.12f; } if (Keyboard.isKeyDown(Keyboard.KEY_RIGHT) && repeatTimers[3] == 0) { context.onRight(); repeatTimers[3] = 0.12f; } for(KeyboardEvent ke : keys) { if(ke.state) { if(ke.key == Keyboard.KEY_Z) context.onSelect(); else if (ke.key == Keyboard.KEY_X) context.onCancel(); } } } for(int i=0; i<repeatTimers.length; i++) { if(repeatTimers[i] > 0) { repeatTimers[i] -= Game.getDeltaSeconds(); if(repeatTimers[i] < 0) repeatTimers[i] = 0; } } processAddStack(); processRemoveStack(); } @Override public void onStep() { for (Entity e : entities) { e.onStep(); } processAddStack(); processRemoveStack(); } @Override public void endStep() { for (Entity e : entities) { e.endStep(); } processAddStack(); processRemoveStack(); } void setContext(OverworldContext c) { context.cleanUp(); context = c; } public void setControl(boolean c){ onControl = c; } public boolean hasControl(){ return onControl; } public void end(){ FEMultiplayer.getClient().sendMessage(new EndTurn()); selectedUnit = null; removeExtraneousEntities(); } @Override protected void doEndTurn(int playerID) { super.doEndTurn(playerID); context.cleanUp(); // reset assists for(Player p : session.getPlayers()) { for(Unit u : p.getParty()) { u.getAssisters().clear(); } } send(); if(FEMultiplayer.getLocalPlayer().getID() != getCurrentPlayer().getID()){ SoundTrack.loop("overworld"); } else { SoundTrack.loop("enemy"); } } protected void doStartTurn(int playerID){ super.doStartTurn(playerID); if(FEMultiplayer.getLocalPlayer().getID() == getCurrentPlayer().getID()){ context = new Idle(this, FEMultiplayer.getLocalPlayer()); addEntity(new TurnDisplay(true, Party.TEAM_BLUE)); } else { context = new WaitForMessages(this); addEntity(new TurnDisplay(false, Party.TEAM_RED)); } } protected void beforeTriggerHook(TerrainTrigger t, int x, int y){ addEntity(t.getAnimation(this, x, y)); } private void clearCmdString(){ selectedUnit = null; movX = 0; movY = 0; currentCmdString.clear(); } public void addCmd(Object cmd){ currentCmdString.add(cmd); } public void addCmd(Object... cmd){ for(Object o: cmd) currentCmdString.add(o); } @Override public void processCommands(CommandMessage message) { final CommandMessage cmds = (CommandMessage) message; boolean execute = true; if(cmds.origin == FEMultiplayer.getClient().getID()) { execute = false; } //TODO: command validation // Get unit and path final Unit unit = (cmds.unit == null ? null : getUnit(cmds.unit)); // Parse commands Command callback = new Command() { @Override public void execute() { if(unit != null) unit.setMoved(true); checkEndGame(); } }; for(int i=0; i<cmds.commands.length; i++) { Object obj = cmds.commands[i]; if(obj.equals("EQUIP") && execute) { Unit other = getUnit((UnitIdentifier) cmds.commands[++i]); other.equip((Integer) cmds.commands[++i]); } else if(obj.equals("TRADE")) { Unit u1 = getUnit((UnitIdentifier) cmds.commands[++i]); int i1 = (Integer)cmds.commands[++i]; Unit u2 = getUnit((UnitIdentifier) cmds.commands[++i]); int i2 = (Integer)cmds.commands[++i]; //Swap the two items if(execute) { TradeContext.doTrade(u1.getInventory(), u2.getInventory(), i1, i2); } } else if(obj.equals("USE")) { final int oHp = unit.getHp(); final int index = (Integer)cmds.commands[++i]; if(execute) { callback = new Command() { public void execute() { unit.use(index); unit.setMoved(true); checkEndGame(); //TODO Positioning addEntity(new Healthbar(unit, oHp, unit.getHp(), ClientOverworldStage.this){ @Override public void done() { destroy(); } }); } }; } } else if(obj.equals("RESCUE")) { final Unit rescuee = getUnit((UnitIdentifier) cmds.commands[++i]); callback = new Command() { public void execute() { unit.setMoved(true); unit.rescue(rescuee); checkEndGame(); } }; } else if(obj.equals("TAKE")) { if(execute) { Unit other = getUnit((UnitIdentifier) cmds.commands[++i]); other.give(unit); } } else if(obj.equals("DROP")) { final int dropX = (Integer) cmds.commands[++i]; final int dropY = (Integer) cmds.commands[++i]; callback = new Command() { public void execute() { unit.setMoved(true); unit.rescuedUnit().setMoved(true); unit.drop(dropX, dropY); checkEndGame(); } }; } else if(obj.equals("ATTACK") || obj.equals("HEAL")) { final UnitIdentifier other = (UnitIdentifier) cmds.commands[++i]; callback = new Command() { public void execute() { unit.setMoved(true); FEMultiplayer.goToFightStage(cmds.unit, other, cmds.attackRecords); } }; } } if(execute && unit != null) { AudioPlayer.playAudio("select", 1, 1); Path p = grid.getShortestPath(unit, unit.getXCoord()+cmds.moveX, unit.getYCoord()+cmds.moveY); grid.move(unit, unit.getXCoord()+cmds.moveX, unit.getYCoord()+cmds.moveY, true); unit.move(p, callback); includeInView(p.getAllNodes()); } else { callback.execute(); } } public void setMovX(int x){ movX = x; } public void setMovY(int y){ movY = y; } public void checkEndGame() { if(FEMultiplayer.getClient().winner != -1) { String winnerName = getPlayerByID(FEMultiplayer.getClient().winner).getName(); FEMultiplayer.getClient().winner = -1; addEntity(new OverworldEndTransition(new EndGameStage(session), winnerName)); } } public void setSelectedUnit(Unit u){ selectedUnit = u; } public void send(){ UnitIdentifier uid = null; if(selectedUnit != null) uid = new UnitIdentifier(selectedUnit); FEMultiplayer.send(uid, movX, movY, currentCmdString.toArray()); clearCmdString(); } public void loadLevel(String levelName) { try { InputStream in = ResourceLoader.getResourceAsStream("levels/"+levelName+".lvl"); ObjectInputStream ois = new ObjectInputStream(in); Level level = (Level) ois.readObject(); grid = new Grid(level.width, level.height, Terrain.NONE); Set<SpawnPoint> spawns = level.spawns; for(int i=0; i<level.tiles.length; i++) { for(int j=0; j<level.tiles[0].length; j++) { Tile tile = new Tile(j, i, level.tiles[i][j]); grid.setTerrain(j, i, tile.getTerrain()); if(Tile.getTerrainFromID(level.tiles[i][j]) == Terrain.THRONE) { int blue = 0; int red = 0; for(SpawnPoint sp : spawns) { if(sp.team.equals(Party.TEAM_BLUE)) { blue += Math.abs(sp.x-j) + Math.abs(sp.y-i); } else { red += Math.abs(sp.x-j) + Math.abs(sp.y-i); } } if(blue < red) { System.out.println(blue + " "+ red); grid.setThronePos(Party.TEAM_BLUE, j, i); } else { System.out.println(blue + " "+ red); grid.setThronePos(Party.TEAM_RED, j, i); } } addEntity(tile); } } // Add units for(Player p : session.getPlayers()) { Color team = p.getParty().getColor(); for(int i=0; i<p.getParty().size(); i++) { SpawnPoint remove = null; for(SpawnPoint sp : spawns) { if(sp.team.equals(team)) { Unit u = p.getParty().getUnit(i); addUnit(u, sp.x, sp.y); remove = sp; break; } } spawns.remove(remove); } } ois.close(); in.close(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public Unit getHoveredUnit() { return getUnit(cursor.getXCoord(), cursor.getYCoord()); } public Terrain getHoveredTerrain() { return grid.getTerrain(cursor.getXCoord(), cursor.getYCoord()); } public Unit getSelectedUnit() { return selectedUnit; } public void playSoundTrack() { if(getCurrentPlayer().equals(FEMultiplayer.getLocalPlayer())) { SoundTrack.loop("overworld"); } else { SoundTrack.loop("enemy"); } } }