package com.galvarez.ttw.model.map;
import static java.lang.Math.max;
import java.util.Iterator;
import com.artemis.Entity;
import com.artemis.World;
import com.badlogic.gdx.utils.IntIntMap;
import com.badlogic.gdx.utils.IntIntMap.Entry;
public final class Influence implements Iterable<IntIntMap.Entry> {
public final MapPosition position;
public final Terrain terrain;
/** Entity id to influence score. */
private final IntIntMap influence = new IntIntMap();
/**
* Entity id to influence delta from last turn. Only for display when starting
* a new turn, player needs to know how things evolve.
*/
private final IntIntMap influenceDelta = new IntIntMap();
/**
* Entity id to influence target for next turn. Used to compute the increment
* at each turn.
*/
private final IntIntMap influenceTarget = new IntIntMap();
private int mainInfluence = 0;
private int mainInfluenceSource = -1;
private int secondInfluenceDiff = 0;
public Influence(MapPosition position, Terrain terrain) {
this.position = position;
this.terrain = terrain;
}
/** Set the source influence to the tile. */
public void setInfluence(Entity source, int inf) {
influence.put(source.getId(), inf);
recomputeMain();
}
/** Move the source influence on the tile. */
public void moveInfluence(Entity from, Entity to) {
influence.getAndIncrement(to.getId(), 0, influence.remove(from.getId(), 0));
recomputeMain();
}
/** Remove the source influence from the tile. */
public void removeInfluence(Entity source) {
influence.remove(source.getId(), 0);
influenceDelta.remove(source.getId(), 0);
recomputeMain();
}
public Iterable<IntIntMap.Entry> getDelta() {
return influenceDelta;
}
public int getDelta(Entity source) {
return influenceDelta.get(source.getId(), 0);
}
public void clearInfluenceTarget() {
influenceTarget.clear();
}
public void increaseTarget(Entity source, int target) {
influenceTarget.getAndIncrement(source.getId(), 0, target);
}
/** Make each participant influence closer to target and compute delta. */
public void computeNewInfluence() {
influenceDelta.clear();
// make sure all involved empires have a target influence
for (Entry e : influence) {
if (!influenceTarget.containsKey(e.key))
influenceTarget.put(e.key, 0);
}
// then compute the delta and apply it
for (Entry e : influenceTarget) {
final int current = influence.get(e.key, 0);
final int target = e.value;
int delta = 0;
if (target > current)
delta = max(1, (target - current) / 10);
else if (target < current)
delta = -max(1, (current - target) / 10);
if (delta != 0) {
// do nothing if same obviously
influence.put(e.key, max(0, current + delta));
influenceDelta.put(e.key, delta);
}
}
recomputeMain();
}
private void recomputeMain() {
int secondInfluence = Integer.MIN_VALUE;
mainInfluence = terrain.moveCost() - 1;
mainInfluenceSource = -1;
if (influence.size > 0) {
for (Iterator<Entry> it = influence.iterator(); it.hasNext();) {
Entry e = it.next();
if (e.value > mainInfluence) {
secondInfluence = mainInfluence;
mainInfluenceSource = e.key;
mainInfluence = e.value;
} else if (e.value <= 0) {
it.remove();
} else if (e.value > secondInfluence) {
secondInfluence = e.value;
}
}
}
if (secondInfluence > 0)
secondInfluenceDiff = mainInfluence - secondInfluence;
}
public int getInfluence(Entity e) {
return influence.get(e.getId(), 0);
}
public int getSecondInfluenceDiff() {
return secondInfluenceDiff;
}
public int getMainInfluenceSource() {
return mainInfluenceSource;
}
public Entity getMainInfluenceSource(World world) {
if (hasMainInfluence())
return world.getEntity(mainInfluenceSource);
else
return null;
}
public int requiredInfluence(Entity e) {
if (isMainInfluencer(e))
return 0;
int current = influence.get(e.getId(), 0);
return max(terrain.moveCost(), mainInfluence + 1) - current;
}
public boolean isMainInfluencer(Entity e) {
return e.getId() == mainInfluenceSource;
}
public boolean hasMainInfluence() {
return mainInfluenceSource >= 0;
}
public boolean hasInfluence(Entity source) {
return influence.get(source.getId(), 0) > 0;
}
public int getMaxInfluence() {
int max = 0;
for (Entry e : influence)
if (e.value > max)
max = e.value;
return max(max, terrain.moveCost());
}
public int getTotalInfluence() {
int total = 0;
for (Entry e : influence)
total += e.value;
return max(total, terrain.moveCost());
}
@Override
public Iterator<Entry> iterator() {
return influence.iterator();
}
@Override
public int hashCode() {
return position.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
else
return (obj instanceof Influence) && position.equals(((Influence) obj).position);
}
@Override
public String toString() {
return terrain + influence.toString();
}
}