package com.galvarez.ttw.model;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.artemis.Aspect;
import com.artemis.ComponentMapper;
import com.artemis.Entity;
import com.artemis.annotations.Wire;
import com.artemis.systems.EntityProcessingSystem;
import com.galvarez.ttw.model.components.AIControlled;
import com.galvarez.ttw.model.components.Destination;
import com.galvarez.ttw.model.components.InfluenceSource;
import com.galvarez.ttw.model.map.GameMap;
import com.galvarez.ttw.model.map.Influence;
import com.galvarez.ttw.model.map.MapPosition;
import com.galvarez.ttw.model.map.Terrain;
import com.galvarez.ttw.rendering.components.Description;
import com.galvarez.ttw.screens.overworld.OverworldScreen;
@Wire
public final class AISourceDestinationSystem extends EntityProcessingSystem {
private static final Logger log = LoggerFactory.getLogger(AISourceDestinationSystem.class);
private final GameMap map;
private ComponentMapper<Destination> destinations;
private ComponentMapper<MapPosition> positions;
private ComponentMapper<AIControlled> intelligences;
private DestinationSystem destinationSystem;
private final OverworldScreen screen;
@SuppressWarnings("unchecked")
public AISourceDestinationSystem(GameMap gameMap, OverworldScreen screen) {
super(Aspect.getAspectForAll(AIControlled.class, Destination.class, InfluenceSource.class));
this.map = gameMap;
this.screen = screen;
}
@Override
protected boolean checkProcessing() {
return true;
}
@Override
protected void process(Entity e) {
Destination dest = destinations.getSafe(e);
if (dest == null)
return;
AIControlled ai = intelligences.get(e);
if (dest.target == null) {
setNewTarget(e, dest, ai);
} else {
// check we are not stuck
MapPosition current = positions.get(e);
if (current.equals(ai.lastPosition)) {
// are we stuck for 3 turns?
if (screen.getTurnNumber() - ai.lastMove > 3)
setNewTarget(e, dest, ai);
} else {
ai.lastMove = screen.getTurnNumber();
ai.lastPosition = current;
}
}
}
private void setNewTarget(Entity e, Destination dest, AIControlled ai) {
// ...must find another tile to influence
int bestScore = 0;
MapPosition best = null;
for (MapPosition p : destinationSystem.getTargetTiles(e)) {
if (p.equals(dest.target))
// if it fails, do not select it again
continue;
int score = estimate(e, p);
if (score > bestScore) {
bestScore = score;
best = p;
}
}
if (best != null && !best.equals(positions.get(e))) {
destinationSystem.computePath(e, best);
ai.lastMove = screen.getTurnNumber();
ai.lastPosition = positions.get(e);
} else
log.warn("Cannot find a destination for {}", e.getComponent(Description.class));
}
private int estimate(Entity e, MapPosition p) {
int score = 0;
for (MapPosition n : map.getNeighbors(p.x, p.y, 2)) {
// worst case when near other city
if (map.getEntityAt(n) != null)
score -= 10;
// some terrains are best
Terrain terrain = map.getTerrainAt(p);
if (terrain == Terrain.GRASSLAND || terrain == Terrain.PLAIN)
score += 1;
// go on the offensive!
Influence inf = map.getInfluenceAt(p);
if (!inf.isMainInfluencer(e))
score += 1;
// favor empty tiles
if (!inf.hasMainInfluence())
score *= 2;
}
return score;
}
}