package com.galvarez.ttw.model;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.artemis.Aspect;
import com.artemis.ComponentMapper;
import com.artemis.Entity;
import com.artemis.EntitySystem;
import com.artemis.annotations.Wire;
import com.artemis.utils.ImmutableBag;
import com.galvarez.ttw.model.DiplomaticSystem.State;
import com.galvarez.ttw.model.components.Diplomacy;
import com.galvarez.ttw.model.components.Discoveries;
import com.galvarez.ttw.model.components.InfluenceSource;
import com.galvarez.ttw.model.components.Score;
import com.galvarez.ttw.model.data.SessionSettings;
import com.galvarez.ttw.screens.overworld.OverworldScreen;
/**
* For every empire, compute score every turn.
* <p>
* Every turn get one point per influenced tile, half the turn score from
* tributary and a quarter of the turn score from allies.
* </p>
*
* @author Guillaume Alvarez
*/
@Wire
public final class ScoreSystem extends EntitySystem {
@SuppressWarnings("unused")
private static final Logger log = LoggerFactory.getLogger(ScoreSystem.class);
private ComponentMapper<Score> scores;
private ComponentMapper<InfluenceSource> sources;
private ComponentMapper<Diplomacy> relations;
private ComponentMapper<Discoveries> discoveries;
private Item winner;
private final List<Item> list = new ArrayList<>();
private final int nbDiscoveries;
private final OverworldScreen screen;
@SuppressWarnings("unchecked")
public ScoreSystem(SessionSettings s, OverworldScreen screen) {
super(Aspect.getAspectForAll(Score.class, InfluenceSource.class));
this.screen = screen;
nbDiscoveries = s.getDiscoveries().size();
}
@Override
protected void inserted(Entity e) {
super.inserted(e);
Score score = scores.get(e);
score.nbDiscoveriesMax = nbDiscoveries;
list.add(new Item(e, score));
}
@Override
protected void removed(Entity e) {
super.removed(e);
for (Iterator<Item> it = list.iterator(); it.hasNext();)
if (it.next().empire.equals(e)) {
it.remove();
return;
}
}
@Override
protected boolean checkProcessing() {
return true;
}
@Override
protected void processEntities(ImmutableBag<Entity> entities) {
for (Entity empire : entities) {
Score score = scores.get(empire);
score.lastTurnPoints = 0;
// every empire controls itself
score.controlledEmpires.clear();
score.controlledEmpires.add(empire);
}
int nbControlledMax = entities.size();
// compute current score (may modify other entities' scores)
for (Entity empire : entities) {
InfluenceSource source = sources.get(empire);
add(empire, source.influencedTiles.size(), Collections.emptySet());
Score score = scores.get(empire);
score.nbDiscoveries = discoveries.get(empire).done.size();
score.nbControlledMax = nbControlledMax;
}
// now score is stable, sort by rank and search for winners
Collections.sort(list, Comparator.comparingInt((Item i) -> i.score.totalScore).reversed());
for (int r = 0; r < list.size(); r++) {
Item i = list.get(r);
i.score.rank = r + 1;
if (winner == null && hasWon(i.score))
winner = i;
}
if (winner != null)
screen.scoresMenu();
}
private static boolean hasWon(Score score) {
// also test "greater" in case other empires were destroyed
// it should not really happen but it does not cost anything
return score.controlledEmpires.size() >= score.nbControlledMax || score.nbDiscoveries >= score.nbDiscoveriesMax;
}
/** Recursive method to add score to all overlords and partners. */
private void add(Entity empire, int delta, Set<Entity> controlledEmpires) {
if (delta > 0
// do not forget an empire can be deleted
&& scores.has(empire)) {
Diplomacy diplomacy = relations.get(empire);
Score score = scores.get(empire);
score.lastTurnPoints += delta;
score.totalScore += delta;
score.controlledEmpires.addAll(controlledEmpires);
// add to overlords and allies
for (Entry<Entity, State> e : diplomacy.relations.entrySet()) {
if (e.getValue() == State.TREATY)
add(e.getKey(), delta / 4, Collections.emptySet());
else if (e.getValue() == State.TRIBUTE)
// overlord controls me and my vassals
add(e.getKey(), delta / 2, score.controlledEmpires);
}
}
}
public final class Item {
public final Entity empire;
public final Score score;
Item(Entity empire, Score score) {
this.empire = empire;
this.score = score;
}
}
/** Get the winner for current game. <code>null</code> if nobody has won yet. */
public Item getWinner() {
return winner;
}
public List<Item> getScores() {
return list;
}
}