oglimmer/ggo

View on GitHub
core/src/main/java/de/oglimmer/ggo/logic/phase/CombatCommandPhase.java

Summary

Maintainability
A
2 hrs
Test Coverage
package de.oglimmer.ggo.logic.phase;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import de.oglimmer.ggo.logic.Field;
import de.oglimmer.ggo.logic.Game;
import de.oglimmer.ggo.logic.Player;
import de.oglimmer.ggo.logic.Unit;
import de.oglimmer.ggo.logic.battle.CombatPhaseRoundCounter;
import de.oglimmer.ggo.logic.battle.Command;
import de.oglimmer.ggo.logic.battle.CommandCenter;
import de.oglimmer.ggo.logic.battle.CommandType;
import de.oglimmer.ggo.ui.persistent.ModalDialog;
import de.oglimmer.ggo.ui.shortlife.UIButton;
import lombok.Data;
import lombok.Getter;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class CombatCommandPhase extends BasePhase {

    private static final long serialVersionUID = 1L;

    private CombatPhaseRoundCounter combatPhaseRoundCounter;

    private Map<Player, State> states = new HashMap<>();

    private Set<Player> inTurn = new HashSet<>();

    @Getter
    private CommandCenter cc;

    public CombatCommandPhase(Game game, CombatPhaseRoundCounter combatPhaseRoundCounter) {
        super(game);
        this.combatPhaseRoundCounter = combatPhaseRoundCounter;
        if (this.combatPhaseRoundCounter == null) {
            this.combatPhaseRoundCounter = new CombatPhaseRoundCounter();
            getGame().getPlayers().forEach(p -> p.getMessages().clearErrorInfo());
        }
        cc = new CommandCenter(game);
    }

    private State getState(Player player) {
        return states.computeIfAbsent(player, t -> new State(player));
    }

    @Override
    public void init() {
        getGame().getPlayers().forEach(p -> p.getMessages().clearErrorInfo());
        if (getGame().getBoard().getTotalUnits() == 0) {
            nextPhase();
        } else {
            cc.setAllToFortify();
            getGame().getPlayers().forEach(p -> {
                if (getGame().getBoard().getTotalUnits(p) > 0) {
                    inTurn.add(p);
                    notifyPlayer(p);
                }
            });
            if (inTurn.isEmpty()) {
                nextPhase();
            }
        }
    }

    @Override
    public boolean isHighlighted(Field field, Player forPlayer) {
        return getState(forPlayer).isHighlighted(field);
    }

    @Override
    public boolean isSelectable(Field field, Player forPlayer) {
        return getGame().getCurrentPhase().isHighlighted(field, forPlayer);
    }

    @Override
    public boolean isSelected(Unit unit, Player forPlayer) {
        return getState(forPlayer).isSelected(unit);
    }

    @Override
    public boolean isSelectable(Unit unit, Player forPlayer) {
        return getState(forPlayer).isSelectable(unit);
    }

    @Override
    public void execCmd(Player player, String cmd, String param) {
        super.execCmd(player, cmd, param);
        switch (cmd) {
        case "selectUnit":
            execSelectUnit(player, param);
            break;
        case "selectTargetField":
            execTargetField(player, param);
            break;
        case "selectModalDialog":
            execModalDialog(player, param);
            break;
        case "button":
            if ("doneButton".equals(param)) {
                execDoneButton(player);
            }
            break;
        }
    }

    public void execDoneButton(Player player) {
        inTurn.remove(player);
        if (inTurn.isEmpty()) {
            nextPhase();
        }
    }

    private void execModalDialog(Player player, String param) {
        Unit unit = getState(player).getSelectedUnits();
        if (unit == null) {
            log.error("execTargetField but no unit was selected");
            return;
        }
        Field targetField = getState(player).getSelectedFields();
        if (targetField == null) {
            log.error("execTargetField but no target field was selected");
            return;
        }
        if (!"Cancel".equalsIgnoreCase(param)) {
            CommandType commandType = CommandType.valueOf(param);
            cc.addCommand(unit, targetField, commandType);
        }
        getState(player).clear();
    }

    private void execTargetField(Player player, String param) {
        Unit unit = getState(player).getSelectedUnits();
        if (unit == null) {
            log.error("execTargetField but no unit was selected");
            return;
        }
        Field targetField = getGame().getBoard().getField(param);
        Set<CommandType> possibleCommandTypes = unit.getPossibleCommandTypes(cc, targetField);
        if (possibleCommandTypes.size() == 0) {
            player.getMessages().setError(
                    "One of your own units is/will be alreay there. De-select your unit or chose another target field.");
        } else if (possibleCommandTypes.size() == 1) {
            cc.addCommand(unit, targetField, possibleCommandTypes.iterator().next());
            getState(player).clear();
        } else {
            getState(player).setPossibleCommandTypesOptions(possibleCommandTypes);
            getState(player).setSelectedFields(targetField);
        }
    }

    private void execSelectUnit(Player player, String param) {
        Unit unit = getGame().getBoard().getUnitById(param);
        Unit currentlySelected = getState(player).getSelectedUnits();
        if (currentlySelected != null && currentlySelected != unit) {
            log.error("Player {} has unit selected", player.getSide());
            return;
        }
        if (currentlySelected == unit) {
            cc.removeCommandForUnit(unit);
            cc.addCommand(unit, unit.getDeployedOn(), CommandType.FORTIFY);
            getState(player).clear();
        } else {
            getState(player).setSelectedUnits(unit);
        }
    }

    @Override
    protected void updateTitleMessage(Player player) {
        String title;
        if (inTurn.contains(player)) {
            Unit unit = getState(player).getSelectedUnits();
            if (unit != null) {
                title = "Choose a destination field for " + unit.getUnitType().toString();
            } else {
                title = "Command your units. Press `done` when finished. Round "
                        + combatPhaseRoundCounter.getCurrentRound() + " of " + combatPhaseRoundCounter.getMaxRounds();
            }
        } else {
            title = "Wait for your opponent to finish the turn. Round " + combatPhaseRoundCounter.getCurrentRound()
                    + " of " + combatPhaseRoundCounter.getMaxRounds();
        }
        player.getMessages().setTitle(title);
    }

    @Override
    protected void updateModalDialg(Player player) {
        if (getState(player).getPossibleCommandTypesOptions() != null) {
            player.getModalDialog().setShow(true);
            player.getModalDialog().setTitle("Choose a command");
            player.getModalDialog().getOptions().clear();
            for (CommandType ct : getState(player).getPossibleCommandTypesOptions()) {
                player.getModalDialog().getOptions().add(new ModalDialog.Option(ct.name(), ct.name()));
            }
            player.getModalDialog().getOptions().add(new ModalDialog.Option("Cancel", "Cancel"));
        } else {
            player.getModalDialog().setShow(false);
        }
    }

    @Override
    protected void nextPhase() {
        boolean initShouldBeCalled = getGame()
                .setCurrentPhase(new CombatDisplayPhase(getGame(), combatPhaseRoundCounter, cc));
        assert initShouldBeCalled;
        getGame().getCurrentPhase().init();
    }

    @Override
    public Collection<UIButton> getButtons(Player forPlayer) {
        Collection<UIButton> buttons = new ArrayList<>();
        buttons.add(UIButton.builder().id("doneButton").text("Done").width(30).height(20)
                .hidden(!inTurn.contains(forPlayer)).build());
        return buttons;
    }

    @Override
    public Command getCommand(Unit unit, Player forPlayer) {
        Command command = cc.getByUnit(unit);
        if (command != null && command.getUnit().getPlayer() == forPlayer) {
            return command;
        }
        return null;
    }

    @Override
    public String toString() {
        return "CombatCommandPhase [inTurn="
                + inTurn.stream().map(p -> p.getSide().toString()).collect(Collectors.joining(",")) + "]";
    }

    @RequiredArgsConstructor
    @Data
    class State {
        @NonNull
        private Player player;
        private Unit selectedUnits;
        private Field selectedFields;
        private Set<CommandType> possibleCommandTypesOptions;

        public void clear() {
            selectedUnits = null;
            selectedFields = null;
            possibleCommandTypesOptions = null;
        }

        public boolean isHighlighted(Field field) {
            if (isPickUnit()) {
                return false;
            } else if (isPickTargetField()) {
                return selectedUnits.hasCommandOnField(cc, field);
            } else if (isPickCommand()) {
                return selectedUnits.hasCommandOnField(cc, field);
            }
            return false;
        }

        public boolean isSelected(Unit unit) {
            return selectedUnits == unit && unit.getPlayer() == player;
        }

        public boolean isSelectable(Unit unit) {
            if (isPickUnit()) {
                return unit.getPlayer() == player && unit.isOnBoard();
            } else if (isPickTargetField()) {
                return unit == selectedUnits;
            } else if (isPickCommand()) {
                return unit == selectedUnits;
            }
            return false;
        }

        private boolean isPickUnit() {
            return selectedUnits == null && selectedFields == null && possibleCommandTypesOptions == null;
        }

        private boolean isPickTargetField() {
            return selectedUnits != null && selectedFields == null && possibleCommandTypesOptions == null;
        }

        private boolean isPickCommand() {
            return selectedUnits != null && selectedFields != null && possibleCommandTypesOptions != null;
        }
    }
}