Package com.jcloisterzone.game.capability

Source Code of com.jcloisterzone.game.capability.TowerCapability

package com.jcloisterzone.game.capability;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.jcloisterzone.Player;
import com.jcloisterzone.PointCategory;
import com.jcloisterzone.XmlUtils;
import com.jcloisterzone.action.MeepleAction;
import com.jcloisterzone.action.PlayerAction;
import com.jcloisterzone.action.TowerPieceAction;
import com.jcloisterzone.board.Location;
import com.jcloisterzone.board.Position;
import com.jcloisterzone.board.pointer.FeaturePointer;
import com.jcloisterzone.event.MeeplePrisonEvent;
import com.jcloisterzone.event.TowerIncreasedEvent;
import com.jcloisterzone.feature.Tower;
import com.jcloisterzone.figure.BigFollower;
import com.jcloisterzone.figure.Follower;
import com.jcloisterzone.figure.Meeple;
import com.jcloisterzone.figure.SmallFollower;
import com.jcloisterzone.figure.predicate.MeeplePredicates;
import com.jcloisterzone.game.Capability;
import com.jcloisterzone.game.Game;


public final class TowerCapability extends Capability {

    private static final int RANSOM_POINTS = 3;

    private final Set<Position> towers = new HashSet<>();
    private final Map<Player, Integer> towerPieces = new HashMap<>();
    private boolean ransomPaidThisTurn;

    private Position lastIncreasedTower; //needed for persist game in TowerCapturePhase

    //key is Player who keeps follower imprisoned
    //synchronized because of GUI is looking inside
    //TODO fix gui hack
    private final Map<Player, List<Follower>> prisoners = Collections.synchronizedMap(new HashMap<Player, List<Follower>>());

    public TowerCapability(Game game) {
        super(game);
    }

    @Override
    public Object backup() {
        Map<Player, List<Follower>> prisonersCopy = new HashMap<>();
        for (Entry<Player, List<Follower>> entry : prisoners.entrySet()) {
            prisonersCopy.put(entry.getKey(), new ArrayList<>(entry.getValue()));
        }

        return new Object[] {
            ransomPaidThisTurn,
            new HashSet<>(towers),
            new HashMap<>(towerPieces),
            prisonersCopy
        };
    }

    @SuppressWarnings("unchecked")
    @Override
    public void restore(Object data) {
        Object[] a = (Object[]) data;
        ransomPaidThisTurn = (Boolean) a[0];
        towers.clear();
        towers.addAll((Set<Position>) a[1]);
        towerPieces.clear();
        towerPieces.putAll((Map<Player, Integer>) a[2]);
        for (Entry<Player, List<Follower>> entry : ((Map<Player, List<Follower>>)a[3]).entrySet()) {
            List<Follower> value = prisoners.get(entry.getKey());
            value.clear();
            value.addAll(entry.getValue());
        }
    }

    public void registerTower(Position p) {
        towers.add(p);
    }

    public Set<Position> getTowers() {
        return towers;
    }

    public boolean isRansomPaidThisTurn() {
        return ransomPaidThisTurn;
    }

    public void setRansomPaidThisTurn(boolean ransomPayedThisTurn) {
        this.ransomPaidThisTurn = ransomPayedThisTurn;
    }

    @Override
    public void initPlayer(Player player) {
        int pieces = 0;
        switch(game.getAllPlayers().length) {
        case 1:
        case 2: pieces = 10; break;
        case 3: pieces = 9; break;
        case 4: pieces = 7; break;
        case 5: pieces = 6; break;
        case 6: pieces = 5; break;
        }
        towerPieces.put(player, pieces);
        prisoners.put(player, Collections.synchronizedList(new ArrayList<Follower>()));
    }

    public int getTowerPieces(Player player) {
        return towerPieces.get(player);
    }

    public int setTowerPieces(Player player, int pieces) {
        return towerPieces.put(player, pieces);
    }

    public void decreaseTowerPieces(Player player) {
        int pieces = getTowerPieces(player);
        if (pieces == 0) throw new IllegalStateException("Player has no tower pieces");
        towerPieces.put(player, pieces-1);
    }

    private boolean hasSmallOrBigFollower(Player p) {
        return Iterables.any(p.getFollowers(), Predicates.and(
                MeeplePredicates.inSupply(), MeeplePredicates.instanceOf(SmallFollower.class, BigFollower.class)));
    }

    @Override
    public void prepareActions(List<PlayerAction<?>> actions, Set<FeaturePointer> followerOptions) {
        if (hasSmallOrBigFollower(game.getActivePlayer())) {
            prepareTowerFollowerDeploy(findFollowerActions(actions));
        }
        if (getTowerPieces(game.getActivePlayer()) > 0) {
            Set<Position> availTowers = getOpenTowers(0);
            if (!availTowers.isEmpty()) {
                actions.add(new TowerPieceAction().addAll(availTowers));
            }
        }
    }

    public void prepareTowerFollowerDeploy(List<MeepleAction> followerActions) {
        Set<Position> availableTowers = getOpenTowers(1);
        if (!availableTowers.isEmpty()) {
            for (Position p : availableTowers) {
                if (game.isDeployAllowed(getBoard().get(p), Follower.class)) {
                    for (MeepleAction ma : followerActions) {
                        //only small, big and phantoms are allowed on top of tower
                        if (SmallFollower.class.isAssignableFrom(ma.getMeepleType()) || BigFollower.class.isAssignableFrom(ma.getMeepleType())) {
                            ma.add(new FeaturePointer(p, Location.TOWER));
                        }
                    }
                }
            }
        }
    }

    public void placeTowerPiece(Player player, Position pos) {
        Tower tower = getBoard().get(pos).getTower();
        if (tower  == null) {
            throw new IllegalArgumentException("No tower on tile.");
        }
        if (tower.getMeeple() != null) {
            throw new IllegalArgumentException("The tower is sealed");
        }
        decreaseTowerPieces(player);
        tower.increaseHeight();
        lastIncreasedTower = pos;
        game.post(new TowerIncreasedEvent(player, pos, tower.getHeight()));
    }

    protected Set<Position> getOpenTowers(int minHeight) {
        Set<Position> availTower = new HashSet<>();
        for (Position p : getTowers()) {
            Tower t = getBoard().get(p).getTower();
            if (t.getMeeple() == null && t.getHeight() >= minHeight) {
                availTower.add(p);
            }
        }
        return availTower;
    }

    public Map<Player, List<Follower>> getPrisoners() {
        return prisoners;
    }

    public Position getLastIncreasedTower() {
        return lastIncreasedTower;
    }

    public void setLastIncreasedTower(Position lastIncreasedTower) {
        this.lastIncreasedTower = lastIncreasedTower;
    }

    public boolean hasImprisonedFollower(Player followerOwner) {
        for (Follower m : followerOwner.getFollowers()) {
            if (m.getLocation() == Location.PRISON) return true;
        }
        return false;
    }

    public boolean hasImprisonedFollower(Player followerOwner, Class<? extends Follower> followerClass) {
        for (Follower m : followerOwner.getFollowers()) {
            if (m.getLocation() == Location.PRISON && m.getClass().equals(followerClass)) return true;
        }
        return false;
    }

    public void inprison(Meeple m, Player player) {
        assert m.getLocation() == null;
        prisoners.get(player).add((Follower) m);
        game.post(new MeeplePrisonEvent(m, null, player));
        m.setLocation(Location.PRISON);
    }

    public void payRansom(Integer playerIndexToPay, Class<? extends Follower> meepleType) {
        if (ransomPaidThisTurn) {
            throw new IllegalStateException("Ransom alreasy paid this turn");
        }
        Player opponent = game.getAllPlayers()[playerIndexToPay];

        Iterator<Follower> i = prisoners.get(opponent).iterator();
        while (i.hasNext()) {
            Follower meeple = i.next();
            if (meepleType.isInstance(meeple)) {
                i.remove();
                meeple.clearDeployment();
                opponent.addPoints(RANSOM_POINTS, PointCategory.TOWER_RANSOM);
                ransomPaidThisTurn = true;
                game.getActivePlayer().addPoints(-RANSOM_POINTS, PointCategory.TOWER_RANSOM);
                game.post(new MeeplePrisonEvent(meeple, opponent, null));
                game.getPhase().notifyRansomPaid();
                return;
            }
        }
        throw new IllegalStateException("Opponent has no figure to exchage");
    }

    @Override
    public void turnCleanUp() {
        ransomPaidThisTurn = false;
        lastIncreasedTower = null;
    }

    @Override
    public void saveToSnapshot(Document doc, Element node) {
        node.setAttribute("ransomPaid", ransomPaidThisTurn + "");
        if (lastIncreasedTower != null) {
            Element it = doc.createElement("increased-tower");
            XmlUtils.injectPosition(it, lastIncreasedTower);
            node.appendChild(it);
        }
        for (Position towerPos : towers) {
            Tower tower = getBoard().get(towerPos).getTower();
            Element el = doc.createElement("tower");
            node.appendChild(el);
            XmlUtils.injectPosition(el, towerPos);
            el.setAttribute("height", "" + tower.getHeight());
        }
        for (Player player: game.getAllPlayers()) {
            Element el = doc.createElement("player");
            node.appendChild(el);
            el.setAttribute("index", "" + player.getIndex());
            el.setAttribute("pieces", "" + getTowerPieces(player));
            for (Follower follower : prisoners.get(player)) {
                Element prisoner = doc.createElement("prisoner");
                el.appendChild(prisoner);
                prisoner.setAttribute("player", "" + follower.getPlayer().getIndex());
                prisoner.setAttribute("type", "" + follower.getClass().getName());
            }
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public void loadFromSnapshot(Document doc, Element node) {
        ransomPaidThisTurn = Boolean.parseBoolean(node.getAttribute("ransomPaid"));
        NodeList nl = node.getElementsByTagName("increased-tower");
        if (nl.getLength() > 0) {
            lastIncreasedTower = XmlUtils.extractPosition((Element) nl.item(0));
        }
        nl = node.getElementsByTagName("tower");
        for (int i = 0; i < nl.getLength(); i++) {
            Element te = (Element) nl.item(i);
            Position towerPos = XmlUtils.extractPosition(te);
            Tower tower = getBoard().get(towerPos).getTower();
            tower.setHeight(Integer.parseInt(te.getAttribute("height")));
            towers.add(towerPos);
            if (tower.getHeight() > 0) {
                game.post(new TowerIncreasedEvent(null, towerPos, tower.getHeight()));
            }
        }
        nl = node.getElementsByTagName("player");
        for (int i = 0; i < nl.getLength(); i++) {
            Element playerEl = (Element) nl.item(i);
            Player player = game.getPlayer(Integer.parseInt(playerEl.getAttribute("index")));
            towerPieces.put(player, Integer.parseInt(playerEl.getAttribute("pieces")));
            NodeList priosonerNl = playerEl.getElementsByTagName("prisoner");
            for (int j = 0; j < priosonerNl.getLength(); j++) {
                Element prisonerEl = (Element) priosonerNl.item(j);
                int ownerIndex = XmlUtils.attributeIntValue(prisonerEl, "player");
                Class<? extends Meeple> meepleClass = (Class<? extends Meeple>) XmlUtils.classForName(prisonerEl.getAttribute("type"));
                Meeple m = game.getPlayer(ownerIndex).getMeepleFromSupply(meepleClass);
                inprison(m, player);
            }
        }
    }
}
TOP

Related Classes of com.jcloisterzone.game.capability.TowerCapability

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.