diff options
Diffstat (limited to 'core/src/ch/asynk/rustanddust/game/Ctrl.java')
-rw-r--r-- | core/src/ch/asynk/rustanddust/game/Ctrl.java | 612 |
1 files changed, 342 insertions, 270 deletions
diff --git a/core/src/ch/asynk/rustanddust/game/Ctrl.java b/core/src/ch/asynk/rustanddust/game/Ctrl.java index 6ec7184..9ff5d53 100644 --- a/core/src/ch/asynk/rustanddust/game/Ctrl.java +++ b/core/src/ch/asynk/rustanddust/game/Ctrl.java @@ -18,32 +18,54 @@ import ch.asynk.rustanddust.game.State.StateType; import ch.asynk.rustanddust.game.states.StateCommon; import ch.asynk.rustanddust.game.states.StateSelect; import ch.asynk.rustanddust.game.states.StateMove; -import ch.asynk.rustanddust.game.states.StateRotate; import ch.asynk.rustanddust.game.states.StatePromote; import ch.asynk.rustanddust.game.states.StateEngage; -import ch.asynk.rustanddust.game.states.StateBreak; import ch.asynk.rustanddust.game.states.StateAnimation; -import ch.asynk.rustanddust.game.states.StateReinforcement; import ch.asynk.rustanddust.game.states.StateDeployment; -import ch.asynk.rustanddust.game.states.StateWithdraw; +import ch.asynk.rustanddust.game.states.StateReinforcement; import ch.asynk.rustanddust.game.states.StateReplay; public abstract class Ctrl implements Disposable { - public enum EventType + enum Mode { - STATE_CHANGE, - HUD_ANSWER, + LOADING, + REPLAY, + PLAY, + } + + private static final boolean debugCtrl = false; + + public enum MsgType + { + OK, + CANCEL, + PROMOTE, ANIMATIONS_DONE, + UNIT_DOCK_SELECT, UNIT_DOCK_TOGGLE, - UNIT_DOCK_SELECT; + UNIT_DEPLOYED, + UNIT_UNDEPLOYED, + } + + public enum EventType + { + ORDER, + ORDER_DONE, + STATE_CHANGE, + ANIMATION, + REPLAY_DONE, + TURN_DONE, + ACTION_ABORTED, + EXIT_BATTLE, } class Event { public EventType type; public Object data; - public boolean status; + @Override + public String toString() { return String.format("Event : %s - %s", type, (data == null) ? "" : data); } } public final RustAndDust game; @@ -55,39 +77,37 @@ public abstract class Ctrl implements Disposable public Map map; public Hud hud; + private float blockEvents; public boolean blockMap; public boolean blockHud; private Hex touchedHex; + protected int gameId; protected boolean synched; private int depth; + private Order lastOrder; + private final State selectState; - private final State pathState; - private final State rotateState; + private final State moveState; private final State promoteState; private final State engageState; - private final State breakState; private final State animationState; - private final State reinforcementState; private final State deploymentState; - private final State withdrawState; + private final State reinforcementState; private final State replayState; - private int animationCount = 0; - + private Mode mode; private State state; private StateType stateType; private StateType stateAfterAnimation; public abstract void init(); - protected abstract void actionDoneCb(); - protected abstract void turnDoneCb(); - public abstract void orderProcessedCb(); public static Ctrl getCtrl(final RustAndDust game) { Ctrl ctrl = null; - switch(game.config.gameMode) { + switch(game.config.gameMode) + { case SOLO: ctrl = new Solo(game); break; @@ -102,57 +122,57 @@ public abstract class Ctrl implements Disposable this.battle = game.config.battle; this.hud = new Hud(game); - this.blockMap = false; + this.blockEvents = 0.5f; + this.blockMap = true; this.blockHud = false; this.touchedHex = null; + this.gameId = -1; this.synched = false; this.depth = 0; + this.lastOrder = null; + this.selectState = new StateSelect(); - this.pathState = new StateMove(); - this.rotateState = new StateRotate(); + this.moveState = new StateMove(); this.promoteState = new StatePromote(); this.engageState = new StateEngage(); - this.breakState = new StateBreak(); this.animationState = new StateAnimation(); - this.reinforcementState = new StateReinforcement(); this.deploymentState = new StateDeployment(); - this.withdrawState = new StateWithdraw(); + this.reinforcementState = new StateReinforcement(); this.replayState = new StateReplay(); - this.stateType = StateType.LOADING; + this.mode = Mode.LOADING; - battle.init(); - this.map = battle.getMap(); + this.map = battle.init(this); init(); StateCommon.set(game); hud.update(); - this.state = selectState; - this.stateType = StateType.DONE; - this.stateAfterAnimation = StateType.DONE; - - setState(battle.getState()); + this.stateType = StateType.WAIT_EVENT; + this.stateAfterAnimation = battle.getState(); - if (synched) { - this.hud.notify(battle.toString(), 2, Position.MIDDLE_CENTER, false); - return; - } + setState(StateType.ANIMATION); - switch(game.config.loadMode) { - case REPLAY_ALL: - // TODO REPLAY_ALL + switch(game.config.loadMode) + { + case NEW: + this.hud.notify(battle.toString(), 2, Position.MIDDLE_CENTER, false); break; - case REPLAY_LAST: - map.prepareReplayLastTurn(); - setState(StateType.REPLAY); + case RESUME: + if (!synched) { + map.prepareReplayLastAction(); + this.stateAfterAnimation = StateType.REPLAY; + } break; - case LOAD: - map.prepareReplayLastAction(); - setState(StateType.REPLAY); + case REPLAY_CURRENT: + map.prepareReplayCurrentTurn(); + this.stateAfterAnimation = StateType.REPLAY; + break; + case REPLAY_ALL: + // TODO REPLAY ALL + this.stateAfterAnimation = StateType.REPLAY; break; } - } @Override @@ -167,13 +187,9 @@ public abstract class Ctrl implements Disposable // JSON - protected boolean isLoading() - { - return (stateType == StateType.LOADING); - } - protected void load(Marshal.Mode mode, String payload) { + if (payload == null) return; JsonValue root = new JsonReader().parse(payload); battle.load(mode, root); } @@ -188,6 +204,27 @@ public abstract class Ctrl implements Disposable return writer.toString(); } + // DB + private void storeState() + { + game.db.storeGameState(gameId, battle.getTurnCount(), battle.getPlayer().id, unload(Marshal.Mode.PLAYERS), unload(Marshal.Mode.MAP)); + } + + private void storeOrders() + { + game.db.storeGameOrders(gameId, battle.getTurnCount(), battle.getPlayer().id, unload(Marshal.Mode.ORDERS)); + } + + private void clearOrders() + { + game.db.clearGameOrders(gameId); + } + + private void storeTurn() + { + game.db.storeCurrentTurn(gameId); + } + // INPUTS public boolean drag(float x, float y, int dx, int dy) @@ -199,9 +236,7 @@ public abstract class Ctrl implements Disposable public void touchDown(float hudX, float hudY, float mapX, float mapY) { - boolean inAnimation = (this.stateType == StateType.ANIMATION); - - if (!blockHud && hud.hit(hudX, hudY, inAnimation)) + if (!blockHud && hud.hit(hudX, hudY, inAnimation())) return; touchedHex = (blockMap ? null : map.getHexAt(mapX, mapY)); @@ -213,34 +248,64 @@ public abstract class Ctrl implements Disposable state.touch(touchedHex); } - // EVENTS + // MESSAGES - private Event getEvent() + public void sendMsg(MsgType msgType) { - Event evt = freeEvents.pop(); - if (evt == null) - evt = new Event(); - return evt; + sendMsg(msgType, null); } - public void postDone() { post(StateType.DONE); } - public void postAbort() { post(StateType.ABORT); } + public void sendMsg(MsgType msgType, Object data) + { + RustAndDust.debug(String.format("Msg : %s %s", msgType, data)); + switch(msgType) + { + case ANIMATIONS_DONE: animationsDone(); break; + case UNIT_DOCK_TOGGLE: unitDockToggle(); break; + case UNIT_DEPLOYED: deploymentState.processMsg(msgType, data); break; + default: + if (!this.state.processMsg(msgType, data)) + RustAndDust.error(String.format("%s does not handle msg : %s %s", this.state, msgType, data)); + break; + } + } + + // EVENTS + + public void postTurnDone() { postEvent(EventType.TURN_DONE); } + public void postActionAborted() { postEvent(EventType.ACTION_ABORTED); } + public void postReplayDone(StateType stateType) { postEvent(EventType.REPLAY_DONE, stateType); } public void post(StateType stateType) { - Event evt = getEvent(); - evt.type = EventType.STATE_CHANGE; - evt.data = stateType; - events.enqueue(evt); + postEvent(EventType.STATE_CHANGE, stateType); } - public void postAnswer(Hud.OkCancelAction what, boolean status) + public void postOrder(Order order) { - Event evt = getEvent(); - evt.type = EventType.HUD_ANSWER; - evt.data = what; - evt.status = status; - events.enqueue(evt); + postOrder(order, null); + } + + public void postInitOrder(Order order) + { + // postEvent(EventType.ORDER, order); + // postEvent(EventType.ORDER_DONE, stateType); + executeOrder(order); + orderDone(null); + } + + public void postOrder(Order order, StateType stateType) + { + postEvent(EventType.ORDER, order); + switch(order.type) + { + case END: + case REVERT: + break; + default: + postEvent(EventType.ANIMATION, StateType.WAIT_EVENT); + } + postEvent(EventType.ORDER_DONE, stateType); } public void postEvent(EventType type) @@ -250,33 +315,39 @@ public abstract class Ctrl implements Disposable public void postEvent(EventType type, Object data) { - Event evt = getEvent(); + Event evt = freeEvents.pop(); + if (evt == null) + evt = new Event(); evt.type = type; evt.data = data; events.enqueue(evt); } - public void processEvent() + public void processEvent(float delta) { - if (events.size() <= 0) + if (blockEvents > 0f) { + blockEvents -= delta; + if (blockEvents > 0f) + return; + } + if ((events.size() <= 0) || inAnimation()) return; Event evt = events.dequeue(); - switch(evt.type) { - case STATE_CHANGE: - setState((StateType) evt.data); - break; - case HUD_ANSWER: - handleHudAnswer(evt); - break; - case ANIMATIONS_DONE: - animationsDone(); - break; - case UNIT_DOCK_TOGGLE: - unitDockToggle(); - break; - case UNIT_DOCK_SELECT: - unitDockSelect((Unit) evt.data); + RustAndDust.debug(evt.toString()); + + switch(evt.type) + { + case ORDER: executeOrder((Order) evt.data); break; + case ORDER_DONE: orderDone((StateType) evt.data); break; + case STATE_CHANGE: setState((StateType) evt.data); break; + case REPLAY_DONE: replayDone((StateType) evt.data); break; + case TURN_DONE: turnDone(); break; + case ACTION_ABORTED: abortAction(); break; + case EXIT_BATTLE: exitBattle(); break; + case ANIMATION: + stateAfterAnimation = (StateType) evt.data; + setState(StateType.ANIMATION); break; default: RustAndDust.error(String.format("Unhandled Event Type : %s %s", evt.type, evt.data)); @@ -284,243 +355,244 @@ public abstract class Ctrl implements Disposable freeEvents.push(evt); } - // State callbacks - - public void setAfterAnimationState(StateType after) + private boolean inAnimation() { - stateAfterAnimation = after; - } - - // Event handlers - - private void handleHudAnswer(Event evt) - { - switch((Hud.OkCancelAction) evt.data) { - case EXIT_BOARD: - if (evt.status) setState(StateType.DONE); - else setState(StateType.ABORT); - break; - case ABORT_TURN: - if (evt.status) { - this.state.abort(); - turnDone(); - } - break; - case END_DEPLOYMENT: - if (evt.status) { - this.state.execute(); - turnDone(); - } - break; - case QUIT_BATTLE: - if (evt.status) - game.switchToMenu(); - break; - - } + return (this.stateType == StateType.ANIMATION); } private void animationsDone() { + if (debugCtrl) RustAndDust.debug(" ANIMATIONS DONE"); + if (hud.dialogActive()) hud.notifyAnimationsDone(); - if (stateType == StateType.ANIMATION) { - StateType tmp = stateAfterAnimation; - stateAfterAnimation = StateType.DONE; - setState(tmp); + + if (mode == Mode.LOADING) { + this.mode = ((stateAfterAnimation == StateType.REPLAY) ? Mode.REPLAY : Mode.PLAY); + if (game.config.loadMode == Config.LoadMode.NEW) { + storeState(); + storeTurn(); + } + if (mode == Mode.PLAY) + map.clear(true); } + this.blockMap = false; + StateType tmp = stateAfterAnimation; + stateAfterAnimation = StateType.WAIT_EVENT; + setState(tmp); } - private void unitDockSelect(Unit unit) + private void replayDone(StateType nextState) { - if ((stateType == StateType.DEPLOYMENT) || (stateType == StateType.REINFORCEMENT)) - state.touch(null); + if (debugCtrl) RustAndDust.debug(" REPLAY DONE"); + hud.notify("Replay Done", Position.MIDDLE_CENTER); + this.mode = Mode.PLAY; + if (nextState != null) { + setState(nextState); + } else { + if (!synched) { + storeState(); + synched = true; + } + if (battle.getPlayer().apExhausted()) + postTurnDone(); + else if (!battle.getPlayer().canDoSomething()) + postTurnDone(); + else + setState(battle.getState()); + } } - private void unitDockToggle() + private void executeOrder(Order order) { - if (this.stateType == StateType.SELECT) - setState(StateType.REINFORCEMENT); - else if (this.stateType == StateType.REINFORCEMENT) - setState(StateType.SELECT); + if (debugCtrl) RustAndDust.debug(" EXECUTE ORDER"); + lastOrder = order; + map.execute(order); + if ((order.type == Order.OrderType.ENGAGE) && !order.replay) { + game.ctrl.hud.engagementSummary(order.engagement); + } + if (this.mode == Mode.PLAY) + storeOrders(); + hud.update(); } - // - - private void turnDone() + private void orderDone(StateType nextState) { - if (battle.turnDone()) - hud.victory(battle.getPlayer(), battle.getOpponent()); - else { - if (battle.getPlayer().hasReinforcement()) - hud.notify("You have reinforcement", 2, Position.MIDDLE_CENTER, true); - hud.update(); - if (!battle.getPlayer().canDoSomething()) { - hud.notify("No available Actions"); - setState(StateType.TURN_OVER); - } else - setState(battle.getState()); - } - } + if (debugCtrl) RustAndDust.debug(" ORDER DONE -> " + nextState); + Order order = this.lastOrder; + this.lastOrder = null; + if (nextState == null) + nextState = battle.getState(); - // + completeOrder(order); - private void setState(StateType nextState) - { - depth += 1; - if (depth > 1) - RustAndDust.error(String.format("***!!!*** STATE DEPTH : %d", depth)); + if (mode == Mode.LOADING) + return; - if (nextState == StateType.ABORT) - nextState = abortAction(); - else if (nextState == StateType.DONE) { - nextState = complete(); + if (mode == Mode.REPLAY) { + if (order.cost > 0) + battle.getPlayer().burnDownOneAp(); + hud.update(); + blockEvents = 0.2f; + post(nextState); + return; } - if (stateType == StateType.ANIMATION) { - this.blockMap = hud.dialogActive(); - if (nextState == StateType.REPLAY) - completeReplayStep(); + if (order.cost == 0) { + post(nextState); + return; } - hud.playerInfo.blockEndOfTurn(nextState != StateType.SELECT); - - if (nextState == stateType) - RustAndDust.debug(String.format("***!!!*** STATE LOOP : %s", stateType)); - - this.state.leaveFor(nextState); - - this.state = getNextState(nextState); - - StateType tmp = stateType; - stateType = nextState; + battle.getPlayer().burnDownOneAp(); + hud.notify("1 Action Point burnt"); + hud.update(); - this.state.enterFrom(tmp); + if (battle.getPlayer().apExhausted()) { + hud.notify("No more Action Points"); + postTurnDone(); + } else if (!battle.getPlayer().canDoSomething()) { + hud.notify("No available Actions"); + postTurnDone(); + } else { + post(nextState); + } - if (nextState == StateType.TURN_OVER) - turnDone(); - depth -= 1; + storeState(); } - private StateType complete() + private void completeOrder(Order order) { - switch(stateType) { - case DEPLOYMENT: - return completeDeployment(); - case REPLAY: - return completeReplay(); - default: - return completeAction(); + switch(order.type) + { + case MOVE: completeMoveOrder(order, (Unit) order.move.pawn); break; + case ENGAGE: completeEngagementOrder(order, order.engagement.defender); break; + case PROMOTE: battle.getPlayer().promote(order.leader); break; + case REVERT: break; + case END: break; + default: break; } } - private StateType completeDeployment() + private void completeEngagementOrder(Order order, Unit unit) { - if (battle.isDeploymentDone()) - hud.askEndDeployment(); - battle.actionDone(); - return StateType.DEPLOYMENT; + if (order.engagement.success) { + battle.getPlayer().engagementWon += 1; + battle.getOpponent().casualty(unit); + } else { + battle.getPlayer().engagementLost += 1; + } } - private StateType abortAction() + private void completeMoveOrder(Order order, Unit unit) { - hud.notify("Action canceled"); - StateType nextState = this.state.abort(); - - if (nextState == StateType.ABORT) - nextState = battle.getState(); - - return nextState; + switch(order.move.type) + { + case EXIT: battle.getPlayer().unitWithdraw(unit); break; + case SET: battle.getPlayer().unitEntry(unit); break; + case ENTER: battle.getPlayer().unitEntry(unit); break; + case REGULAR: break; + default: break; + } } - private StateType completeAction() + private void turnDone() { - StateType nextState = this.state.execute(); + if (debugCtrl) RustAndDust.debug(" TURN DONE"); - if (nextState == StateType.DONE) { - if (battle.actionDone()) { - hud.notify("1 Action Point burnt"); - hud.update(); - } - if (battle.getPlayer().apExhausted()) { - hud.notify("No more Action Points"); - nextState = StateType.TURN_OVER; - } else if (!battle.getPlayer().canDoSomething()) { + setState(StateType.WAIT_EVENT); + + if (battle.turnDone()) + hud.victory(battle.getPlayer(), battle.getOpponent()); + else { + hud.update(); + if (battle.getPlayer().hasReinforcement()) + hud.notify("You have reinforcement", 2, Position.MIDDLE_CENTER, true); + if (!battle.getPlayer().canDoSomething()) { hud.notify("No available Actions"); - nextState = StateType.TURN_OVER; - } else - nextState = battle.getState(); + postTurnDone(); + } else { + post(battle.getState()); + } } - return nextState; + storeState(); + storeTurn(); + map.clear(true); + clearOrders(); } - private StateType completeReplay() + private void abortAction() { - if (battle.getPlayer().apExhausted()) { - return StateType.TURN_OVER; - } else if (!battle.getPlayer().canDoSomething()) { - return StateType.TURN_OVER; - } else - return battle.getState(); + if (debugCtrl) RustAndDust.debug(" ABORT ACTION"); + post(battle.getState()); } - private void completeReplayStep() + private void exitBattle() { - StateType nextState = replayState.execute(); + if (debugCtrl) RustAndDust.debug(" EXIT BATTLE"); + game.switchToMenu(); + } - if (nextState == StateType.DONE) { - battle.getPlayer().burnDownOneAp(); - hud.update(); + private void unitDockToggle() + { + if (this.stateType == StateType.SELECT) + post(StateType.REINFORCEMENT); + else if (this.stateType == StateType.REINFORCEMENT) { + sendMsg(MsgType.OK); + post(StateType.SELECT); } } - private State getNextState(StateType nextState) + // + + private void setState(StateType nextState) { - RustAndDust.debug("Ctrl", String.format(" %s -> %s : %s", stateType, nextState, battle.getPlayer())); + if (stateType == nextState) + RustAndDust.error("***!!!*** STATE LOOP ********************************************************************** " + stateType); - State state = this.state; + if (nextState == StateType.WAIT_EVENT) { + stateType = nextState; + if (debugCtrl) RustAndDust.debug(" WAIT_EVENT"); + return; + } - switch(nextState) { - case SELECT: - state = selectState; - break; - case MOVE: - state = pathState; - break; - case ROTATE: - state = rotateState; - break; - case PROMOTE: - state = promoteState; - break; - case ENGAGE: - state = engageState; - break; - case BREAK: - state = breakState; - break; - case WITHDRAW: - state = withdrawState; - break; - case ANIMATION: - state = animationState; - this.blockMap = true; - break; - case REINFORCEMENT: - state = reinforcementState; - break; - case DEPLOYMENT: - state = deploymentState; - break; - case REPLAY: - state = replayState; - break; + depth += 1; + if (depth > 1) + RustAndDust.error(String.format("***!!!*** STATE DEPTH : %d", depth)); + + if (nextState == StateType.DEPLOYMENT) { + if (battle.isDeploymentDone()) + hud.askEndDeployment(); + } + + hud.playerInfo.blockEndOfTurn(nextState != StateType.SELECT); + + this.state = getNextState(nextState); + StateType tmp = stateType; + stateType = nextState; + this.state.enterFrom(tmp); + + depth -= 1; + } + + private State getNextState(StateType nextState) + { + RustAndDust.debug(" State Change", String.format("%s -> %s", stateType, nextState)); + + switch(nextState) + { + case SELECT: return selectState; + case MOVE: return moveState; + case PROMOTE: return promoteState; + case ENGAGE: return engageState; + case ANIMATION: return animationState; + case DEPLOYMENT: return deploymentState; + case REINFORCEMENT: return reinforcementState; + case REPLAY: return replayState; default: RustAndDust.error(String.format("Unhandled State : %s", nextState)); - break; } - return state; + return this.state; } } |