Converted all logic/map files to Kotlin

This commit is contained in:
Yair Morgenstern 2018-02-25 00:07:40 +02:00
parent 18be9e37b2
commit 113f3965fc
19 changed files with 561 additions and 603 deletions

View file

@ -111,7 +111,7 @@ public class CivilizationInfo {
statsForTurn.happiness=0;
int transportationUpkeep = 0;
for(TileInfo tile : gameInfo.tileMap.values()) {
for(TileInfo tile : gameInfo.tileMap.getValues()) {
if(tile.isCityCenter()) continue;
if (tile.roadStatus == RoadStatus.Road) transportationUpkeep+=1;
else if(tile.roadStatus == RoadStatus.Railroad) transportationUpkeep+=2;

View file

@ -1,15 +0,0 @@
package com.unciv.logic.civilization;
import com.badlogic.gdx.math.Vector2;
public class Notification{
public String text;
public Vector2 location;
Notification(){}
public Notification(String text, Vector2 location) {
this.text = text;
this.location = location;
}
}

View file

@ -0,0 +1,15 @@
package com.unciv.logic.civilization
import com.badlogic.gdx.math.Vector2
class Notification {
@JvmField var text: String = ""
@JvmField var location: Vector2? = null
internal constructor() {}
constructor(text: String, location: Vector2?) {
this.text = text
this.location = location
}
}

View file

@ -63,7 +63,7 @@ public class TechManager {
});
if (revealedResource != null)
for (TileInfo tileInfo : civInfo.gameInfo.tileMap.values())
for (TileInfo tileInfo : civInfo.gameInfo.tileMap.getValues())
if (revealedResource.name.equals(tileInfo.resource) && civInfo.civName.equals(tileInfo.owner)) {
for (int i = 0; ; i++) {
TileInfo cityTile = civInfo.gameInfo.tileMap.getTilesAtDistance(tileInfo.position, i)

View file

@ -1,130 +0,0 @@
package com.unciv.logic.map;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Predicate;
import com.unciv.logic.civilization.CivilizationInfo;
import com.unciv.models.gamebasics.GameBasics;
import com.unciv.models.gamebasics.TileImprovement;
import com.unciv.models.linq.Linq;
public class MapUnit{
public transient CivilizationInfo civInfo;
public String owner;
public String name;
public int maxMovement;
public float currentMovement;
public String action; // work, automation, fortifying, I dunno what.
public void doPreTurnAction(TileInfo tile){
if(currentMovement==0) return; // We've already done stuff this turn, and can't do any more stuff
if(action!=null && action.startsWith("moveTo")){
String[] destination = action.replace("moveTo ","").split(",");
Vector2 destinationVector = new Vector2(Integer.parseInt(destination[0]), Integer.parseInt(destination[1]));
TileInfo gotTo = headTowards(tile.position,destinationVector);
if(gotTo==null) // we couldn't move there because another unit was in the way!
return;
if(gotTo.position.equals(destinationVector)) action=null;
if(currentMovement!=0) doPreTurnAction(gotTo);
return;
}
if ("automation".equals(action)) doAutomatedAction(tile);
}
public void doPostTurnAction(TileInfo tile){
if(name.equals("Worker") && tile.improvementInProgress!=null) workOnImprovement(tile);
}
private void workOnImprovement(TileInfo tile){
tile.turnsToImprovement -= 1;
if(tile.turnsToImprovement == 0)
{
if (tile.improvementInProgress.startsWith("Remove")) tile.terrainFeature = null;
else if(tile.improvementInProgress.equals("Road")) tile.roadStatus = RoadStatus.Road;
else if(tile.improvementInProgress.equals("Railroad")) tile.roadStatus = RoadStatus.Railroad;
else tile.improvement = tile.improvementInProgress;
tile.improvementInProgress = null;
}
}
private int getPriority(TileInfo tileInfo){
int priority =0;
if(tileInfo.workingCity!=null) priority+=2;
if(tileInfo.hasViewableResource(civInfo)) priority+=1;
if(tileInfo.owner!=null) priority+=2;
else if(tileInfo.getNeighbors().any(new Predicate<TileInfo>() {
@Override
public boolean evaluate(TileInfo arg0) {
return arg0.owner!=null;
}
})) priority+=1;
return priority;
}
public TileInfo findTileToWork(TileInfo currentTile){
TileInfo selectedTile = currentTile;
int tilePriority = currentTile.improvement==null
&& currentTile.canBuildImprovement(chooseImprovement(currentTile), civInfo)
? getPriority(currentTile) : 1; // min rank to get selected is 2
for (int i = 1; i < 5; i++)
for (TileInfo tile : civInfo.gameInfo.tileMap.getTilesAtDistance(currentTile.position,i))
if(tile.unit==null && tile.improvement==null && getPriority(tile)>tilePriority
&& tile.canBuildImprovement(chooseImprovement(tile),civInfo)){
selectedTile = tile;
tilePriority = getPriority(tile);
}
return selectedTile;
}
public void doAutomatedAction(TileInfo tile){
TileInfo toWork = findTileToWork(tile);
if(toWork!=tile) {
tile = headTowards(tile.position, toWork.position);
doPreTurnAction(tile);
return;
}
if(tile.improvementInProgress == null){
TileImprovement improvement =chooseImprovement(tile);
if(tile.canBuildImprovement(improvement,civInfo)) // What if we're stuck on this tile but can't build there?
tile.startWorkingOnImprovement(improvement,civInfo);
}
}
private TileImprovement chooseImprovement(final TileInfo tile){
return GameBasics.TileImprovements.get(chooseImprovementString(tile));
}
private String chooseImprovementString(final TileInfo tile){
if(tile.improvementInProgress!=null) return tile.improvementInProgress;
if("Forest".equals(tile.terrainFeature)) return "Lumber mill";
if("Jungle".equals(tile.terrainFeature)) return "Trading post";
if("Marsh".equals(tile.terrainFeature)) return "Remove Marsh";
if(tile.resource!=null) return tile.getTileResource().improvement;
if(tile.baseTerrain.equals("Hill")) return "Mine";
if(tile.baseTerrain.equals("Grassland") || tile.baseTerrain.equals("Desert") || tile.baseTerrain.equals("Plains"))
return "Farm";
if(tile.baseTerrain.equals("Tundra")) return "Trading post";
return null;
}
/**
*
* @param origin
* @param destination
* @return The tile that we reached this turn
*/
public TileInfo headTowards(Vector2 origin, Vector2 destination){
TileMap tileMap = civInfo.gameInfo.tileMap;
boolean isMachieneryResearched = civInfo.tech.isResearched("Machinery");
Linq<TileInfo> path = tileMap.getShortestPath(origin,destination,currentMovement,maxMovement, isMachieneryResearched);
TileInfo destinationThisTurn = path.get(0);
if(destinationThisTurn.unit!=null) return null;
float distanceToTile = tileMap.getDistanceToTilesWithinTurn(origin,currentMovement,isMachieneryResearched).get(destinationThisTurn);
tileMap.get(origin).moveUnitToTile(destinationThisTurn, distanceToTile);
return destinationThisTurn;
}
}

View file

@ -0,0 +1,141 @@
package com.unciv.logic.map
import com.badlogic.gdx.math.Vector2
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.gamebasics.TileImprovement
import java.text.DecimalFormat
class MapUnit {
@Transient
@JvmField var civInfo: CivilizationInfo? = null
@JvmField var owner: String? = null
@JvmField var name: String? = null
@JvmField var maxMovement: Int = 0
@JvmField var currentMovement: Float = 0.toFloat()
@JvmField var action: String? = null // work, automation, fortifying, I dunno what.
val movementString: String
get() = DecimalFormat("0.#").format(currentMovement.toDouble()) + "/" + maxMovement
fun doPreTurnAction(tile: TileInfo) {
if (currentMovement == 0f) return // We've already done stuff this turn, and can't do any more stuff
if (action != null && action!!.startsWith("moveTo")) {
val destination = action!!.replace("moveTo ", "").split(",").dropLastWhile { it.isEmpty() }.toTypedArray()
val destinationVector = Vector2(Integer.parseInt(destination[0]).toFloat(), Integer.parseInt(destination[1]).toFloat())
val gotTo = headTowards(tile.position, destinationVector)
if(gotTo==tile) // We didn't move at all
return
if (gotTo.position == destinationVector) action = null
if (currentMovement != 0f) doPreTurnAction(gotTo)
return
}
if ("automation" == action) doAutomatedAction(tile)
}
private fun doPostTurnAction(tile: TileInfo) {
if (name == "Worker" && tile.improvementInProgress != null) workOnImprovement(tile)
}
private fun workOnImprovement(tile: TileInfo) {
tile.turnsToImprovement -= 1
if (tile.turnsToImprovement != 0) return
when {
tile.improvementInProgress!!.startsWith("Remove") -> tile.terrainFeature = null
tile.improvementInProgress == "Road" -> tile.roadStatus = RoadStatus.Road
tile.improvementInProgress == "Railroad" -> tile.roadStatus = RoadStatus.Railroad
else -> tile.improvement = tile.improvementInProgress
}
tile.improvementInProgress = null
}
private fun getPriority(tileInfo: TileInfo): Int {
var priority = 0
if (tileInfo.workingCity != null) priority += 2
if (tileInfo.hasViewableResource(civInfo!!)) priority += 1
if (tileInfo.owner == owner) priority += 2
else if (tileInfo.neighbors.any { it.owner != null }) priority += 1
return priority
}
private fun findTileToWork(currentTile: TileInfo): TileInfo {
var selectedTile = currentTile
var selectedTilePriority =
if (currentTile.improvement == null && currentTile.canBuildImprovement(chooseImprovement(currentTile), civInfo!!))
getPriority(currentTile)
else
1 // min rank to get selected is 2
for (i in 1..4)
for (tile in civInfo!!.gameInfo.tileMap.getTilesAtDistance(currentTile.position, i))
if (tile.unit == null && tile.improvement == null && getPriority(tile) > selectedTilePriority
&& tile.canBuildImprovement(chooseImprovement(tile), civInfo!!)) {
selectedTile = tile
selectedTilePriority = getPriority(tile)
}
return selectedTile
}
fun doAutomatedAction(tile: TileInfo) {
var tile = tile
val toWork = findTileToWork(tile)
if (toWork != tile) {
tile = headTowards(tile.position, toWork.position)
doPreTurnAction(tile)
return
}
if (tile.improvementInProgress == null) {
val improvement = chooseImprovement(tile)
if (tile.canBuildImprovement(improvement, civInfo!!))
// What if we're stuck on this tile but can't build there?
tile.startWorkingOnImprovement(improvement, civInfo!!)
}
}
private fun chooseImprovement(tile: TileInfo): TileImprovement {
return GameBasics.TileImprovements[chooseImprovementString(tile)]!!
}
private fun chooseImprovementString(tile: TileInfo): String? {
when {
tile.improvementInProgress != null -> return tile.improvementInProgress
tile.terrainFeature == "Forest" -> return "Lumber mill"
tile.terrainFeature == "Jungle" -> return "Trading post"
tile.terrainFeature == "Marsh" -> return "Remove Marsh"
tile.resource != null -> return tile.tileResource!!.improvement
tile.baseTerrain == "Hill" -> return "Mine"
tile.baseTerrain == "Grassland" || tile.baseTerrain == "Desert" || tile.baseTerrain == "Plains" -> return "Farm"
tile.baseTerrain == "Tundra" -> return "Trading post"
else -> return null
}
}
/**
*
* @param origin
* @param destination
* @return The tile that we reached this turn
*/
private fun headTowards(origin: Vector2, destination: Vector2): TileInfo {
val tileMap = civInfo!!.gameInfo.tileMap
val isMachineryResearched = civInfo!!.tech.isResearched("Machinery")
val path = tileMap.getShortestPath(origin, destination, currentMovement, maxMovement, isMachineryResearched)
val destinationThisTurn = path[0]
if (destinationThisTurn.unit != null) return tileMap[origin] // Someone is blocking tohe path to the final tile...
val distanceToTile = tileMap.getDistanceToTilesWithinTurn(origin, currentMovement, isMachineryResearched)[destinationThisTurn]!!
tileMap[origin].moveUnitToTile(destinationThisTurn, distanceToTile)
return destinationThisTurn
}
fun nextTurn(tileInfo: TileInfo) {
doPostTurnAction(tileInfo)
currentMovement = maxMovement.toFloat()
doPreTurnAction(tileInfo)
}
}

View file

@ -1,85 +0,0 @@
package com.unciv.logic.map;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Predicate;
import com.unciv.models.gamebasics.GameBasics;
import com.unciv.models.gamebasics.ResourceType;
import com.unciv.models.gamebasics.Terrain;
import com.unciv.models.gamebasics.TerrainType;
import com.unciv.models.gamebasics.TileResource;
import com.unciv.models.linq.Linq;
import com.unciv.models.linq.LinqHashMap;
import com.unciv.ui.utils.HexMath;
public class RandomMapGenerator{
private TileInfo addRandomTile(Vector2 position) {
final TileInfo tileInfo = new TileInfo();
tileInfo.position = position;
Linq<Terrain> Terrains = GameBasics.Terrains.linqValues();
final Terrain baseTerrain = Terrains.where(new Predicate<Terrain>() {
@Override
public boolean evaluate(Terrain arg0) {
return arg0.type == TerrainType.BaseTerrain && !arg0.name.equals("Lakes");
}
}).getRandom();
tileInfo.baseTerrain = baseTerrain.name;
if (baseTerrain.canHaveOverlay) {
if (Math.random() > 0.7f) {
Terrain SecondaryTerrain = Terrains.where(new Predicate<Terrain>() {
@Override
public boolean evaluate(Terrain arg0) {
return arg0.type == TerrainType.TerrainFeature && arg0.occursOn.contains(baseTerrain.name);
}
}).getRandom();
if (SecondaryTerrain != null) tileInfo.terrainFeature = SecondaryTerrain.name;
}
}
addRandomResourceToTile(tileInfo);
return tileInfo;
}
void addRandomResourceToTile(final TileInfo tileInfo){
Linq<TileResource> TileResources = GameBasics.TileResources.linqValues();
// Resources are placed according to TerrainFeature, if exists, otherwise according to BaseLayer.
TileResources = TileResources.where(new Predicate<TileResource>() {
@Override
public boolean evaluate(TileResource arg0) {
return arg0.terrainsCanBeFoundOn.contains(tileInfo.getLastTerrain().name);
}
});
TileResource resource = null;
if (Math.random() < 1 / 5f) {
resource = GetRandomResource(TileResources, ResourceType.Bonus);
} else if (Math.random() < 1 / 7f) {
resource = GetRandomResource(TileResources, ResourceType.Strategic);
} else if (Math.random() < 1 / 15f) {
resource = GetRandomResource(TileResources, ResourceType.Luxury);
}
if (resource != null) tileInfo.resource = resource.name;
}
TileResource GetRandomResource(Linq<TileResource> resources, final ResourceType resourceType) {
return resources.where(new Predicate<TileResource>() {
@Override
public boolean evaluate(TileResource arg0) {
return arg0.resourceType.equals(resourceType);
}
}).getRandom();
}
public LinqHashMap<String,TileInfo> generateMap(int distance) {
LinqHashMap<String,TileInfo> map = new LinqHashMap<String, TileInfo>();
for(Vector2 vector : HexMath.GetVectorsInDistance(Vector2.Zero,distance))
map.put(vector.toString(),addRandomTile(vector));
return map;
}
}

View file

@ -0,0 +1,63 @@
package com.unciv.logic.map
import com.badlogic.gdx.math.Vector2
import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.gamebasics.ResourceType
import com.unciv.models.gamebasics.TerrainType
import com.unciv.models.gamebasics.TileResource
import com.unciv.models.linq.Linq
import com.unciv.models.linq.LinqHashMap
import com.unciv.ui.utils.HexMath
class RandomMapGenerator {
private fun addRandomTile(position: Vector2): TileInfo {
val tileInfo = TileInfo()
tileInfo.position = position
val terrains = GameBasics.Terrains.linqValues()
val baseTerrain = terrains.where { it.type === TerrainType.BaseTerrain && it.name != "Lakes" }.random
tileInfo.baseTerrain = baseTerrain!!.name
if (baseTerrain.canHaveOverlay) {
if (Math.random() > 0.7f) {
val SecondaryTerrain = terrains.where { it.type === TerrainType.TerrainFeature && it.occursOn!!.contains(baseTerrain.name) }.random
if (SecondaryTerrain != null) tileInfo.terrainFeature = SecondaryTerrain.name
}
}
addRandomResourceToTile(tileInfo)
return tileInfo
}
internal fun addRandomResourceToTile(tileInfo: TileInfo) {
var TileResources = GameBasics.TileResources.linqValues()
// Resources are placed according to TerrainFeature, if exists, otherwise according to BaseLayer.
TileResources = TileResources.where { it.terrainsCanBeFoundOn.contains(tileInfo.lastTerrain!!.name) }
var resource: TileResource? = null
if (Math.random() < 1 / 5f) {
resource = GetRandomResource(TileResources, ResourceType.Bonus)
} else if (Math.random() < 1 / 7f) {
resource = GetRandomResource(TileResources, ResourceType.Strategic)
} else if (Math.random() < 1 / 15f) {
resource = GetRandomResource(TileResources, ResourceType.Luxury)
}
if (resource != null) tileInfo.resource = resource.name
}
internal fun GetRandomResource(resources: Linq<TileResource>, resourceType: ResourceType): TileResource? {
return resources.where { it.resourceType == resourceType }.random
}
fun generateMap(distance: Int): LinqHashMap<String, TileInfo> {
val map = LinqHashMap<String, TileInfo>()
for (vector in HexMath.GetVectorsInDistance(Vector2.Zero, distance))
map[vector.toString()] = addRandomTile(vector)
return map
}
}

View file

@ -1,7 +0,0 @@
package com.unciv.logic.map;
public enum RoadStatus{
None,
Road,
Railroad
}

View file

@ -0,0 +1,7 @@
package com.unciv.logic.map
enum class RoadStatus {
None,
Road,
Railroad
}

View file

@ -1,193 +0,0 @@
package com.unciv.logic.map;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Predicate;
import com.unciv.logic.city.CityInfo;
import com.unciv.logic.civilization.CivilizationInfo;
import com.unciv.models.linq.Linq;
import com.unciv.models.gamebasics.GameBasics;
import com.unciv.models.gamebasics.Terrain;
import com.unciv.models.gamebasics.TileImprovement;
import com.unciv.models.gamebasics.TileResource;
import com.unciv.models.stats.FullStats;
import java.text.DecimalFormat;
public class TileInfo
{
public transient TileMap tileMap;
public MapUnit unit;
public Vector2 position;
public String baseTerrain;
public String terrainFeature;
public String resource;
public String improvement;
public String improvementInProgress;
public String owner; // owning civ name
public String workingCity; // Working City name
public RoadStatus roadStatus = RoadStatus.None;
public boolean explored=false;
public int turnsToImprovement;
public Terrain getBaseTerrain(){return GameBasics.Terrains.get(baseTerrain);}
public CivilizationInfo getOwner(){
if(owner==null) return null;
return tileMap.gameInfo.civilizations.first(new Predicate<CivilizationInfo>() {
@Override
public boolean evaluate(CivilizationInfo arg0) {
return arg0.civName.equals(owner);
}
});
}
public CityInfo getCity(){
if(workingCity == null) return null;
return getOwner().cities.first(new Predicate<CityInfo>() {
@Override
public boolean evaluate(CityInfo arg0) {
return arg0.name.equals(workingCity);
}
});}
public Terrain getTerrainFeature(){return terrainFeature ==null ? null : GameBasics.Terrains.get(terrainFeature);}
public Terrain getLastTerrain() {
return terrainFeature == null ? getBaseTerrain() : getTerrainFeature();
}
public TileResource getTileResource(){return resource ==null ? null : GameBasics.TileResources.get(resource);}
public boolean isCityCenter(){return getCity()!=null && position.equals(getCity().cityLocation);}
public TileImprovement getTileImprovement(){return improvement ==null ? null : GameBasics.TileImprovements.get(improvement);}
public FullStats getTileStats(CivilizationInfo observingCiv){return getTileStats(getCity(),observingCiv);}
public FullStats getTileStats(CityInfo city, CivilizationInfo observingCiv)
{
FullStats stats = getBaseTerrain().clone();
if(terrainFeature !=null){
Terrain terrainFeature = getTerrainFeature();
if(terrainFeature.overrideStats) stats = terrainFeature.clone();
else stats.add(terrainFeature);
}
TileResource resource = getTileResource();
if (hasViewableResource(observingCiv))
{
stats.add(resource); // resource base
if(resource.building !=null && city!=null && city.cityConstructions.isBuilt(resource.building))
{
stats.add(resource.GetBuilding().resourceBonusStats); // resource-specific building (eg forge, stable) bonus
}
}
TileImprovement improvement = getTileImprovement();
if (improvement != null)
{
if (resource != null && resource.improvement.equals(improvement.name))
stats.add(resource.improvementStats); // resource-specifc improvement
else stats.add(improvement); // basic improvement
if (observingCiv.tech.isResearched(improvement.improvingTech)) stats.add(improvement.improvingTechStats); // eg Chemistry for mines
if(improvement.name.equals("Trading post") && city!=null && city.civInfo.policies.isAdopted("Free Thought"))
stats.science+=1;
if(new Linq<String>("Academy","Landmark","Manufactory","Customs House").contains(improvement.name)
&& observingCiv.policies.isAdopted("Freedom Complete"))
stats.add(improvement); // again, for the double effect
}
if (isCityCenter()) {
if (stats.food < 2) stats.food = 2;
if (stats.production < 1) stats.production = 1;
}
if (stats.production < 0) stats.production = 0;
if("Jungle".equals(terrainFeature) && city!=null
&& city.getBuildingUniques().contains("JunglesProvideScience")) stats.science+=2;
if(stats.gold!=0 && observingCiv.goldenAges.isGoldenAge())
stats.gold++;
return stats;
}
public boolean canBuildImprovement(TileImprovement improvement, CivilizationInfo civInfo)
{
if(isCityCenter() || improvement.name.equals(this.improvement)) return false;
Terrain topTerrain = terrainFeature ==null ? getBaseTerrain() : getTerrainFeature();
if (improvement.techRequired != null && !civInfo.tech.isResearched(improvement.techRequired)) return false;
if (improvement.terrainsCanBeBuiltOn.contains(topTerrain.name)) return true;
if(improvement.name.equals("Road") && this.roadStatus== RoadStatus.None) return true;
if(improvement.name.equals("Railroad") && this.roadStatus != RoadStatus.Railroad) return true;
if (topTerrain.unbuildable) return false;
return hasViewableResource(civInfo) && getTileResource().improvement.equals(improvement.name);
}
public void startWorkingOnImprovement(TileImprovement improvement, CivilizationInfo civInfo)
{
improvementInProgress = improvement.name;
turnsToImprovement = improvement.getTurnsToBuild(civInfo);
}
public void stopWorkingOnImprovement()
{
improvementInProgress = null;
}
public void nextTurn()
{
if(unit !=null) {
unit.doPostTurnAction(this);
unit.currentMovement = unit.maxMovement;
unit.doPreTurnAction(this);
}
}
public String toString() {
StringBuilder SB = new StringBuilder();
if (isCityCenter()){SB.append(workingCity+",\r\n"+getCity().cityConstructions.getProductionForTileInfo());}
SB.append(this.baseTerrain);
if (terrainFeature != null) SB.append(",\r\n" + terrainFeature);
if (hasViewableResource(tileMap.gameInfo.getPlayerCivilization())) SB.append(",\r\n" + resource);
if (roadStatus!= RoadStatus.None && !isCityCenter()) SB.append(",\r\n" + roadStatus);
if (improvement != null) SB.append(",\r\n" + improvement);
if (improvementInProgress != null) SB.append(",\r\n" + improvementInProgress +" in "+this.turnsToImprovement +" turns");
if (unit !=null) SB.append(",\r\n" + unit.name + "("+ new DecimalFormat("0.#").format(unit.currentMovement)+"/"+ unit.maxMovement+")");
return SB.toString();
}
public boolean hasViewableResource(CivilizationInfo civInfo) {
return resource != null && (getTileResource().revealedBy ==null || civInfo.tech.isResearched(getTileResource().revealedBy));
}
public boolean hasIdleUnit() {
if (unit == null) return false;
if (unit.currentMovement == 0) return false;
return !(unit.name.equals("Worker") && improvementInProgress != null);
}
public void moveUnitToTile(TileInfo otherTile, float movementDistance){
if(otherTile.unit!=null) return; // Fail.
unit.currentMovement -= movementDistance;
if(unit.currentMovement < 0.1) unit.currentMovement =0; // silly floats which are "almost zero"
otherTile.unit = unit;
unit = null;
}
public Linq<TileInfo> getNeighbors(){
return tileMap.getTilesAtDistance(position,1);
}
public int getHeight(){
int height=0;
if(new Linq<String>("Forest","Jungle").contains(terrainFeature)) height+=1;
if("Hill".equals(baseTerrain)) height+=2;
return height;
}
}

View file

@ -0,0 +1,180 @@
package com.unciv.logic.map
import com.badlogic.gdx.math.Vector2
import com.unciv.logic.city.CityInfo
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.models.linq.Linq
import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.gamebasics.Terrain
import com.unciv.models.gamebasics.TileImprovement
import com.unciv.models.gamebasics.TileResource
import com.unciv.models.stats.FullStats
class TileInfo {
@Transient @JvmField var tileMap: TileMap? = null
@JvmField var unit: MapUnit? = null
@JvmField var position: Vector2 = Vector2.Zero
@JvmField var baseTerrain: String? = null
@JvmField var terrainFeature: String? = null
@JvmField var resource: String? = null
@JvmField var improvement: String? = null
@JvmField var improvementInProgress: String? = null
@JvmField var owner: String? = null // owning civ name
@JvmField var workingCity: String? = null // Working City name
@JvmField var roadStatus = RoadStatus.None
@JvmField var explored = false
@JvmField var turnsToImprovement: Int = 0
val city: CityInfo?
get() = if (workingCity == null) null else getOwner()!!.cities.first { it.name == workingCity }
val lastTerrain: Terrain
get() = if (terrainFeature == null) getBaseTerrain() else getTerrainFeature()!!
val tileResource: TileResource?
get() = if (resource == null) null else GameBasics.TileResources[resource]
val isCityCenter: Boolean
get() = city != null && position == city!!.cityLocation
val tileImprovement: TileImprovement?
get() = if (improvement == null) null else GameBasics.TileImprovements[improvement]
val neighbors: Linq<TileInfo>
get() = tileMap!!.getTilesAtDistance(position, 1)
val height: Int
get() {
var height = 0
if (Linq("Forest", "Jungle").contains(terrainFeature)) height += 1
if ("Hill" == baseTerrain) height += 2
return height
}
fun getBaseTerrain(): Terrain {
return GameBasics.Terrains[baseTerrain]!!
}
fun getOwner(): CivilizationInfo? {
return if (owner == null) null
else tileMap!!.gameInfo!!.civilizations.first { it.civName == owner }
}
fun getTerrainFeature(): Terrain? {
return if (terrainFeature == null) null else GameBasics.Terrains[terrainFeature]
}
fun getTileStats(observingCiv: CivilizationInfo): FullStats {
return getTileStats(city, observingCiv)
}
fun getTileStats(city: CityInfo?, observingCiv: CivilizationInfo): FullStats {
var stats = getBaseTerrain().clone()
if (terrainFeature != null) {
val terrainFeature = getTerrainFeature()
if (terrainFeature!!.overrideStats)
stats = terrainFeature.clone()
else
stats.add(terrainFeature)
}
val resource = tileResource
if (hasViewableResource(observingCiv)) {
stats.add(resource!!) // resource base
if (resource.building != null && city != null && city.cityConstructions.isBuilt(resource.building)) {
stats.add(resource.GetBuilding()!!.resourceBonusStats!!) // resource-specific building (eg forge, stable) bonus
}
}
val improvement = tileImprovement
if (improvement != null) {
if (resource != null && resource.improvement == improvement.name)
stats.add(resource.improvementStats!!) // resource-specifc improvement
else
stats.add(improvement) // basic improvement
if (observingCiv.tech.isResearched(improvement.improvingTech)) stats.add(improvement.improvingTechStats!!) // eg Chemistry for mines
if (improvement.name == "Trading post" && city != null && city.civInfo.policies.isAdopted("Free Thought"))
stats.science += 1f
if (Linq("Academy", "Landmark", "Manufactory", "Customs House").contains(improvement.name) && observingCiv.policies.isAdopted("Freedom Complete"))
stats.add(improvement) // again, for the double effect
}
if (isCityCenter) {
if (stats.food < 2) stats.food = 2f
if (stats.production < 1) stats.production = 1f
}
if (stats.production < 0) stats.production = 0f
if ("Jungle" == terrainFeature && city != null
&& city.buildingUniques.contains("JunglesProvideScience"))
stats.science += 2f
if (stats.gold != 0f && observingCiv.goldenAges.isGoldenAge)
stats.gold++
return stats
}
fun canBuildImprovement(improvement: TileImprovement, civInfo: CivilizationInfo): Boolean {
if (isCityCenter || improvement.name == this.improvement) return false
val topTerrain = if (terrainFeature == null) getBaseTerrain() else getTerrainFeature()
if (improvement.techRequired != null && !civInfo.tech.isResearched(improvement.techRequired)) return false
if (improvement.terrainsCanBeBuiltOn.contains(topTerrain!!.name)) return true
if (improvement.name == "Road" && this.roadStatus === RoadStatus.None) return true
if (improvement.name == "Railroad" && this.roadStatus !== RoadStatus.Railroad) return true
if (topTerrain.unbuildable) return false
return hasViewableResource(civInfo) && tileResource!!.improvement == improvement.name
}
fun startWorkingOnImprovement(improvement: TileImprovement, civInfo: CivilizationInfo) {
improvementInProgress = improvement.name
turnsToImprovement = improvement.getTurnsToBuild(civInfo)
}
fun stopWorkingOnImprovement() {
improvementInProgress = null
}
fun nextTurn() {
if (unit != null) unit!!.nextTurn(this)
}
override fun toString(): String {
val SB = StringBuilder()
if (isCityCenter) {
SB.appendln(workingCity + ",\r\n" + city!!.cityConstructions.productionForTileInfo)
}
SB.appendln(this.baseTerrain)
if (terrainFeature != null) SB.appendln(terrainFeature!!)
if (hasViewableResource(tileMap!!.gameInfo!!.playerCivilization)) SB.appendln(resource!!)
if (roadStatus !== RoadStatus.None && !isCityCenter) SB.appendln(roadStatus)
if (improvement != null) SB.appendln(improvement!!)
if (improvementInProgress != null) SB.appendln("$improvementInProgress in ${this.turnsToImprovement} turns")
if (unit != null) SB.appendln(unit!!.name + "(" + unit!!.movementString + ")")
return SB.toString()
}
fun hasViewableResource(civInfo: CivilizationInfo): Boolean {
return resource != null && (tileResource!!.revealedBy == null || civInfo.tech.isResearched(tileResource!!.revealedBy))
}
fun hasIdleUnit(): Boolean {
if (unit == null) return false
if (unit!!.currentMovement == 0f) return false
if (unit!!.name == "Worker" && improvementInProgress != null) return false;
return true;
}
fun moveUnitToTile(otherTile: TileInfo, movementDistance: Float) {
if (otherTile.unit != null) return // Fail.
unit!!.currentMovement -= movementDistance
if (unit!!.currentMovement < 0.1) unit!!.currentMovement = 0f // silly floats which are "almost zero"
otherTile.unit = unit
unit = null
}
}

View file

@ -1,149 +0,0 @@
package com.unciv.logic.map;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Predicate;
import com.unciv.logic.civilization.CivilizationInfo;
import com.unciv.models.gamebasics.GameBasics;
import com.unciv.models.linq.Linq;
import com.unciv.models.linq.LinqHashMap;
import com.unciv.ui.GameInfo;
import com.unciv.ui.utils.HexMath;
public class TileMap{
public transient GameInfo gameInfo;
private Linq<MapUnit> units;
private LinqHashMap<String, TileInfo> tiles = new LinqHashMap<String, TileInfo>();
public TileMap(){} // for json parsing, we need to have a default constructor
public Linq<TileInfo> values(){return tiles.linqValues();}
public TileMap(int distance) {
tiles = new RandomMapGenerator().generateMap(distance);
setTransients();
}
public boolean contains(Vector2 vector){ return tiles.containsKey(vector.toString());}
public TileInfo get(Vector2 vector){return tiles.get(vector.toString());}
public Linq<TileInfo> getTilesInDistance(Vector2 origin, int distance){
Linq<TileInfo> tiles = new Linq<TileInfo>();
for(Vector2 vector : HexMath.GetVectorsInDistance(origin, distance))
if(contains(vector))
tiles.add(get(vector));
return tiles;
}
public Linq<TileInfo> getTilesAtDistance(Vector2 origin, int distance){
Linq<TileInfo> tiles = new Linq<TileInfo>();
for(Vector2 vector : HexMath.GetVectorsAtDistance(origin, distance))
if(contains(vector))
tiles.add(get(vector));
return tiles;
}
public LinqHashMap<TileInfo,Float> getDistanceToTilesWithinTurn(Vector2 origin, float currentUnitMovement, boolean machineryIsResearched){
LinqHashMap<TileInfo,Float> distanceToTiles = new LinqHashMap<TileInfo, Float>();
distanceToTiles.put(get(origin), 0f);
Linq<TileInfo> tilesToCheck = new Linq<TileInfo>();
tilesToCheck.add(get(origin));
while(!tilesToCheck.isEmpty()){
Linq<TileInfo> updatedTiles = new Linq<TileInfo>();
for(TileInfo tileToCheck : tilesToCheck)
for (TileInfo maybeUpdatedTile : getTilesInDistance(tileToCheck.position,1)) {
float distanceBetweenTiles = maybeUpdatedTile.getLastTerrain().movementCost;
if(tileToCheck.roadStatus!=RoadStatus.None && maybeUpdatedTile.roadStatus!=RoadStatus.None) {
if(machineryIsResearched) distanceBetweenTiles = 1 / 3f;
else distanceBetweenTiles = 1/2f;
}
if(tileToCheck.roadStatus==RoadStatus.Railroad && maybeUpdatedTile.roadStatus==RoadStatus.Railroad) distanceBetweenTiles = 1/10f;
float totalDistanceToTile = distanceToTiles.get(tileToCheck)+ distanceBetweenTiles;
if (!distanceToTiles.containsKey(maybeUpdatedTile) || distanceToTiles.get(maybeUpdatedTile) > totalDistanceToTile) {
if(totalDistanceToTile<currentUnitMovement) updatedTiles.add(maybeUpdatedTile);
else totalDistanceToTile = currentUnitMovement;
distanceToTiles.put(maybeUpdatedTile,totalDistanceToTile);
}
}
tilesToCheck = updatedTiles;
}
return distanceToTiles;
}
public Linq<TileInfo> getShortestPath(Vector2 origin, Vector2 destination, float currentMovement, int maxMovement, boolean isMachieneryResearched){
Linq<TileInfo> toCheck = new Linq<TileInfo>(get(origin));
LinqHashMap<TileInfo,TileInfo> parents = new LinqHashMap<TileInfo, TileInfo>();
parents.put(get(origin),null);
for (int distance = 1; ; distance++) {
Linq<TileInfo> newToCheck = new Linq<TileInfo>();
for (TileInfo ti : toCheck){
for (TileInfo otherTile : getDistanceToTilesWithinTurn(ti.position, distance == 1 ? currentMovement : maxMovement, isMachieneryResearched).keySet()){
if(parents.containsKey(otherTile)) continue; // We cannot be faster than anything existing...
if(!otherTile.position.equals(destination) && otherTile.unit!=null) continue; // go to
parents.put(otherTile,ti);
if(otherTile.position.equals(destination)){
Linq<TileInfo> path = new Linq<TileInfo>();
TileInfo current = otherTile;
while(parents.get(current)!=null){
path.add(current);
current = parents.get(current);
}
return path.reverse();
}
newToCheck.add(otherTile);
}
}
toCheck = newToCheck;
}
}
public void placeUnitNearTile(Vector2 position, final String unitName, final CivilizationInfo civInfo){
MapUnit unit = GameBasics.Units.get(unitName).getMapUnit();
unit.owner = civInfo.civName;
unit.civInfo = civInfo;
getTilesInDistance(position,2).first(new Predicate<TileInfo>() {
@Override
public boolean evaluate(TileInfo arg0) {
return arg0.unit==null;
}
}).unit = unit; // And if there's none, then kill me.
}
public Linq<TileInfo> getViewableTiles(Vector2 position, int sightDistance){
final Linq<TileInfo> tiles = getTilesInDistance(position,1);
if(get(position).baseTerrain.equals("Hill")) sightDistance+=1;
for (int i = 0; i <= sightDistance; i++) {
Linq<TileInfo> tilesForLayer = new Linq<TileInfo>();
for (final TileInfo tile : getTilesAtDistance(position, i))
if (tile.getNeighbors().any(new Predicate<TileInfo>() {
@Override
public boolean evaluate(TileInfo neighbor) {
if (!tiles.contains(neighbor))
return false; // Basically, if there's a viewable neighbor which is either flatlands, or I'm taller than him
int tileHeight = neighbor.getHeight();
return tileHeight == 0 || tile.getHeight() > tileHeight;
}
})) tilesForLayer.add(tile);
tiles.addAll(tilesForLayer);
}
return tiles;
}
public void setTransients(){
for(TileInfo tileInfo: values()) tileInfo.tileMap=this;
}
}

View file

@ -0,0 +1,131 @@
package com.unciv.logic.map
import com.badlogic.gdx.math.Vector2
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.linq.Linq
import com.unciv.models.linq.LinqHashMap
import com.unciv.ui.GameInfo
import com.unciv.ui.utils.HexMath
class TileMap {
@Transient
@JvmField var gameInfo: GameInfo? = null
private var tiles = LinqHashMap<String, TileInfo>()
constructor() {} // for json parsing, we need to have a default constructor
val values: Linq<TileInfo>
get() = tiles.linqValues()
constructor(distance: Int) {
tiles = RandomMapGenerator().generateMap(distance)
setTransients()
}
operator fun contains(vector: Vector2): Boolean {
return tiles.containsKey(vector.toString())
}
operator fun get(vector: Vector2): TileInfo {
return tiles[vector.toString()]!!
}
fun getTilesInDistance(origin: Vector2?, distance: Int): Linq<TileInfo> {
return HexMath.GetVectorsInDistance(origin, distance).where{contains(it)}.select { get(it) }
}
fun getTilesAtDistance(origin: Vector2, distance: Int): Linq<TileInfo> {
return HexMath.GetVectorsAtDistance(origin, distance).where{contains(it)}.select { get(it) }
}
fun getDistanceToTilesWithinTurn(origin: Vector2, currentUnitMovement: Float, machineryIsResearched: Boolean): LinqHashMap<TileInfo, Float> {
val distanceToTiles = LinqHashMap<TileInfo, Float>()
distanceToTiles[get(origin)] = 0f
var tilesToCheck = Linq<TileInfo>(get(origin))
while (!tilesToCheck.isEmpty()) {
val updatedTiles = Linq<TileInfo>()
for (tileToCheck in tilesToCheck)
for (maybeUpdatedTile in getTilesInDistance(tileToCheck.position, 1)) {
var distanceBetweenTiles = maybeUpdatedTile.lastTerrain.movementCost.toFloat() // no road
if (tileToCheck.roadStatus !== RoadStatus.None && maybeUpdatedTile.roadStatus !== RoadStatus.None) //Road
distanceBetweenTiles = if (machineryIsResearched) 1 / 3f else 1 / 2f
if (tileToCheck.roadStatus === RoadStatus.Railroad && maybeUpdatedTile.roadStatus === RoadStatus.Railroad) // Railroad
distanceBetweenTiles = 1 / 10f
var totalDistanceToTile = distanceToTiles[tileToCheck]!! + distanceBetweenTiles
if (!distanceToTiles.containsKey(maybeUpdatedTile) || distanceToTiles[maybeUpdatedTile]!! > totalDistanceToTile) {
if (totalDistanceToTile < currentUnitMovement)
updatedTiles += maybeUpdatedTile
else
totalDistanceToTile = currentUnitMovement
distanceToTiles[maybeUpdatedTile] = totalDistanceToTile
}
}
tilesToCheck = updatedTiles
}
return distanceToTiles
}
fun getShortestPath(origin: Vector2, destination: Vector2, currentMovement: Float, maxMovement: Int, isMachineryResearched: Boolean): Linq<TileInfo> {
var tilesToCheck: Linq<TileInfo> = Linq(get(origin))
val movementTreeParents = LinqHashMap<TileInfo, TileInfo>() // contains a map of "you can get from X to Y in that turn"
movementTreeParents[get(origin)] = null
var distance = 1
while (true) {
val newTilesToCheck = Linq<TileInfo>()
for (tileToCheck in tilesToCheck) {
val movementThisTurn = if (distance == 1) currentMovement else maxMovement.toFloat()
for (reachableTile in getDistanceToTilesWithinTurn(tileToCheck.position, movementThisTurn, isMachineryResearched).keys) {
if (movementTreeParents.containsKey(reachableTile)) continue // We cannot be faster than anything existing...
if (reachableTile.position != destination && reachableTile.unit != null) continue // This is an intermediary tile that contains a unit - we can't go there!
movementTreeParents[reachableTile] = tileToCheck
if (reachableTile.position == destination) {
val path = Linq<TileInfo>() // Traverse the tree upwards to get the list of tiles leading to the destination,
var current = reachableTile
while (movementTreeParents[current] != null) {
path.add(current)
current = movementTreeParents[current]
}
return path.reverse() // and reverse in order to get the list in chronological order
}
newTilesToCheck.add(reachableTile)
}
}
tilesToCheck = newTilesToCheck
distance++
}
}
fun placeUnitNearTile(position: Vector2, unitName: String, civInfo: CivilizationInfo) {
val unit = GameBasics.Units[unitName]!!.mapUnit
unit.owner = civInfo.civName
unit.civInfo = civInfo
getTilesInDistance(position, 2).first { it.unit == null }!!.unit = unit // And if there's none, then kill me.
}
fun getViewableTiles(position: Vector2, sightDistance: Int): Linq<TileInfo> {
var sightDistance = sightDistance
val viewableTiles = getTilesInDistance(position, 1)
if (get(position).baseTerrain == "Hill") sightDistance += 1
for (i in 1..sightDistance) { // in each layer,
getTilesAtDistance(position, i).filterTo(viewableTiles) // take only tiles which have a visible neighbor, which is lower than the tile
{ tile -> tile.neighbors.any{viewableTiles.contains(it) && (it.height==0 || it.height < tile.height)} }
}
return viewableTiles
}
fun setTransients() {
for (tileInfo in values) tileInfo.tileMap = this
}
}

View file

@ -15,9 +15,9 @@ open class FullStats : CivStats()
}
fun clone():FullStats {
val FS = FullStats()
FS.add(this)
return FS
val stats = FullStats()
stats.add(this)
return stats
}
fun getMinus(): FullStats {
@ -28,22 +28,22 @@ open class FullStats : CivStats()
stats.science = -science
stats.culture = -culture
stats.happiness = -happiness
return stats;
return stats
}
operator fun times(number: Float): FullStats{
val FS = FullStats()
FS.production = production * number
FS.food = food*number
FS.gold = gold*number
FS.science = science*number
FS.culture = culture*number
FS.happiness = happiness*number
return FS
val stats = FullStats()
stats.production = production * number
stats.food = food*number
stats.gold = gold*number
stats.science = science*number
stats.culture = culture*number
stats.happiness = happiness*number
return stats
}
override fun toString(): String {
return toDict().filter{it.value!=0}.map{it.key+": "+it.value}.joinToString(",")
return toDict().filter{it.value!=0}.map{it.key+": "+it.value}.joinToString()
}
fun toDict(): HashMap<String, Int> {

View file

@ -26,7 +26,7 @@ public class GameInfo{
for(CivilizationInfo civInfo : civilizations) civInfo.nextTurn();
for(TileInfo tile : tileMap.values().where(new Predicate<TileInfo>() {
for(TileInfo tile : tileMap.getValues().where(new Predicate<TileInfo>() {
@Override
public boolean evaluate(TileInfo arg0) {
return arg0.unit!=null;
@ -52,7 +52,7 @@ public class GameInfo{
civInfo.setTransients();
}
for(final TileInfo tile : tileMap.values())
for(final TileInfo tile : tileMap.getValues())
if(tile.unit!=null) tile.unit.civInfo=civilizations.first(new Predicate<CivilizationInfo>() {
@Override
public boolean evaluate(CivilizationInfo arg0) {

View file

@ -45,8 +45,8 @@ public class HexMath
return vectors;
}
public static ArrayList<Vector2> GetVectorsAtDistance(Vector2 origin, int distance){
ArrayList<Vector2> vectors = new ArrayList<Vector2>();
public static Linq<Vector2> GetVectorsAtDistance(Vector2 origin, int distance){
Linq<Vector2> vectors = new Linq<Vector2>();
if(distance==0){vectors.add(origin.cpy()); return vectors;}
Vector2 Current = origin.cpy().sub(distance,distance); // start at 6 o clock
for (int i = 0; i < distance; i++) { // From 6 to 8

View file

@ -20,7 +20,7 @@ public class IdleUnitButton extends TextButton {
addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
Linq<TileInfo> tilesWithIdleUnits = worldScreen.civInfo.gameInfo.tileMap.values().where(new Predicate<TileInfo>() {
Linq<TileInfo> tilesWithIdleUnits = worldScreen.civInfo.gameInfo.tileMap.getValues().where(new Predicate<TileInfo>() {
@Override
public boolean evaluate(TileInfo arg0) {
return arg0.hasIdleUnit();
@ -43,7 +43,7 @@ public class IdleUnitButton extends TextButton {
}
void update() {
if (worldScreen.civInfo.gameInfo.tileMap.values().any(new Predicate<TileInfo>() {
if (worldScreen.civInfo.gameInfo.tileMap.getValues().any(new Predicate<TileInfo>() {
@Override
public boolean evaluate(TileInfo arg0) {
return arg0.hasIdleUnit();

View file

@ -42,7 +42,7 @@ public class TileMapHolder extends ScrollPane {
float bottomX = 0;
float bottomY = 0;
for (final TileInfo tileInfo : tileMap.values()) {
for (final TileInfo tileInfo : tileMap.getValues()) {
final WorldTileGroup group = new WorldTileGroup(tileInfo);
group.addListener(new ClickListener() {
@ -130,13 +130,13 @@ public class TileMapHolder extends ScrollPane {
HashSet<String> ViewableVectorStrings = new HashSet<String>();
// tiles adjacent to city tiles
for (TileInfo tileInfo : tileMap.values())
for (TileInfo tileInfo : tileMap.getValues())
if (civInfo.civName.equals(tileInfo.owner))
for (Vector2 adjacentLocation : HexMath.GetAdjacentVectors(tileInfo.position))
ViewableVectorStrings.add(adjacentLocation.toString());
// Tiles within 2 tiles of units
for (TileInfo tile : tileMap.values()
for (TileInfo tile : tileMap.getValues()
.where(new Predicate<TileInfo>() {
@Override
public boolean evaluate(TileInfo arg0) {