All coe converted to Kotlin!

This commit is contained in:
Yair Morgenstern 2018-03-02 15:34:24 +02:00
parent 1dbb28148c
commit 9b29944c2b
99 changed files with 3753 additions and 4233 deletions

View file

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View file

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View file

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View file

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -0,0 +1,59 @@
package com.unciv.logic
import com.badlogic.gdx.math.Vector2
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.civilization.Notification
import com.unciv.logic.map.TileMap
import com.unciv.models.linq.Linq
class GameInfo {
var notifications = Linq<Notification>()
var tutorial = Linq<String>()
var civilizations = Linq<CivilizationInfo>()
var tileMap: TileMap = TileMap()
var turns = 1
fun getPlayerCivilization(): CivilizationInfo = civilizations[0]
fun addNotification(text: String, location: Vector2?) {
notifications.add(Notification(text, location))
}
fun nextTurn() {
notifications.clear()
for (civInfo in civilizations) civInfo.nextTurn()
for (tile in tileMap.values.where { it.unit != null })
tile.nextTurn()
// We need to update the stats after ALL the cities are done updating because
// maybe one of them has a wonder that affects the stats of all the rest of the cities
for (civInfo in civilizations)
for (city in civInfo.cities)
city.cityStats.update()
turns++
}
fun setTransients() {
tileMap.gameInfo = this
tileMap.setTransients()
for (civInfo in civilizations) {
civInfo.gameInfo = this
civInfo.setTransients()
}
for (tile in tileMap.values.filter { it.unit!=null })
tile.unit!!.civInfo = civilizations.first { it.civName == tile.unit!!.owner }
for (civInfo in civilizations)
for (cityInfo in civInfo.cities)
cityInfo.cityStats.update()
}
}

View file

@ -1,195 +0,0 @@
package com.unciv.logic.city;
import com.badlogic.gdx.utils.Predicate;
import com.unciv.models.linq.Linq;
import com.unciv.models.gamebasics.Building;
import com.unciv.models.gamebasics.GameBasics;
import com.unciv.models.stats.FullStats;
import java.util.HashMap;
public class CityConstructions
{
public transient CityInfo cityInfo;
static final String Worker="Worker";
static final String Settler="Settler";
public CityConstructions(){} // for json parsing, we need to have a default constructor
public Linq<String> builtBuildings = new Linq<String>();
public HashMap<String, Integer> inProgressConstructions = new HashMap<String, Integer>();
public String currentConstruction; // default starting building!
public IConstruction getCurrentConstruction(){return getConstruction(currentConstruction);}
public boolean isBuilt(String buildingName) { return builtBuildings.contains(buildingName); }
public boolean isBuilding(String buildingName) { return currentConstruction !=null && currentConstruction.equals(buildingName); }
IConstruction getConstruction(String constructionName) {
if(GameBasics.Buildings.containsKey(constructionName))
return GameBasics.Buildings.get(constructionName);
else if(GameBasics.Units.containsKey(constructionName))
return GameBasics.Units.get(constructionName);
return null;
}
public Linq<Building> getBuiltBuildings(){ return builtBuildings.select(new Linq.Func<String, Building>() {
@Override
public Building GetBy(String arg0) {
return GameBasics.Buildings.get(arg0);
}
}); }
public void addConstruction(int constructionToAdd){
if (!inProgressConstructions.containsKey(currentConstruction)) inProgressConstructions.put(currentConstruction, 0);
inProgressConstructions.put(currentConstruction, inProgressConstructions.get(currentConstruction) + constructionToAdd);
}
public void nextTurn(FullStats cityStats)
{
if (getCurrentConstruction()==null) return;
IConstruction construction = getConstruction(currentConstruction);
// Let's try to remove the building from the city, and see if we can still build it (weneed to remove because of wonders etc.
String saveCurrentConstruction = currentConstruction;
currentConstruction = null;
if(!construction.isBuildable(this)){
// We can't build this building anymore! (Wonder has been built / resource is gone / etc.)
cityInfo.civInfo.gameInfo.addNotification("Cannot continue work on "+saveCurrentConstruction,cityInfo.cityLocation);
chooseNextConstruction();
construction = getConstruction(currentConstruction);
}
else currentConstruction = saveCurrentConstruction;
addConstruction(Math.round(cityStats.production));
int productionCost = construction.getProductionCost(cityInfo.civInfo.policies.getAdoptedPolicies());
if (inProgressConstructions.get(currentConstruction) >= productionCost)
{
construction.postBuildEvent(this);
inProgressConstructions.remove(currentConstruction);
cityInfo.civInfo.gameInfo.addNotification(currentConstruction +" has been built in "+cityInfo.name,cityInfo.cityLocation);
chooseNextConstruction();
}
}
public void chooseNextConstruction() {
currentConstruction = getBuildableBuildings().first(new Predicate<String>() {
@Override
public boolean evaluate(String arg0) {
if(((Building)getConstruction(arg0)).isWonder) return false;
return !builtBuildings.contains(arg0);
}
});
if (currentConstruction == null) currentConstruction = Worker;
GameBasics.TileImprovements.keySet().contains("fds");
cityInfo.civInfo.gameInfo.addNotification("Work has started on "+ currentConstruction,cityInfo.cityLocation);
}
public Linq<String> getBuildableBuildings()
{
final CityConstructions self=this;
return new Linq<Building>(GameBasics.Buildings.values())
.where(new Predicate<Building>() {
@Override
public boolean evaluate(Building arg0) { return (arg0.isBuildable(self)); }
}).select(new Linq.Func<Building, String>() {
@Override
public String GetBy(Building arg0) {
return arg0.name;
}
});
}
public FullStats getStats()
{
FullStats stats = new FullStats();
for(Building building : getBuiltBuildings())
stats.add(building.getStats(cityInfo.civInfo.policies.getAdoptedPolicies()));
stats.science += cityInfo.getBuildingUniques().count(new Predicate<String>() {
@Override
public boolean evaluate(String arg0) {
return "SciencePer2Pop".equals(arg0);
}
}) * cityInfo.population.population/2; // Library and public school unique (not actualy unique, though...hmm)
return stats;
}
public int getMaintainanceCosts(){
int maintainanceTotal = 0;
for( Building building : getBuiltBuildings()) maintainanceTotal+=building.maintenance;
return maintainanceTotal;
}
public FullStats getStatPercentBonuses(){
FullStats stats = new FullStats();
for(Building building : getBuiltBuildings())
if(building.percentStatBonus != null)
stats.add(building.percentStatBonus);
return stats;
}
public int workDone(String constructionName) {
if (inProgressConstructions.containsKey(constructionName))
return inProgressConstructions.get(constructionName);
return 0;
}
public int turnsToConstruction(String constructionName){
int productionCost = getConstruction(constructionName).getProductionCost(cityInfo.civInfo.policies.getAdoptedPolicies());
float workLeft = productionCost - workDone(constructionName); // needs to be float so that we get the cieling properly ;)
FullStats cityStats = cityInfo.cityStats.currentCityStats;
int production = Math.round(cityStats.production);
if (constructionName.equals(Settler)) production += cityStats.food;
return (int) Math.ceil(workLeft / production);
}
public void purchaseBuilding(String buildingName) {
cityInfo.civInfo.gold -= getConstruction(buildingName).getGoldCost(cityInfo.civInfo.policies.getAdoptedPolicies());
getConstruction(buildingName).postBuildEvent(this);
if(currentConstruction.equals(buildingName)) chooseNextConstruction();
cityInfo.cityStats.update();
}
public String getCityProductionTextForCityButton(){
String result = currentConstruction;
if(!result.equals("Science") && !result.equals("Gold"))
result+="\r\n"+ turnsToConstruction(currentConstruction)+" turns";
return result;
}
public String getProductionForTileInfo(){
String result = currentConstruction;
if(!result.equals("Science") && !result.equals("Gold"))
result+="\r\nin "+ turnsToConstruction(currentConstruction)+" turns,\r\n";
return result;
}
public String getAmountConstructedText(){
if(currentConstruction.equals("Science") || currentConstruction.equals("Gold")) return "";
return " ("+ workDone(currentConstruction) + "/"+ getCurrentConstruction().getProductionCost(cityInfo.civInfo.policies.getAdoptedPolicies())+")";
}
public void addCultureBuilding() {
for (String string : new Linq<String>("Monument","Temple","Opera House","Museum")){
if(!builtBuildings.contains(string)){
builtBuildings.add(string);
if(currentConstruction.equals(string))
chooseNextConstruction();
break;
}
}
}
}

View file

@ -0,0 +1,153 @@
package com.unciv.logic.city
import com.unciv.models.linq.Linq
import com.unciv.models.gamebasics.Building
import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.stats.Stats
import java.util.HashMap
class CityConstructions {
@Transient
lateinit var cityInfo: CityInfo
var builtBuildings = Linq<String>()
private val inProgressConstructions = HashMap<String, Int>()
var currentConstruction: String = "Monument" // default starting building!
private val buildableBuildings: Linq<String>
get() {
return Linq(GameBasics.Buildings.values)
.where { it.isBuildable(this) }.select { it.name }
}
// Library and public school unique (not actualy unique, though...hmm)
fun getStats(): Stats {
val stats = Stats()
for (building in getBuiltBuildings())
stats.add(building.getStats(cityInfo.civInfo.policies.adoptedPolicies))
stats.science += (cityInfo.buildingUniques.count({ it == "SciencePer2Pop" }) * cityInfo.population.population / 2).toFloat()
return stats
}
fun getMaintenanceCosts(): Int = getBuiltBuildings().sumBy { it.maintenance }
fun getStatPercentBonuses(): Stats {
val stats = Stats()
for (building in getBuiltBuildings().where { it.percentStatBonus != null })
stats.add(building.percentStatBonus!!)
return stats
}
fun getCityProductionTextForCityButton(): String {
var result = currentConstruction
if (result != "Science" && result != "Gold")
result += "\r\n" + turnsToConstruction(currentConstruction) + " turns"
return result
}
fun getProductionForTileInfo(): String {
var result = currentConstruction
if (result != "Science" && result != "Gold")
result += "\r\nin " + turnsToConstruction(currentConstruction) + " turns,\r\n"
return result
}
fun getAmountConstructedText(): String =
if (currentConstruction == "Science" || currentConstruction == "Gold") ""
else " (" + workDone(currentConstruction) + "/" +
getCurrentConstruction().getProductionCost(cityInfo.civInfo.policies.adoptedPolicies) + ")"
fun getCurrentConstruction(): IConstruction = getConstruction(currentConstruction)
fun isBuilt(buildingName: String): Boolean = builtBuildings.contains(buildingName)
fun isBuilding(buildingName: String): Boolean = currentConstruction == buildingName
private fun getConstruction(constructionName: String): IConstruction {
if (GameBasics.Buildings.containsKey(constructionName))
return GameBasics.Buildings[constructionName]!!
else if (GameBasics.Units.containsKey(constructionName))
return GameBasics.Units[constructionName]!!
throw Exception(constructionName+ " is not a building or a unit!")
}
internal fun getBuiltBuildings(): Linq<Building> = builtBuildings.select { GameBasics.Buildings[it] }
fun addConstruction(constructionToAdd: Int) {
if (!inProgressConstructions.containsKey(currentConstruction)) inProgressConstructions[currentConstruction] = 0
inProgressConstructions[currentConstruction] = inProgressConstructions[currentConstruction]!! + constructionToAdd
}
fun nextTurn(cityStats: Stats) {
var construction = getConstruction(currentConstruction)
// Let's try to remove the building from the city, and see if we can still build it (we need to remove because of wonders etc.)
val saveCurrentConstruction = currentConstruction
currentConstruction = "lie"
if (!construction.isBuildable(this)) {
// We can't build this building anymore! (Wonder has been built / resource is gone / etc.)
cityInfo.civInfo.gameInfo.addNotification("Cannot continue work on " + saveCurrentConstruction, cityInfo.cityLocation)
chooseNextConstruction()
construction = getConstruction(currentConstruction)
} else
currentConstruction = saveCurrentConstruction
addConstruction(Math.round(cityStats.production))
val productionCost = construction.getProductionCost(cityInfo.civInfo.policies.adoptedPolicies)
if (inProgressConstructions[currentConstruction]!! >= productionCost) {
construction.postBuildEvent(this)
inProgressConstructions.remove(currentConstruction)
cityInfo.civInfo.gameInfo.addNotification(currentConstruction + " has been built in " + cityInfo.name, cityInfo.cityLocation)
chooseNextConstruction()
}
}
fun chooseNextConstruction() {
val buildableNotWonders = buildableBuildings.filterNot{(getConstruction(it) as Building).isWonder}
if(buildableNotWonders.isEmpty()) currentConstruction = Worker
else currentConstruction = buildableNotWonders.first()
cityInfo.civInfo.gameInfo.addNotification("Work has started on " + currentConstruction, cityInfo.cityLocation)
}
private fun workDone(constructionName: String): Int {
return if (inProgressConstructions.containsKey(constructionName)) inProgressConstructions[constructionName]!! else 0
}
fun turnsToConstruction(constructionName: String): Int {
val productionCost = getConstruction(constructionName).getProductionCost(cityInfo.civInfo.policies.adoptedPolicies)
val workLeft = (productionCost - workDone(constructionName)).toFloat() // needs to be float so that we get the cieling properly ;)
val cityStats = cityInfo.cityStats.currentCityStats
var production = Math.round(cityStats.production)
if (constructionName == Settler) production += cityStats.food.toInt()
return Math.ceil((workLeft / production.toDouble())).toInt()
}
fun purchaseBuilding(buildingName: String) {
cityInfo.civInfo.gold -= getConstruction(buildingName).getGoldCost(cityInfo.civInfo.policies.adoptedPolicies)
getConstruction(buildingName).postBuildEvent(this)
if (currentConstruction == buildingName) chooseNextConstruction()
cityInfo.cityStats.update()
}
fun addCultureBuilding() {
val cultureBuildingToBuild = Linq("Monument", "Temple", "Opera House", "Museum").first { !builtBuildings.contains(it) }
if (cultureBuildingToBuild == null) return
builtBuildings.add(cultureBuildingToBuild)
if (currentConstruction == cultureBuildingToBuild)
chooseNextConstruction()
}
companion object {
internal const val Worker = "Worker"
internal const val Settler = "Settler"
}
} // for json parsing, we need to have a default constructor

View file

@ -1,68 +0,0 @@
package com.unciv.logic.city;
import com.badlogic.gdx.utils.Predicate;
import com.unciv.logic.map.TileInfo;
import com.unciv.models.linq.Linq;
public class CityExpansionManager{
transient public CityInfo cityInfo;
public int cultureStored;
private int tilesClaimed;
private void addNewTileWithCulture(){
cultureStored -= getCultureToNextTile();
tilesClaimed++;
for (int i = 2; i <4 ; i++) {
Linq<TileInfo> tiles = cityInfo.civInfo.gameInfo.tileMap.getTilesInDistance(cityInfo.cityLocation,i);
tiles = tiles.where(new Predicate<TileInfo>() {
@Override
public boolean evaluate(TileInfo arg0) {
return arg0.owner == null;
}
});
if(tiles.size()==0) continue;
TileInfo TileChosen=null;
double TileChosenRank=0;
for(TileInfo tile : tiles){
double rank = cityInfo.rankTile(tile);
if(rank>TileChosenRank){
TileChosenRank = rank;
TileChosen = tile;
}
}
if(TileChosen==null) // We can't add any more tiles to this city!
return;
TileChosen.owner = cityInfo.civInfo.civName;
return;
}
}
public int getCultureToNextTile(){
// This one has conflicting sources -
// http://civilization.wikia.com/wiki/Mathematics_of_Civilization_V says it's 20+(10(t-1))^1.1
// https://www.reddit.com/r/civ/comments/58rxkk/how_in_gods_name_do_borders_expand_in_civ_vi/ has it
// (per game XML files) at 6*(t+0.4813)^1.3
// The second seems to be more based, so I'll go with that
double a = 6*Math.pow(tilesClaimed+1.4813,1.3);
if(cityInfo.civInfo.getBuildingUniques().contains("NewTileCostReduction")) a *= 0.75; //Speciality of Angkor Wat
if(cityInfo.civInfo.policies.isAdopted("Tradition")) a *= 0.75;
return (int)Math.round(a);
}
public void nextTurn(float culture) {
cultureStored+=culture;
if(cultureStored>=getCultureToNextTile()){
addNewTileWithCulture();
cityInfo.civInfo.gameInfo.addNotification(cityInfo.name+" has expanded its borders!",cityInfo.cityLocation);
}
}
public int getGoldCostOfTile(TileInfo tileInfo){
//int distanceFromCenter =
return 50;
}
}

View file

@ -0,0 +1,46 @@
package com.unciv.logic.city
class CityExpansionManager {
@Transient
lateinit var cityInfo: CityInfo
var cultureStored: Int = 0
private var tilesClaimed: Int = 0
// This one has conflicting sources -
// http://civilization.wikia.com/wiki/Mathematics_of_Civilization_V says it's 20+(10(t-1))^1.1
// https://www.reddit.com/r/civ/comments/58rxkk/how_in_gods_name_do_borders_expand_in_civ_vi/ has it
// (per game XML files) at 6*(t+0.4813)^1.3
// The second seems to be more based, so I'll go with that
//Speciality of Angkor Wat
val cultureToNextTile: Int
get() {
var cultureToNextTile = 6 * Math.pow(tilesClaimed + 1.4813, 1.3)
if (cityInfo.civInfo.buildingUniques.contains("NewTileCostReduction")) cultureToNextTile *= 0.75
if (cityInfo.civInfo.policies.isAdopted("Tradition")) cultureToNextTile *= 0.75
return Math.round(cultureToNextTile).toInt()
}
private fun addNewTileWithCulture() {
cultureStored -= cultureToNextTile
for (i in 2..3) {
val tiles = cityInfo.civInfo.gameInfo.tileMap.getTilesInDistance(cityInfo.cityLocation, i).where { it.owner == null }
if (tiles.size == 0) continue
val chosenTile = tiles.maxBy { cityInfo.rankTile(it) }
chosenTile!!.owner = cityInfo.civInfo.civName
tilesClaimed++
return
}
}
fun nextTurn(culture: Float) {
cultureStored += culture.toInt()
if (cultureStored >= cultureToNextTile) {
addNewTileWithCulture()
cityInfo.civInfo.gameInfo.addNotification(cityInfo.name + " has expanded its borders!", cityInfo.cityLocation)
}
}
}

View file

@ -1,158 +0,0 @@
package com.unciv.logic.city;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Predicate;
import com.unciv.logic.civilization.CivilizationInfo;
import com.unciv.logic.map.RoadStatus;
import com.unciv.logic.map.TileInfo;
import com.unciv.logic.map.TileMap;
import com.unciv.models.linq.Linq;
import com.unciv.models.linq.LinqCounter;
import com.unciv.models.gamebasics.Building;
import com.unciv.models.gamebasics.GameBasics;
import com.unciv.models.gamebasics.TileResource;
import com.unciv.models.stats.FullStats;
public class CityInfo {
public transient CivilizationInfo civInfo;
public Vector2 cityLocation;
public String name;
public PopulationManager population = new PopulationManager();
public CityConstructions cityConstructions = new CityConstructions();
public CityExpansionManager expansion = new CityExpansionManager();
public CityStats cityStats = new CityStats();
TileMap getTileMap(){return civInfo.gameInfo.tileMap; }
public TileInfo getTile(){return getTileMap().get(cityLocation);}
public Linq<TileInfo> getTilesInRange(){
return getTileMap().getTilesInDistance(cityLocation,3).where(new Predicate<TileInfo>() {
@Override
public boolean evaluate(TileInfo arg0) {
return civInfo.civName.equals(arg0.owner);
}
});
}
private String[] CityNames = new String[]{
"New Bark","Cherrygrove","Violet","Azalea","Goldenrod","Ecruteak","Olivine","Cianwood","Mahogany","Blackthorn",
"Pallet","Viridian","Pewter","Cerulean","Vermillion","Lavender","Celadon","Fuchsia","Saffron","Cinnibar"};
public CityInfo(){
cityLocation = Vector2.Zero;
} // for json parsing, we need to have a default constructor
public CityInfo(CivilizationInfo civInfo, Vector2 cityLocation) {
this.civInfo =civInfo;
setTransients();
name = CityNames[civInfo.cities.size()];
this.cityLocation = cityLocation;
civInfo.cities.add(this);
civInfo.gameInfo.addNotification(name+" has been founded!",cityLocation);
if(civInfo.policies.isAdopted("Legalism") && civInfo.cities.size() <= 4) cityConstructions.addCultureBuilding();
if(civInfo.cities.size()==1) {
cityConstructions.builtBuildings.add("Palace");
cityConstructions.currentConstruction = "Worker"; // Default for first city only!
}
for(TileInfo tileInfo : civInfo.gameInfo.tileMap.getTilesInDistance(cityLocation,1)) {
tileInfo.owner = civInfo.civName;
}
TileInfo tile = getTile();
tile.workingCity = this.name;
tile.roadStatus = RoadStatus.Railroad;
if(new Linq<String>("Forest","Jungle","Marsh").contains(tile.terrainFeature))
tile.terrainFeature=null;
population.autoAssignWorker();
cityStats.update();
}
public void setTransients(){
population.cityInfo = this;
expansion.cityInfo = this;
cityStats.cityInfo = this;
cityConstructions.cityInfo=this;
}
public LinqCounter<TileResource> getCityResources(){
LinqCounter<TileResource> cityResources = new LinqCounter<TileResource>();
for (TileInfo tileInfo : getTilesInRange()) {
TileResource resource = tileInfo.getTileResource();
if (resource != null && (resource.improvement.equals(tileInfo.improvement) || tileInfo.isCityCenter()))
cityResources.add(resource,1);
}
// Remove resources required by buildings
for(Building building : cityConstructions.getBuiltBuildings()){
if(building.requiredResource!=null){
TileResource resource = GameBasics.TileResources.get(building.requiredResource);
cityResources.add(resource,-1);
}
}
return cityResources;
}
public void nextTurn() {
FullStats stats = cityStats.currentCityStats;
if (cityConstructions.currentConstruction.equals(CityConstructions.Settler) && stats.food > 0) {
stats.production += stats.food;
stats.food = 0;
}
population.nextTurn(stats.food);
cityConstructions.nextTurn(stats);
expansion.nextTurn(stats.culture);
}
double rankTile(TileInfo tile){
FullStats stats = tile.getTileStats(this,civInfo);
double rank=0;
if(stats.food <= 2) rank+=stats.food;
else rank += 2 + (stats.food -2)/2; // 1 point for each food up to 2, from there on half a point
rank+=stats.gold /2;
rank+=stats.production;
rank+=stats.science;
rank+=stats.culture;
if(tile.improvement == null) rank+=0.5; // improvement potential!
if(tile.resource!=null) rank+=1;
return rank;
}
public Linq<String> getBuildingUniques(){
return cityConstructions.getBuiltBuildings().select(new Linq.Func<Building, String>() {
@Override
public String GetBy(Building arg0) {
return arg0.unique;
}
}).where(new Predicate<String>() {
@Override
public boolean evaluate(String arg0) {
return arg0!=null;
}
});
}
public FullStats getGreatPersonPoints(){
FullStats greatPersonPoints = population.getSpecialists().times(3);
for(Building building : cityConstructions.getBuiltBuildings())
if(building.greatPersonPoints!=null)
greatPersonPoints.add(building.greatPersonPoints);
if(civInfo.getBuildingUniques().contains("GreatPersonGenerationIncrease"))
greatPersonPoints = greatPersonPoints.times(1.33f);
if(civInfo.policies.isAdopted("Entrepreneurship"))
greatPersonPoints.gold*=1.25;
if(civInfo.policies.isAdopted("Freedom"))
greatPersonPoints = greatPersonPoints.times(1.25f);
return greatPersonPoints;
}
}

View file

@ -0,0 +1,138 @@
package com.unciv.logic.city
import com.badlogic.gdx.math.Vector2
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.map.RoadStatus
import com.unciv.logic.map.TileInfo
import com.unciv.logic.map.TileMap
import com.unciv.models.linq.Linq
import com.unciv.models.linq.LinqCounter
import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.gamebasics.TileResource
import com.unciv.models.stats.Stats
class CityInfo {
@Transient
lateinit var civInfo: CivilizationInfo
var cityLocation: Vector2 = Vector2.Zero
var name: String = ""
var population = PopulationManager()
var cityConstructions = CityConstructions()
var expansion = CityExpansionManager()
var cityStats = CityStats()
internal val tileMap: TileMap
get() = civInfo.gameInfo.tileMap
val tile: TileInfo
get() = tileMap[cityLocation]
val tilesInRange: Linq<TileInfo>
get() = tileMap.getTilesInDistance(cityLocation, 3).where { civInfo.civName == it.owner }
private val CityNames = arrayOf("New Bark", "Cherrygrove", "Violet", "Azalea", "Goldenrod", "Ecruteak", "Olivine", "Cianwood", "Mahogany", "Blackthorn", "Pallet", "Viridian", "Pewter", "Cerulean", "Vermillion", "Lavender", "Celadon", "Fuchsia", "Saffron", "Cinnibar")
// Remove resources required by buildings
fun getCityResources(): LinqCounter<TileResource> {
val cityResources = LinqCounter<TileResource>()
for (tileInfo in tilesInRange.filter { it.resource != null }) {
val resource = tileInfo.tileResource
if (resource.improvement == tileInfo.improvement || tileInfo.isCityCenter)
cityResources.add(resource, 1)
}
for (building in cityConstructions.getBuiltBuildings().filter { it.requiredResource != null }) {
val resource = GameBasics.TileResources[building.requiredResource]
cityResources.add(resource, -1)
}
return cityResources
}
val buildingUniques: Linq<String>
get() = cityConstructions.getBuiltBuildings().where { it.unique!=null }.select { it.unique }
val greatPersonPoints: Stats
get() {
var greatPersonPoints = population.specialists.times(3f)
for (building in cityConstructions.getBuiltBuildings())
if (building.greatPersonPoints != null)
greatPersonPoints.add(building.greatPersonPoints!!)
if (civInfo.buildingUniques.contains("GreatPersonGenerationIncrease"))
greatPersonPoints = greatPersonPoints.times(1.33f)
if (civInfo.policies.isAdopted("Entrepreneurship"))
greatPersonPoints.gold *= 1.25f
if (civInfo.policies.isAdopted("Freedom"))
greatPersonPoints = greatPersonPoints.times(1.25f)
return greatPersonPoints
}
constructor() // for json parsing, we need to have a default constructor
constructor(civInfo: CivilizationInfo, cityLocation: Vector2) {
this.civInfo = civInfo
setTransients()
name = CityNames[civInfo.cities.size]
this.cityLocation = cityLocation
civInfo.cities.add(this)
civInfo.gameInfo.addNotification(name + " has been founded!", cityLocation)
if (civInfo.policies.isAdopted("Legalism") && civInfo.cities.size <= 4) cityConstructions.addCultureBuilding()
if (civInfo.cities.size == 1) {
cityConstructions.builtBuildings.add("Palace")
cityConstructions.currentConstruction = "Worker" // Default for first city only!
}
for (tileInfo in civInfo.gameInfo.tileMap.getTilesInDistance(cityLocation, 1)) {
tileInfo.owner = civInfo.civName
}
val tile = tile
tile.workingCity = this.name
tile.roadStatus = RoadStatus.Railroad
if (Linq("Forest", "Jungle", "Marsh").contains(tile.terrainFeature))
tile.terrainFeature = null
population.autoAssignWorker()
cityStats.update()
}
fun setTransients() {
population.cityInfo = this
expansion.cityInfo = this
cityStats.cityInfo = this
cityConstructions.cityInfo = this
}
fun nextTurn() {
val stats = cityStats.currentCityStats
if (cityConstructions.currentConstruction == CityConstructions.Settler && stats.food > 0) {
stats.production += stats.food
stats.food = 0f
}
population.nextTurn(stats.food)
cityConstructions.nextTurn(stats)
expansion.nextTurn(stats.culture)
}
internal fun rankTile(tile: TileInfo): Float {
val stats = tile.getTileStats(this, civInfo)
var rank = 0.0f
if (stats.food <= 2) rank += stats.food
else rank += (2 + (stats.food - 2) / 2f) // 1 point for each food up to 2, from there on half a point
rank += (stats.gold / 2)
rank += stats.production
rank += stats.science
rank += stats.culture
if (tile.improvement == null) rank += 0.5f // improvement potential!
if (tile.resource != null) rank += 1.0f
return rank
}
}

View file

@ -1,263 +0,0 @@
package com.unciv.logic.city;
import com.badlogic.gdx.utils.Predicate;
import com.unciv.logic.civilization.CivilizationInfo;
import com.unciv.logic.map.RoadStatus;
import com.unciv.logic.map.TileInfo;
import com.unciv.models.gamebasics.Building;
import com.unciv.models.gamebasics.GameBasics;
import com.unciv.models.linq.Linq;
import com.unciv.models.stats.FullStats;
/**
* Created by LENOVO on 1/13/2018.
*/
public class CityStats{
public transient FullStats currentCityStats; // This is so we won't have to calculate this multiple times - takes a lot of time, especially on phones
public transient CityInfo cityInfo;
private FullStats getStatsFromTiles(){
FullStats stats = new FullStats();
for (TileInfo cell : cityInfo.getTilesInRange())
if (cityInfo.name.equals(cell.workingCity))
stats.add(cell.getTileStats(cityInfo,cityInfo.civInfo));
return stats;
}
private FullStats getStatsFromSpecialists(FullStats specialists, Linq<String> policies){
FullStats stats = new FullStats();
// Specialists
stats.culture+=specialists.culture*3;
stats.production+=specialists.production*2;
stats.science+=specialists.science*3;
stats.gold+=specialists.gold*2;
int numOfSpecialists = cityInfo.population.getNumberOfSpecialists();
if(policies.contains("Commerce Complete")) stats.gold+=numOfSpecialists;
if(policies.contains(("Secularism"))) stats.science+=numOfSpecialists*2;
return stats;
}
private FullStats getStatsFromTradeRoute(){
FullStats stats = new FullStats();
if(!isCapital() && isConnectedToCapital(RoadStatus.Road)) {
CivilizationInfo civInfo = cityInfo.civInfo;
// Calculated by http://civilization.wikia.com/wiki/Trade_route_(Civ5)
double goldFromTradeRoute = civInfo.getCapital().population.population * 0.15
+ cityInfo.population.population * 1.1 - 1;
if(civInfo.policies.isAdopted("Trade Unions")) goldFromTradeRoute+=2;
if(civInfo.getBuildingUniques().contains("TradeRouteGoldIncrease")) goldFromTradeRoute*=1.25; // Machu Pichu speciality
stats.gold += goldFromTradeRoute;
}
return stats;
}
private FullStats getStatsFromPolicies(Linq<String> adoptedPolicies){
FullStats stats = new FullStats();
if(adoptedPolicies.contains("Tradition") && isCapital())
stats.culture+=3;
if(adoptedPolicies.contains("Landed Elite") && isCapital())
stats.food+=2;
if(adoptedPolicies.contains("Tradition Complete"))
stats.food+=2;
if(adoptedPolicies.contains("Monarchy") && isCapital())
stats.gold+=cityInfo.population.population/2;
if(adoptedPolicies.contains("Liberty"))
stats.culture+=1;
if(adoptedPolicies.contains("Republic"))
stats.production+=1;
if(adoptedPolicies.contains("Universal Suffrage"))
stats.production+=cityInfo.population.population/5;
if(adoptedPolicies.contains("Free Speech"))
stats.culture+=cityInfo.population.population/2;
return stats;
}
private FullStats getStatsFromProduction(){
FullStats stats = new FullStats();
if("Gold".equals(cityInfo.cityConstructions.currentConstruction)) stats.gold+=stats.production/4;
if("Science".equals(cityInfo.cityConstructions.currentConstruction)) {
float scienceProduced=stats.production/4;
if (cityInfo.civInfo.getBuildingUniques().contains("ScienceConversionIncrease"))
scienceProduced*=1.33;
if(cityInfo.civInfo.policies.isAdopted("Rationalism")) scienceProduced*=1.33;
stats.science += scienceProduced;
}
return stats;
}
private FullStats getStatPercentBonusesFromRailroad(){
FullStats stats = new FullStats();
if( cityInfo.civInfo.tech.isResearched ("Combustion") &&
(isCapital() || isConnectedToCapital(RoadStatus.Railroad)))
stats.production += 25;
return stats;
}
private FullStats getStatPercentBonusesFromGoldenAge(boolean isGoldenAge){
FullStats stats = new FullStats();
if(isGoldenAge)
stats.production+=20;
return stats;
}
private FullStats getStatPercentBonusesFromPolicies(Linq<String> policies, CityConstructions cityConstructions){
FullStats stats = new FullStats();
if(policies.contains("Collective Rule") && isCapital()
&& "Settler".equals(cityConstructions.currentConstruction))
stats.production+=50;
if(policies.contains("Republic") && cityConstructions.getCurrentConstruction() instanceof Building)
stats.production+=5;
if(policies.contains("Reformation") && cityConstructions.builtBuildings.any(new Predicate<String>() {
@Override
public boolean evaluate(String arg0) {
return GameBasics.Buildings.get(arg0).isWonder;
}
}))
stats.culture+=33;
if(policies.contains("Commerce") && isCapital())
stats.gold+=25;
if(policies.contains("Sovereignty") && cityInfo.civInfo.getHappinessForNextTurn() >= 0)
stats.science+=15;
if(policies.contains("Aristocracy")
&& cityConstructions.getCurrentConstruction() instanceof Building
&& ((Building)cityConstructions.getCurrentConstruction()).isWonder)
stats.production+=15;
return stats;
}
private FullStats getStatPercentBonusesFromMarble() {
FullStats stats = new FullStats();
IConstruction construction = cityInfo.cityConstructions.getCurrentConstruction();
if (construction instanceof Building
&& ((Building) construction).isWonder
&& cityInfo.civInfo.getCivResources().containsKey(GameBasics.TileResources.get("Marble")))
stats.production += 15;
return stats;
}
private FullStats getStatPercentBonusesFromComputers() {
FullStats stats = new FullStats();
if (cityInfo.civInfo.tech.isResearched("Computers")) {
stats.production += 10;
stats.science += 10;
}
return stats;
}
private float getGrowthBonusFromPolicies(){
float bonus = 0;
if(cityInfo.civInfo.policies.isAdopted("Landed Elite") && isCapital())
bonus+=0.1;
if(cityInfo.civInfo.policies.isAdopted("Tradition Complete"))
bonus+=0.15;
return bonus;
}
public void update() {
CivilizationInfo civInfo = cityInfo.civInfo;
FullStats stats = new FullStats();
stats.science += cityInfo.population.population;
stats.production += cityInfo.population.getFreePopulation();
stats.add(getStatsFromTiles());
stats.add(getStatsFromSpecialists(cityInfo.population.getSpecialists(), civInfo.policies.getAdoptedPolicies()));
stats.add(getStatsFromTradeRoute());
stats.add(cityInfo.cityConstructions.getStats());
stats.add(getStatsFromPolicies(civInfo.policies.getAdoptedPolicies()));
FullStats statPercentBonuses = cityInfo.cityConstructions.getStatPercentBonuses();
statPercentBonuses.add(getStatPercentBonusesFromGoldenAge(cityInfo.civInfo.goldenAges.isGoldenAge()));
statPercentBonuses.add(getStatPercentBonusesFromPolicies(civInfo.policies.getAdoptedPolicies(), cityInfo.cityConstructions));
statPercentBonuses.add(getStatPercentBonusesFromRailroad());
statPercentBonuses.add(getStatPercentBonusesFromMarble());
statPercentBonuses.add(getStatPercentBonusesFromComputers());
stats.production*=1+statPercentBonuses.production/100; // So they get bonuses for production and gold/science
stats.add(getStatsFromProduction());
stats.gold*=1+statPercentBonuses.gold/100;
stats.science*=1+statPercentBonuses.science/100;
stats.culture*=1+statPercentBonuses.culture/100;
boolean isUnhappy = civInfo.getHappinessForNextTurn() < 0;
if (!isUnhappy) stats.food*=1+statPercentBonuses.food/100; // Regular food bonus revoked when unhappy per https://forums.civfanatics.com/resources/complete-guide-to-happiness-vanilla.25584/
stats.food -= cityInfo.population.population * 2; // Food reduced after the bonus
if(civInfo.policies.isAdopted("Civil Society"))
stats.food+=cityInfo.population.getNumberOfSpecialists();
if(isUnhappy) stats.food /= 4; // Reduce excess food to 1/4 per the same
stats.food *= (1+getGrowthBonusFromPolicies());
stats.gold-= cityInfo.cityConstructions.getMaintainanceCosts(); // this is AFTER the bonus calculation!
this.currentCityStats = stats;
}
public float getCityHappiness(){ // needs to be a separate function because we need to know the global happiness state
CivilizationInfo civInfo = cityInfo.civInfo;
// in order to determine how much food is produced in a city!
float happiness = -3; // -3 happiness per city
float unhappinessFromCitizens = cityInfo.population.population;
if(civInfo.policies.isAdopted("Democracy"))
unhappinessFromCitizens -= cityInfo.population.getNumberOfSpecialists()*0.5f;
if(civInfo.getBuildingUniques().contains("CitizenUnhappinessDecreased"))
unhappinessFromCitizens*=0.9;
if(civInfo.policies.isAdopted("Aristocracy"))
unhappinessFromCitizens*=0.95;
happiness-=unhappinessFromCitizens;
if(civInfo.policies.isAdopted("Aristocracy"))
happiness+=cityInfo.population.population/10;
if(civInfo.policies.isAdopted("Monarchy") && isCapital())
happiness+=cityInfo.population.population/2;
if(civInfo.policies.isAdopted("Meritocracy") && isConnectedToCapital(RoadStatus.Road))
happiness+=1;
happiness+=(int) cityInfo.cityConstructions.getStats().happiness;
return happiness;
}
boolean isConnectedToCapital(RoadStatus roadType){
if(cityInfo.civInfo.getCapital()==null) return false;// first city!
TileInfo capitalTile = cityInfo.civInfo.getCapital().getTile();
Linq<TileInfo> tilesReached = new Linq<TileInfo>();
Linq<TileInfo> tilesToCheck = new Linq<TileInfo>();
tilesToCheck.add(cityInfo.getTile());
while(!tilesToCheck.isEmpty()){
Linq<TileInfo> newTiles = new Linq<TileInfo>();
for(TileInfo tile : tilesToCheck)
for (TileInfo maybeNewTile : cityInfo.getTileMap().getTilesInDistance(tile.position,1))
if(!tilesReached.contains(maybeNewTile) && !tilesToCheck.contains(maybeNewTile) && !newTiles.contains(maybeNewTile)
&& (roadType != RoadStatus.Road || maybeNewTile.roadStatus != RoadStatus.None)
&& (roadType!=RoadStatus.Railroad || maybeNewTile.roadStatus == roadType))
newTiles.add(maybeNewTile);
if(newTiles.contains(capitalTile)) return true;
tilesReached.addAll(tilesToCheck);
tilesToCheck = newTiles;
}
return false;
}
private boolean isCapital(){ return cityInfo.civInfo.getCapital() == cityInfo; }
}

View file

@ -0,0 +1,257 @@
package com.unciv.logic.city
import com.unciv.logic.map.RoadStatus
import com.unciv.logic.map.TileInfo
import com.unciv.models.gamebasics.Building
import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.linq.Linq
import com.unciv.models.stats.Stats
class CityStats {
@Transient @JvmField var currentCityStats: Stats = Stats() // This is so we won't have to calculate this multiple times - takes a lot of time, especially on phones
@Transient lateinit var cityInfo: CityInfo
private val statsFromTiles: Stats
get() {
val stats = Stats()
for (cell in cityInfo.tilesInRange.where { cityInfo.name == it.workingCity })
stats.add(cell.getTileStats(cityInfo, cityInfo.civInfo))
return stats
}
private
val statsFromTradeRoute: Stats
get() {
val stats = Stats()
if (!isCapital && isConnectedToCapital(RoadStatus.Road)) {
val civInfo = cityInfo.civInfo
var goldFromTradeRoute = civInfo.capital.population.population * 0.15 + cityInfo.population.population * 1.1 - 1 // Calculated by http://civilization.wikia.com/wiki/Trade_route_(Civ5)
if (civInfo.policies.isAdopted("Trade Unions")) goldFromTradeRoute += 2.0
if (civInfo.buildingUniques.contains("TradeRouteGoldIncrease")) goldFromTradeRoute *= 1.25 // Machu Pichu speciality
stats.gold += goldFromTradeRoute.toFloat()
}
return stats
}
private val statsFromProduction: Stats
get() {
val stats = Stats()
if ("Gold" == cityInfo.cityConstructions.currentConstruction) stats.gold += stats.production / 4
if ("Science" == cityInfo.cityConstructions.currentConstruction) {
var scienceProduced = stats.production / 4
if (cityInfo.civInfo.buildingUniques.contains("ScienceConversionIncrease")) scienceProduced *= 1.33f
if (cityInfo.civInfo.policies.isAdopted("Rationalism")) scienceProduced *= 1.33f
stats.science += scienceProduced
}
return stats
}
private val statPercentBonusesFromRailroad: Stats
get() {
val stats = Stats()
if (cityInfo.civInfo.tech.isResearched("Combustion") && (isCapital || isConnectedToCapital(RoadStatus.Railroad)))
stats.production += 25f
return stats
}
private val statPercentBonusesFromMarble: Stats
get() {
val stats = Stats()
val construction = cityInfo.cityConstructions.getCurrentConstruction()
if (construction is Building
&& construction.isWonder
&& cityInfo.civInfo.getCivResources().containsKey(GameBasics.TileResources["Marble"]))
stats.production += 15f
return stats
}
private val statPercentBonusesFromComputers: Stats
get() {
val stats = Stats()
if (cityInfo.civInfo.tech.isResearched("Computers")) {
stats.production += 10f
stats.science += 10f
}
return stats
}
private val growthBonusFromPolicies: Float
get() {
var bonus = 0f
if (cityInfo.civInfo.policies.isAdopted("Landed Elite") && isCapital)
bonus += 0.1f
if (cityInfo.civInfo.policies.isAdopted("Tradition Complete"))
bonus += 0.15f
return bonus
}
// needs to be a separate function because we need to know the global happiness state
// in order to determine how much food is produced in a city!
// -3 happiness per city
val cityHappiness: Float
get() {
val civInfo = cityInfo.civInfo
var happiness = -3f
var unhappinessFromCitizens = cityInfo.population.population.toFloat()
if (civInfo.policies.isAdopted("Democracy"))
unhappinessFromCitizens -= cityInfo.population.numberOfSpecialists * 0.5f
if (civInfo.buildingUniques.contains("CitizenUnhappinessDecreased"))
unhappinessFromCitizens *= 0.9f
if (civInfo.policies.isAdopted("Aristocracy"))
unhappinessFromCitizens *= 0.95f
happiness -= unhappinessFromCitizens
if (civInfo.policies.isAdopted("Aristocracy"))
happiness += (cityInfo.population.population / 10).toFloat()
if (civInfo.policies.isAdopted("Monarchy") && isCapital)
happiness += (cityInfo.population.population / 2).toFloat()
if (civInfo.policies.isAdopted("Meritocracy") && isConnectedToCapital(RoadStatus.Road))
happiness += 1f
happiness += cityInfo.cityConstructions.getStats().happiness.toInt().toFloat()
return happiness
}
private val isCapital: Boolean
get() = cityInfo.civInfo.capital === cityInfo
private fun getStatsFromSpecialists(specialists: Stats, policies: Linq<String>): Stats {
val stats = Stats()
// Specialists
stats.culture += specialists.culture * 3
stats.production += specialists.production * 2
stats.science += specialists.science * 3
stats.gold += specialists.gold * 2
val numOfSpecialists = cityInfo.population.numberOfSpecialists
if (policies.contains("Commerce Complete")) stats.gold += numOfSpecialists.toFloat()
if (policies.contains("Secularism")) stats.science += (numOfSpecialists * 2).toFloat()
return stats
}
private fun getStatsFromPolicies(adoptedPolicies: Linq<String>): Stats {
val stats = Stats()
if (adoptedPolicies.contains("Tradition") && isCapital)
stats.culture += 3f
if (adoptedPolicies.contains("Landed Elite") && isCapital)
stats.food += 2f
if (adoptedPolicies.contains("Tradition Complete"))
stats.food += 2f
if (adoptedPolicies.contains("Monarchy") && isCapital)
stats.gold += (cityInfo.population.population / 2).toFloat()
if (adoptedPolicies.contains("Liberty"))
stats.culture += 1f
if (adoptedPolicies.contains("Republic"))
stats.production += 1f
if (adoptedPolicies.contains("Universal Suffrage"))
stats.production += (cityInfo.population.population / 5).toFloat()
if (adoptedPolicies.contains("Free Speech"))
stats.culture += (cityInfo.population.population / 2).toFloat()
return stats
}
private fun getStatPercentBonusesFromGoldenAge(isGoldenAge: Boolean): Stats {
val stats = Stats()
if (isGoldenAge) stats.production += 20f
return stats
}
private fun getStatPercentBonusesFromPolicies(policies: Linq<String>, cityConstructions: CityConstructions): Stats {
val stats = Stats()
if (policies.contains("Collective Rule") && isCapital
&& "Settler" == cityConstructions.currentConstruction)
stats.production += 50f
if (policies.contains("Republic") && cityConstructions.getCurrentConstruction() is Building)
stats.production += 5f
if (policies.contains("Reformation") && cityConstructions.builtBuildings.any { GameBasics.Buildings[it]!!.isWonder })
stats.culture += 33f
if (policies.contains("Commerce") && isCapital)
stats.gold += 25f
if (policies.contains("Sovereignty") && cityInfo.civInfo.happiness >= 0)
stats.science += 15f
if (policies.contains("Aristocracy")
&& cityConstructions.getCurrentConstruction() is Building
&& (cityConstructions.getCurrentConstruction() as Building).isWonder)
stats.production += 15f
return stats
}
fun update() {
val civInfo = cityInfo.civInfo
val stats = Stats()
stats.science += cityInfo.population.population.toFloat()
stats.production += cityInfo.population.freePopulation.toFloat()
stats.add(statsFromTiles)
stats.add(getStatsFromSpecialists(cityInfo.population.specialists, civInfo.policies.adoptedPolicies))
stats.add(statsFromTradeRoute)
stats.add(cityInfo.cityConstructions.getStats())
stats.add(getStatsFromPolicies(civInfo.policies.adoptedPolicies))
val statPercentBonuses = cityInfo.cityConstructions.getStatPercentBonuses()
statPercentBonuses.add(getStatPercentBonusesFromGoldenAge(cityInfo.civInfo.goldenAges.isGoldenAge()))
statPercentBonuses.add(getStatPercentBonusesFromPolicies(civInfo.policies.adoptedPolicies, cityInfo.cityConstructions))
statPercentBonuses.add(statPercentBonusesFromRailroad)
statPercentBonuses.add(statPercentBonusesFromMarble)
statPercentBonuses.add(statPercentBonusesFromComputers)
stats.production *= 1 + statPercentBonuses.production / 100 // So they get bonuses for production and gold/science
stats.add(statsFromProduction)
stats.gold *= 1 + statPercentBonuses.gold / 100
stats.science *= 1 + statPercentBonuses.science / 100
stats.culture *= 1 + statPercentBonuses.culture / 100
val isUnhappy = civInfo.happiness < 0
if (!isUnhappy) stats.food *= 1 + statPercentBonuses.food / 100 // Regular food bonus revoked when unhappy per https://forums.civfanatics.com/resources/complete-guide-to-happiness-vanilla.25584/
stats.food -= (cityInfo.population.population * 2).toFloat() // Food reduced after the bonus
if (civInfo.policies.isAdopted("Civil Society"))
stats.food += cityInfo.population.numberOfSpecialists.toFloat()
if (isUnhappy) stats.food /= 4f // Reduce excess food to 1/4 per the same
stats.food *= 1 + growthBonusFromPolicies
stats.gold -= cityInfo.cityConstructions.getMaintenanceCosts().toFloat() // this is AFTER the bonus calculation!
this.currentCityStats = stats
}
private fun isConnectedToCapital(roadType: RoadStatus): Boolean {
if(cityInfo.civInfo.cities.count()<2) return false// first city!
val capitalTile = cityInfo.civInfo.capital.tile
val tilesReached = HashSet<TileInfo>()
var tilesToCheck : List<TileInfo> = Linq<TileInfo>(cityInfo.tile)
while (tilesToCheck.any()) {
val newTiles = tilesToCheck
.flatMap { cityInfo.tileMap.getTilesInDistance(it.position, 1) }.distinct()
.filter{ !tilesReached.contains(it) && !tilesToCheck.contains(it)
&& (roadType !== RoadStatus.Road || it.roadStatus !== RoadStatus.None)
&& (roadType !== RoadStatus.Railroad || it.roadStatus === roadType) }
if (newTiles.contains(capitalTile)) return true
tilesReached.addAll(tilesToCheck)
tilesToCheck = newTiles
}
return false
}
}

View file

@ -1,81 +0,0 @@
package com.unciv.logic.city;
import com.badlogic.gdx.utils.Predicate;
import com.unciv.logic.map.TileInfo;
import com.unciv.models.linq.LinqHashMap;
import com.unciv.models.stats.FullStats;
public class PopulationManager {
transient public CityInfo cityInfo;
public int population = 1;
public int foodStored = 0;
public LinqHashMap<String,FullStats> buildingsSpecialists = new LinqHashMap<String, FullStats>();
public FullStats getSpecialists(){
FullStats allSpecialists = new FullStats();
for(FullStats stats : buildingsSpecialists.values())
allSpecialists.add(stats);
return allSpecialists;
}
public int getNumberOfSpecialists(){
FullStats specialists = getSpecialists();
return (int) (specialists.science+specialists.production+specialists.culture+specialists.gold);
}
public int foodToNextPopulation()
{
// civ v math,civilization.wikia
return 15 + 6 * (population - 1) + (int)Math.floor(Math.pow(population - 1, 1.8f));
}
public int getFreePopulation() {
int workingPopulation = cityInfo.getTilesInRange().count(new Predicate<TileInfo>() {
@Override
public boolean evaluate(TileInfo arg0) {
return cityInfo.name.equals(arg0.workingCity);
}
})-1; // 1 is the city center
return population - workingPopulation - getNumberOfSpecialists();
}
public void nextTurn(float food) {
foodStored += food;
if (foodStored < 0) // starvation!
{
population--;
foodStored = 0;
cityInfo.civInfo.gameInfo.addNotification(cityInfo.name+" is starving!",cityInfo.cityLocation);
}
if (foodStored >= foodToNextPopulation()) // growth!
{
foodStored -= foodToNextPopulation();
if(cityInfo.getBuildingUniques().contains("FoodCarriesOver")) foodStored+=0.4f*foodToNextPopulation(); // Aqueduct special
population++;
autoAssignWorker();
cityInfo.civInfo.gameInfo.addNotification(cityInfo.name+" has grown!",cityInfo.cityLocation);
}
}
void autoAssignWorker() {
double maxValue = 0;
TileInfo toWork = null;
for (TileInfo tileInfo : cityInfo.getTilesInRange()) {
if (tileInfo.workingCity !=null) continue;
double value = cityInfo.rankTile(tileInfo);
if (value > maxValue) {
maxValue = value;
toWork = tileInfo;
}
}
if(toWork!=null) // This is when we've run out of tiles!
toWork.workingCity = cityInfo.name;
}
}

View file

@ -0,0 +1,72 @@
package com.unciv.logic.city
import com.unciv.logic.map.TileInfo
import com.unciv.models.linq.LinqHashMap
import com.unciv.models.stats.Stats
class PopulationManager {
@Transient
@JvmField var cityInfo: CityInfo? = null
@JvmField var population = 1
@JvmField var foodStored = 0
@JvmField var buildingsSpecialists = LinqHashMap<String, Stats>()
val specialists: Stats
get() {
val allSpecialists = Stats()
for (stats in buildingsSpecialists.values)
allSpecialists.add(stats)
return allSpecialists
}
val numberOfSpecialists: Int
get() {
val specialists = specialists
return (specialists.science + specialists.production + specialists.culture + specialists.gold).toInt()
}
// 1 is the city center
val freePopulation: Int
get() {
val workingPopulation = cityInfo!!.tilesInRange.count { cityInfo!!.name == it.workingCity } - 1
return population - workingPopulation - numberOfSpecialists
}
val foodToNextPopulation: Int
get() {
// civ v math,civilization.wikia
return 15 + 6 * (population - 1) + Math.floor(Math.pow((population - 1).toDouble(), 1.8)).toInt()
}
fun nextTurn(food: Float) {
foodStored += food.toInt()
if (foodStored < 0)
// starvation!
{
population--
foodStored = 0
cityInfo!!.civInfo.gameInfo.addNotification(cityInfo!!.name + " is starving!", cityInfo!!.cityLocation)
}
if (foodStored >= foodToNextPopulation)
// growth!
{
foodStored -= foodToNextPopulation
if (cityInfo!!.buildingUniques.contains("FoodCarriesOver")) foodStored += (0.4f * foodToNextPopulation).toInt() // Aqueduct special
population++
autoAssignWorker()
cityInfo!!.civInfo.gameInfo.addNotification(cityInfo!!.name + " has grown!", cityInfo!!.cityLocation)
}
}
internal fun autoAssignWorker() {
var toWork: TileInfo? = cityInfo!!.tilesInRange.where { it.workingCity==null }.maxBy { cityInfo!!.rankTile(it) }
if (toWork != null) // This is when we've run out of tiles!
toWork.workingCity = cityInfo!!.name
}
}

View file

@ -1,177 +0,0 @@
package com.unciv.logic.civilization;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Predicate;
import com.unciv.logic.city.CityInfo;
import com.unciv.logic.map.RoadStatus;
import com.unciv.logic.map.TileInfo;
import com.unciv.ui.GameInfo;
import com.unciv.models.linq.Linq;
import com.unciv.models.linq.LinqCounter;
import com.unciv.models.gamebasics.Building;
import com.unciv.models.gamebasics.GameBasics;
import com.unciv.models.gamebasics.ResourceType;
import com.unciv.models.gamebasics.TileResource;
import com.unciv.models.stats.CivStats;
import java.util.Collection;
public class CivilizationInfo {
public transient GameInfo gameInfo;
//public CivStats civStats = new CivStats();
public int gold = 0;
public String civName = "Babylon";
public TechManager tech = new TechManager();
public PolicyManager policies = new PolicyManager();
public GoldenAgeManager goldenAges = new GoldenAgeManager();
public GreatPersonManager greatPeople = new GreatPersonManager();
public ScienceVictoryManager scienceVictory = new ScienceVictoryManager();
public Linq<CityInfo> cities = new Linq<CityInfo>();
public CivilizationInfo(){}
public CivilizationInfo(String civName, Vector2 startingLocation, GameInfo gameInfo) {
this.civName = civName;
this.gameInfo = gameInfo;
this.placeUnitNearTile(startingLocation,"Settler");
this.placeUnitNearTile(startingLocation,"Scout");
}
public void setTransients(){
goldenAges.civInfo=this;
policies.civInfo=this;
tech.civInfo=this;
for (CityInfo cityInfo : cities) {
cityInfo.setTransients();
cityInfo.civInfo = this;
}
}
public int turnsToTech(String TechName) {
return (int) Math.ceil((float)(GameBasics.Technologies.get(TechName).cost - tech.researchOfTech(TechName))
/ getStatsForNextTurn().science);
}
public void addCity(Vector2 location){
CityInfo newCity = new CityInfo(this,location);
newCity.cityConstructions.chooseNextConstruction();
}
public CityInfo getCapital(){
return cities.first(new Predicate<CityInfo>() {
@Override
public boolean evaluate(CityInfo arg0) {
return arg0.cityConstructions.isBuilt("Palace");
}
});
}
public void nextTurn()
{
CivStats nextTurnStats = getStatsForNextTurn();
policies.nextTurn(nextTurnStats.culture);
gold+=nextTurnStats.gold;
int happiness = getHappinessForNextTurn();
if(cities.size() > 0) tech.nextTurn((int)nextTurnStats.science);
for (CityInfo city : cities){
city.nextTurn();
greatPeople.addGreatPersonPoints(city.getGreatPersonPoints());
}
String greatPerson = greatPeople.getNewGreatPerson();
if(greatPerson!=null) {
}
goldenAges.nextTurn(happiness);
}
public void addGreatPerson(String greatPerson){
CityInfo randomCity = cities.getRandom();
placeUnitNearTile(cities.getRandom().cityLocation, greatPerson);
gameInfo.addNotification("A " + greatPerson + " has been born!", randomCity.cityLocation);
}
public CivStats getStatsForNextTurn() {
CivStats statsForTurn = new CivStats();
for (CityInfo city : cities) {
statsForTurn.add(city.cityStats.currentCityStats);
}
statsForTurn.happiness=0;
int transportationUpkeep = 0;
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;
}
if(policies.isAdopted("Trade Unions")) transportationUpkeep *= 2/3f;
statsForTurn.gold -=transportationUpkeep;
if(policies.isAdopted("Mandate Of Heaven"))
statsForTurn.culture+=getHappinessForNextTurn()/2;
if(statsForTurn.gold<0) statsForTurn.science+=statsForTurn.gold; // negative gold hurts science
return statsForTurn;
}
public int getHappinessForNextTurn(){
int happiness = 15; // base happiness
int happinessPerUniqueLuxury = 5;
if(policies.isAdopted("Protectionism")) happinessPerUniqueLuxury+=1;
happiness += new Linq<TileResource>(getCivResources().keySet()).count(new Predicate<TileResource>() {
@Override
public boolean evaluate(TileResource arg0) {
return arg0.resourceType == ResourceType.Luxury;
}
}) * happinessPerUniqueLuxury;
for (CityInfo city : cities) {
happiness += city.cityStats.getCityHappiness();
}
if(getBuildingUniques().contains("HappinessPerSocialPolicy"))
happiness+=policies.getAdoptedPolicies().count(new Predicate<String>() {
@Override
public boolean evaluate(String arg0) {
return !arg0.endsWith("Complete");
}
});
return happiness;
}
public LinqCounter<TileResource> getCivResources(){
LinqCounter<TileResource> civResources = new LinqCounter<TileResource>();
for (CityInfo city : cities) civResources.add(city.getCityResources());
return civResources;
}
public Linq<String> getBuildingUniques(){
return cities.selectMany(new Linq.Func<CityInfo, Collection<? extends String>>() {
@Override
public Collection<? extends String> GetBy(CityInfo arg0) {
return arg0.cityConstructions.getBuiltBuildings().select(new Linq.Func<Building, String>() {
@Override
public String GetBy(Building arg0) {
return arg0.unique;
}
});
}
}).unique();
}
public void placeUnitNearTile(Vector2 location, String unitName){
gameInfo.tileMap.placeUnitNearTile(location,unitName,this);
}
}

View file

@ -0,0 +1,147 @@
package com.unciv.logic.civilization
import com.badlogic.gdx.math.Vector2
import com.unciv.logic.city.CityInfo
import com.unciv.logic.map.RoadStatus
import com.unciv.logic.GameInfo
import com.unciv.models.linq.Linq
import com.unciv.models.linq.LinqCounter
import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.gamebasics.ResourceType
import com.unciv.models.gamebasics.TileResource
import com.unciv.models.stats.Stats
class CivilizationInfo {
@Transient
var gameInfo: GameInfo = GameInfo()
var gold = 0
var happiness = 15
var civName = "Babylon"
var tech = TechManager()
var policies = PolicyManager()
var goldenAges = GoldenAgeManager()
private var greatPeople = GreatPersonManager()
var scienceVictory = ScienceVictoryManager()
var cities = Linq<CityInfo>()
val capital: CityInfo
get() = cities.first { it.cityConstructions.isBuilt("Palace") }
// negative gold hurts science
fun getStatsForNextTurn(): Stats {
val statsForTurn = Stats()
for (city in cities) statsForTurn.add(city.cityStats.currentCityStats)
statsForTurn.happiness = getHappinessForNextTurn().toFloat()
val transportationUpkeep = getTransportationUpkeep()
statsForTurn.gold -= transportationUpkeep.toFloat()
if (policies.isAdopted("Mandate Of Heaven"))
statsForTurn.culture += statsForTurn.happiness / 2
if (statsForTurn.gold < 0) statsForTurn.science += statsForTurn.gold
return statsForTurn
}
private fun getTransportationUpkeep(): Int {
var transportationUpkeep = 0
for (it in gameInfo.tileMap.values.filterNot { it.isCityCenter }) {
when(it.roadStatus) {
RoadStatus.Road -> transportationUpkeep += 1
RoadStatus.Railroad -> transportationUpkeep += 2
}
}
if (policies.isAdopted("Trade Unions")) transportationUpkeep *= (2 / 3f).toInt()
return transportationUpkeep
}
// base happiness
private fun getHappinessForNextTurn(): Int {
var happiness = 15
var happinessPerUniqueLuxury = 5
if (policies.isAdopted("Protectionism")) happinessPerUniqueLuxury += 1
happiness += getCivResources().keys
.count { it.resourceType === ResourceType.Luxury } * happinessPerUniqueLuxury
happiness += cities.sumBy { it.cityStats.cityHappiness.toInt() }
if (buildingUniques.contains("HappinessPerSocialPolicy"))
happiness += policies.getAdoptedPolicies().count { !it.endsWith("Complete") }
return happiness
}
fun getCivResources(): LinqCounter<TileResource> {
val civResources = LinqCounter<TileResource>()
for (city in cities) civResources.add(city.getCityResources())
return civResources
}
val buildingUniques: Linq<String>
get() = cities.selectMany { it.cityConstructions.getBuiltBuildings().select { it.unique }.filterNotNull() }.unique()
constructor()
constructor(civName: String, startingLocation: Vector2, gameInfo: GameInfo) {
this.civName = civName
this.gameInfo = gameInfo
this.placeUnitNearTile(startingLocation, "Settler")
this.placeUnitNearTile(startingLocation, "Scout")
}
fun setTransients() {
goldenAges.civInfo = this
policies.civInfo = this
tech.civInfo = this
for (cityInfo in cities) {
cityInfo.setTransients()
cityInfo.civInfo = this
}
}
fun turnsToTech(TechName: String): Int {
return Math.ceil(((GameBasics.Technologies[TechName]!!.cost - tech.researchOfTech(TechName))
/ getStatsForNextTurn().science).toDouble()).toInt()
}
fun addCity(location: Vector2) {
val newCity = CityInfo(this, location)
newCity.cityConstructions.chooseNextConstruction()
}
fun nextTurn() {
val nextTurnStats = getStatsForNextTurn()
happiness = nextTurnStats.happiness.toInt()
policies.nextTurn(nextTurnStats.culture.toInt())
gold += nextTurnStats.gold.toInt()
if (cities.size > 0) tech.nextTurn(nextTurnStats.science.toInt())
for (city in cities) {
city.nextTurn()
greatPeople.addGreatPersonPoints(city.greatPersonPoints)
}
val greatPerson = greatPeople.getNewGreatPerson()
if (greatPerson != null) {
addGreatPerson(greatPerson)
}
goldenAges.nextTurn(happiness)
}
fun addGreatPerson(greatPerson: String) {
val randomCity = cities.random
placeUnitNearTile(cities.random.cityLocation, greatPerson)
gameInfo.addNotification("A $greatPerson has been born!", randomCity!!.cityLocation)
}
fun placeUnitNearTile(location: Vector2, unitName: String) {
gameInfo.tileMap.placeUnitNearTile(location, unitName, this)
}
}

View file

@ -1,35 +0,0 @@
package com.unciv.logic.civilization;
public class GoldenAgeManager{
public transient CivilizationInfo civInfo;
public int storedHappiness=0;
public int numberOfGoldenAges=0;
public int turnsLeftForCurrentGoldenAge=0;
public boolean isGoldenAge(){return turnsLeftForCurrentGoldenAge>0;}
public int happinessRequiredForNextGoldenAge(){
return (int) ((500+numberOfGoldenAges*250)*(1+civInfo.cities.size()/100.0)); //https://forums.civfanatics.com/resources/complete-guide-to-happiness-vanilla.25584/
}
public void enterGoldenAge(){
int turnsToGoldenAge = 10;
if(civInfo.getBuildingUniques().contains("GoldenAgeLengthIncrease")) turnsToGoldenAge*=1.5;
if(civInfo.policies.isAdopted("Freedom Complete")) turnsToGoldenAge*=1.5;
turnsLeftForCurrentGoldenAge += turnsToGoldenAge;
civInfo.gameInfo.addNotification("You have entered a golden age!",null);
}
public void nextTurn(int happiness) {
if(happiness>0&& !isGoldenAge()) storedHappiness+=happiness;
if(isGoldenAge()) turnsLeftForCurrentGoldenAge--;
else if(storedHappiness > happinessRequiredForNextGoldenAge()){
storedHappiness -= happinessRequiredForNextGoldenAge();
enterGoldenAge();
numberOfGoldenAges++;
}
}
}

View file

@ -0,0 +1,36 @@
package com.unciv.logic.civilization
class GoldenAgeManager {
@Transient
lateinit var civInfo: CivilizationInfo
var storedHappiness = 0
private var numberOfGoldenAges = 0
var turnsLeftForCurrentGoldenAge = 0
fun isGoldenAge(): Boolean = turnsLeftForCurrentGoldenAge > 0
fun happinessRequiredForNextGoldenAge(): Int {
return ((500 + numberOfGoldenAges * 250) * (1 + civInfo.cities.size / 100.0)).toInt() //https://forums.civfanatics.com/resources/complete-guide-to-happiness-vanilla.25584/
}
fun enterGoldenAge() {
var turnsToGoldenAge = 10.0
if (civInfo.buildingUniques.contains("GoldenAgeLengthIncrease")) turnsToGoldenAge *= 1.5
if (civInfo.policies.isAdopted("Freedom Complete")) turnsToGoldenAge *= 1.5
turnsLeftForCurrentGoldenAge += turnsToGoldenAge.toInt()
civInfo.gameInfo.addNotification("You have entered a golden age!", null)
}
fun nextTurn(happiness: Int) {
if (happiness > 0 && !isGoldenAge()) storedHappiness += happiness
if (isGoldenAge())
turnsLeftForCurrentGoldenAge--
else if (storedHappiness > happinessRequiredForNextGoldenAge()) {
storedHappiness -= happinessRequiredForNextGoldenAge()
enterGoldenAge()
numberOfGoldenAges++
}
}
}

View file

@ -1,37 +0,0 @@
package com.unciv.logic.civilization;
import com.unciv.logic.city.CityInfo;
import com.unciv.models.stats.FullStats;
public class GreatPersonManager{
private int pointsForNextGreatPerson=100;
private FullStats greatPersonPoints = new FullStats();
public void addGreatPersonPoints(FullStats greatPersonPoints){ greatPersonPoints.add(greatPersonPoints);}
public String getNewGreatPerson(){
if(greatPersonPoints.science>pointsForNextGreatPerson){
greatPersonPoints.science-=pointsForNextGreatPerson;
pointsForNextGreatPerson*=2;
return "Great Scientist";
}
if(greatPersonPoints.production>pointsForNextGreatPerson){
greatPersonPoints.production-=pointsForNextGreatPerson;
pointsForNextGreatPerson*=2;
return "Great Engineer";
}
if(greatPersonPoints.culture>pointsForNextGreatPerson){
greatPersonPoints.culture-=pointsForNextGreatPerson;
pointsForNextGreatPerson*=2;
return "Great Artist";
}
if(greatPersonPoints.gold>pointsForNextGreatPerson){
greatPersonPoints.gold-=pointsForNextGreatPerson;
pointsForNextGreatPerson*=2;
return "Great Merchant";
}
return null;
}
}

View file

@ -0,0 +1,29 @@
package com.unciv.logic.civilization
import com.unciv.models.stats.Stats
class GreatPersonManager {
private var pointsForNextGreatPerson = 100
private val greatPersonPoints = Stats()
fun getNewGreatPerson(): String? {
var greatPerson: String? = null
when {
greatPersonPoints.science > pointsForNextGreatPerson -> greatPerson = "Great Scientist"
greatPersonPoints.production > pointsForNextGreatPerson -> greatPerson = "Great Engineer"
greatPersonPoints.culture > pointsForNextGreatPerson -> greatPerson = "Great Artist"
greatPersonPoints.gold > pointsForNextGreatPerson -> greatPerson = "Great Merchant"
}
if (greatPerson != null) {
greatPersonPoints.science -= pointsForNextGreatPerson.toFloat()
pointsForNextGreatPerson *= 2
}
return greatPerson
}
fun addGreatPersonPoints(greatPersonPoints: Stats) {
greatPersonPoints.add(greatPersonPoints)
}
}

View file

@ -6,7 +6,7 @@ class Notification {
@JvmField var text: String = ""
@JvmField var location: Vector2? = null
internal constructor() {}
internal constructor()
constructor(text: String, location: Vector2?) {
this.text = text

View file

@ -1,94 +0,0 @@
package com.unciv.logic.civilization;
import com.badlogic.gdx.utils.Predicate;
import com.unciv.logic.city.CityInfo;
import com.unciv.models.gamebasics.GameBasics;
import com.unciv.models.gamebasics.Policy;
import com.unciv.models.gamebasics.PolicyBranch;
import com.unciv.models.linq.Linq;
import com.unciv.ui.UnCivGame;
import com.unciv.ui.pickerscreens.GreatPersonPickerScreen;
public class PolicyManager {
public transient CivilizationInfo civInfo;
public int freePolicies=0;
public int storedCulture=0;
private Linq<String> adoptedPolicies = new Linq<String>();
public boolean shouldOpenPolicyPicker=false;
public Linq<String> getAdoptedPolicies(){return adoptedPolicies.clone();}
public boolean isAdopted(String policyName){return adoptedPolicies.contains(policyName);}
public int getCultureNeededForNextPolicy(){
// from https://forums.civfanatics.com/threads/the-number-crunching-thread.389702/
int basicPolicies = adoptedPolicies.count(new Predicate<String>() {
@Override
public boolean evaluate(String arg0) {
return !arg0.endsWith("Complete");
}
});
double baseCost = 25+ Math.pow(basicPolicies*6,1.7);
double cityModifier = 0.3*(civInfo.cities.size()-1);
if(isAdopted("Representation")) cityModifier *= 2/3f;
int cost = (int) Math.round(baseCost*(1+cityModifier));
if(isAdopted("Piety Complete")) cost*=0.9;
if(civInfo.getBuildingUniques().contains("PolicyCostReduction")) cost*=0.9;
return cost-cost%5; // round down to nearest 5
}
public boolean canAdoptPolicy(){
return storedCulture >= getCultureNeededForNextPolicy();
}
public void adopt(Policy policy){
adoptedPolicies.add(policy.name);
PolicyBranch branch = GameBasics.PolicyBranches.get(policy.branch);
int policiesCompleteInBranch = branch.policies.count(new Predicate<Policy>() {
@Override
public boolean evaluate(Policy arg0) {
return isAdopted(arg0.name);
}
});
if (policiesCompleteInBranch == branch.policies.size() - 1) { // All done apart from branch completion
adopt(branch.policies.get(branch.policies.size() - 1)); // add branch completion!
}
for(CityInfo cityInfo : civInfo.cities)
cityInfo.cityStats.update();
if (policy.name.equals("Collective Rule"))
civInfo.placeUnitNearTile(civInfo.getCapital().cityLocation, "Settler");
if (policy.name.equals("Citizenship"))
civInfo.placeUnitNearTile(civInfo.getCapital().cityLocation, "Worker");
if (policy.name.equals("Representation") || policy.name.equals("Reformation"))
civInfo.goldenAges.enterGoldenAge();
if (policy.name.equals("Scientific Revolution"))
civInfo.tech.freeTechs+=2;
if (policy.name.equals("Legalism")) {
for (CityInfo city : civInfo.cities.subList(0, Math.min(4, civInfo.cities.size())))
city.cityConstructions.addCultureBuilding();
}
if (policy.name.equals("Free Religion"))
freePolicies++;
if (policy.name.equals("Liberty Complete"))
UnCivGame.Current.setScreen(new GreatPersonPickerScreen());
}
public void nextTurn(float culture) {
boolean couldAdoptPolicyBefore = canAdoptPolicy();
storedCulture+=culture;
if(!couldAdoptPolicyBefore && canAdoptPolicy())
shouldOpenPolicyPicker=true;
}
}

View file

@ -0,0 +1,71 @@
package com.unciv.logic.civilization
import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.gamebasics.Policy
import com.unciv.models.linq.Linq
import com.unciv.ui.UnCivGame
import com.unciv.ui.pickerscreens.GreatPersonPickerScreen
class PolicyManager {
@Transient
lateinit var civInfo: CivilizationInfo
var freePolicies = 0
var storedCulture = 0
internal val adoptedPolicies = Linq<String>()
var shouldOpenPolicyPicker = false
// from https://forums.civfanatics.com/threads/the-number-crunching-thread.389702/
// round down to nearest 5
fun getCultureNeededForNextPolicy(): Int {
val basicPolicies = adoptedPolicies.count { !it.endsWith("Complete") }
var baseCost = 25 + Math.pow((basicPolicies * 6).toDouble(), 1.7)
var cityModifier = 0.3 * (civInfo.cities.size - 1)
if (isAdopted("Representation")) cityModifier *= (2 / 3f).toDouble()
if (isAdopted("Piety Complete")) baseCost *= 0.9
if (civInfo.buildingUniques.contains("PolicyCostReduction")) baseCost *= 0.9
val cost: Int = Math.round(baseCost * (1 + cityModifier)).toInt()
return cost - (cost % 5)
}
fun getAdoptedPolicies(): Linq<String> = adoptedPolicies
fun isAdopted(policyName: String): Boolean = adoptedPolicies.contains(policyName)
fun canAdoptPolicy(): Boolean = storedCulture >= getCultureNeededForNextPolicy()
fun adopt(policy: Policy) {
adoptedPolicies.add(policy.name)
val branch = GameBasics.PolicyBranches[policy.branch]!!
if (branch.policies.count { isAdopted(it.name) } == branch.policies.size - 1) { // All done apart from branch completion
adopt(branch.policies.last()) // add branch completion!
}
when(policy.name ) {
"Collective Rule" -> civInfo.placeUnitNearTile(civInfo.capital.cityLocation, "Settler")
"Citizenship" -> civInfo.placeUnitNearTile(civInfo.capital.cityLocation, "Worker")
"Representation", "Reformation" -> civInfo.goldenAges.enterGoldenAge()
"Scientific Revolution" -> civInfo.tech.freeTechs += 2
"Legalism" ->
for (city in civInfo.cities.subList(0, Math.min(4, civInfo.cities.size)))
city.cityConstructions.addCultureBuilding()
"Free Religion" -> freePolicies++
"Liberty Complete" -> UnCivGame.Current.screen = GreatPersonPickerScreen()
}
for (cityInfo in civInfo.cities)
cityInfo.cityStats.update()
}
fun nextTurn(culture: Int) {
val couldAdoptPolicyBefore = canAdoptPolicy()
storedCulture += culture
if (!couldAdoptPolicyBefore && canAdoptPolicy())
shouldOpenPolicyPicker = true
}
}

View file

@ -1,21 +0,0 @@
package com.unciv.logic.civilization;
import com.unciv.models.linq.LinqCounter;
public class ScienceVictoryManager {
public LinqCounter<String> requiredParts = new LinqCounter<String>(){
{
add("SS Booster",3);
add("SS Cockpit",1);
add("SS Engine",1);
add("SS Statis Chamber",1);
}
};
public LinqCounter<String> currentParts = new LinqCounter<String>();
public LinqCounter<String> unconstructedParts() {
LinqCounter<String> counter = requiredParts.clone();
counter.remove(currentParts);
return counter;
}
}

View file

@ -0,0 +1,22 @@
package com.unciv.logic.civilization
import com.unciv.models.linq.LinqCounter
class ScienceVictoryManager {
var requiredParts = LinqCounter<String>()
var currentParts = LinqCounter<String>()
fun unconstructedParts(): LinqCounter<String> {
val counter = requiredParts.clone()
counter.remove(currentParts)
return counter
}
init {
requiredParts.add("SS Booster", 3)
requiredParts.add("SS Cockpit", 1)
requiredParts.add("SS Engine", 1)
requiredParts.add("SS Statis Chamber", 1)
}
}

View file

@ -1,92 +0,0 @@
package com.unciv.logic.civilization;
import com.badlogic.gdx.utils.Predicate;
import com.unciv.logic.map.TileInfo;
import com.unciv.models.gamebasics.GameBasics;
import com.unciv.models.gamebasics.Technology;
import com.unciv.models.gamebasics.TileResource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
public class TechManager {
public transient CivilizationInfo civInfo;
public int freeTechs = 0;
public HashSet<String> techsResearched = new HashSet<String>();
/* When moving towards a certain tech, the user doesn't have to manually pick every one. */
public ArrayList<String> techsToResearch = new ArrayList<String>();
public HashMap<String, Integer> techsInProgress = new HashMap<String, Integer>();
public String currentTechnology(){if(techsToResearch.isEmpty()) return null; return techsToResearch.get(0);}
public Technology getCurrentTechnology() {
return GameBasics.Technologies.get(currentTechnology());
}
public int researchOfTech(String TechName) {
int amountResearched = 0;
if (techsInProgress.containsKey(TechName)) amountResearched = techsInProgress.get(TechName);
return amountResearched;
}
public boolean isResearched(String TechName) {
return techsResearched.contains(TechName);
}
public boolean canBeResearched(String TechName) {
for (String prerequisiteTech : GameBasics.Technologies.get(TechName).prerequisites)
if (!isResearched(prerequisiteTech)) return false;
return true;
}
public void nextTurn(int scienceForNewTurn){
final String CurrentTechnology = currentTechnology();
techsInProgress.put(CurrentTechnology, researchOfTech(CurrentTechnology) + scienceForNewTurn);
if (techsInProgress.get(CurrentTechnology) >= getCurrentTechnology().cost) // We finished it!
{
techsInProgress.remove(CurrentTechnology);
techsToResearch.remove(CurrentTechnology);
techsResearched.add(CurrentTechnology);
civInfo.gameInfo.addNotification("Research of " + CurrentTechnology + " has completed!", null);
TileResource revealedResource = GameBasics.TileResources.linqValues().first(new Predicate<TileResource>() {
@Override
public boolean evaluate(TileResource arg0) {
return CurrentTechnology.equals(arg0.revealedBy);
}
});
if (revealedResource != null)
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)
.first(new Predicate<TileInfo>() {
@Override
public boolean evaluate(TileInfo arg0) {
return arg0.isCityCenter();
}
});
if (cityTile != null) {
civInfo.gameInfo.addNotification(
revealedResource.name + " revealed near " + cityTile.getCity().name, tileInfo.position);
break;
}
}
}
}
}
public String getAmountResearchedText(){
if(currentTechnology()==null) return "";
return "("+researchOfTech(currentTechnology())+"/"+getCurrentTechnology().cost+")";
}
}

View file

@ -0,0 +1,74 @@
package com.unciv.logic.civilization
import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.gamebasics.Technology
import java.util.ArrayList
import java.util.HashMap
import java.util.HashSet
class TechManager {
@Transient
lateinit var civInfo: CivilizationInfo
var freeTechs = 0
var techsResearched = HashSet<String>()
/* When moving towards a certain tech, the user doesn't have to manually pick every one. */
var techsToResearch = ArrayList<String>()
private var techsInProgress = HashMap<String, Int>()
private fun getCurrentTechnology(): Technology = GameBasics.Technologies[currentTechnology()]!!
fun getAmountResearchedText(): String =
if (currentTechnology() == null) ""
else "(" + researchOfTech(currentTechnology()!!) + "/" + getCurrentTechnology().cost + ")"
fun currentTechnology(): String? {
if (techsToResearch.isEmpty()) return null
else return techsToResearch[0]
}
fun researchOfTech(TechName: String?): Int {
if (techsInProgress.containsKey(TechName)) return techsInProgress[TechName]!!
else return 0
}
fun isResearched(TechName: String): Boolean = techsResearched.contains(TechName)
fun canBeResearched(TechName: String): Boolean {
return GameBasics.Technologies[TechName]!!.prerequisites.all { isResearched(it) }
}
fun nextTurn(scienceForNewTurn: Int) {
val currentTechnology = currentTechnology()
if (currentTechnology == null) return
techsInProgress[currentTechnology] = researchOfTech(currentTechnology) + scienceForNewTurn
if (techsInProgress[currentTechnology]!! < getCurrentTechnology().cost)
return
// We finished it!
techsInProgress.remove(currentTechnology)
techsToResearch.remove(currentTechnology)
techsResearched.add(currentTechnology)
civInfo.gameInfo.addNotification("Research of $currentTechnology has completed!", null)
val revealedResource = GameBasics.TileResources.linqValues().first { currentTechnology == it.revealedBy }
if (revealedResource == null) return
for (tileInfo in civInfo.gameInfo.tileMap.values
.where { it.resource == revealedResource.name && civInfo.civName == it.owner }) {
val closestCityTile = civInfo.gameInfo.tileMap.getTilesInDistance(tileInfo.position, 4)
.first { it.isCityCenter }
if (closestCityTile != null) {
civInfo.gameInfo.addNotification(
revealedResource.name + " revealed near " + closestCityTile.city!!.name, tileInfo.position)
break
}
}
}
}

View file

@ -14,7 +14,7 @@ class MapUnit {
@JvmField var owner: String? = null
@JvmField var name: String? = null
@JvmField var maxMovement: Int = 0
@JvmField var currentMovement: Float = 0.toFloat()
@JvmField var currentMovement: Float = 0f
@JvmField var action: String? = null // work, automation, fortifying, I dunno what.
val movementString: String
@ -82,9 +82,9 @@ class MapUnit {
fun doAutomatedAction(tile: TileInfo) {
var tile = tile
val toWork = findTileToWork(tile)
if (toWork != tile) {
tile = headTowards(tile.position, toWork.position)
val tileToWork = findTileToWork(tile)
if (tileToWork != tile) {
tile = headTowards(tile.position, tileToWork.position)
doPreTurnAction(tile)
return
}
@ -106,7 +106,7 @@ class MapUnit {
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.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"
@ -126,7 +126,7 @@ class MapUnit {
val isMachineryResearched = civInfo!!.tech.isResearched("Machinery")
val path = tileMap.getShortestPath(origin, destination, currentMovement, maxMovement, isMachineryResearched)
val destinationThisTurn = path[0]
val destinationThisTurn = path.first()
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)

View file

@ -36,7 +36,7 @@ class RandomMapGenerator {
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) }
TileResources = TileResources.where { it.terrainsCanBeFoundOn.contains(tileInfo.lastTerrain.name) }
var resource: TileResource? = null
if (Math.random() < 1 / 5f) {

View file

@ -8,7 +8,7 @@ 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 com.unciv.models.stats.Stats
class TileInfo {
@Transient @JvmField var tileMap: TileMap? = null
@ -32,8 +32,8 @@ class TileInfo {
val lastTerrain: Terrain
get() = if (terrainFeature == null) getBaseTerrain() else getTerrainFeature()!!
val tileResource: TileResource?
get() = if (resource == null) null else GameBasics.TileResources[resource]
val tileResource: TileResource
get() = if (resource == null) throw Exception("No resource exists for this tile!") else GameBasics.TileResources[resource]!!
val isCityCenter: Boolean
get() = city != null && position == city!!.cityLocation
@ -66,11 +66,11 @@ class TileInfo {
}
fun getTileStats(observingCiv: CivilizationInfo): FullStats {
fun getTileStats(observingCiv: CivilizationInfo): Stats {
return getTileStats(city, observingCiv)
}
fun getTileStats(city: CityInfo?, observingCiv: CivilizationInfo): FullStats {
fun getTileStats(city: CityInfo?, observingCiv: CivilizationInfo): Stats {
var stats = getBaseTerrain().clone()
if (terrainFeature != null) {
@ -81,22 +81,22 @@ class TileInfo {
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)) {
val resource = tileResource
stats.add(tileResource) // 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
if (resource != null && tileResource.improvement == improvement.name)
stats.add(tileResource.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.improvingTech != null && 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"))
@ -113,7 +113,7 @@ class TileInfo {
if ("Jungle" == terrainFeature && city != null
&& city.buildingUniques.contains("JunglesProvideScience"))
stats.science += 2f
if (stats.gold != 0f && observingCiv.goldenAges.isGoldenAge)
if (stats.gold != 0f && observingCiv.goldenAges.isGoldenAge())
stats.gold++
return stats
@ -122,12 +122,12 @@ class TileInfo {
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.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
return hasViewableResource(civInfo) && tileResource.improvement == improvement.name
}
@ -147,11 +147,11 @@ class TileInfo {
override fun toString(): String {
val SB = StringBuilder()
if (isCityCenter) {
SB.appendln(workingCity + ",\r\n" + city!!.cityConstructions.productionForTileInfo)
SB.appendln(workingCity + ",\r\n" + city!!.cityConstructions.getProductionForTileInfo())
}
SB.appendln(this.baseTerrain)
if (terrainFeature != null) SB.appendln(terrainFeature!!)
if (hasViewableResource(tileMap!!.gameInfo!!.playerCivilization)) SB.appendln(resource!!)
if (hasViewableResource(tileMap!!.gameInfo!!.getPlayerCivilization())) 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")
@ -160,14 +160,14 @@ class TileInfo {
}
fun hasViewableResource(civInfo: CivilizationInfo): Boolean {
return resource != null && (tileResource!!.revealedBy == null || civInfo.tech.isResearched(tileResource!!.revealedBy))
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;
if (unit!!.name == "Worker" && improvementInProgress != null) return false
return true
}
fun moveUnitToTile(otherTile: TileInfo, movementDistance: Float) {

View file

@ -5,7 +5,7 @@ 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.logic.GameInfo
import com.unciv.ui.utils.HexMath
class TileMap {
@ -15,7 +15,7 @@ class TileMap {
private var tiles = LinqHashMap<String, TileInfo>()
constructor() {} // for json parsing, we need to have a default constructor
constructor() // for json parsing, we need to have a default constructor
val values: Linq<TileInfo>
get() = tiles.linqValues()
@ -34,7 +34,7 @@ class TileMap {
return tiles[vector.toString()]!!
}
fun getTilesInDistance(origin: Vector2?, distance: Int): Linq<TileInfo> {
fun getTilesInDistance(origin: Vector2, distance: Int): Linq<TileInfo> {
return HexMath.GetVectorsInDistance(origin, distance).where{contains(it)}.select { get(it) }
}

View file

@ -7,7 +7,7 @@ import com.unciv.ui.UnCivGame
import com.unciv.ui.VictoryScreen
import com.unciv.ui.pickerscreens.PolicyPickerScreen
import com.unciv.models.linq.Linq
import com.unciv.models.stats.FullStats
import com.unciv.models.stats.Stats
import com.unciv.models.stats.NamedStats
class Building : NamedStats(), IConstruction, ICivilopedia {
@ -19,9 +19,9 @@ class Building : NamedStats(), IConstruction, ICivilopedia {
@JvmField var cost: Int = 0
@JvmField var maintenance = 0
@JvmField var percentStatBonus: FullStats? = null
@JvmField var specialistSlots: FullStats? = null
@JvmField var greatPersonPoints: FullStats? = null
@JvmField var percentStatBonus: Stats? = null
@JvmField var specialistSlots: Stats? = null
@JvmField var greatPersonPoints: Stats? = null
/** Extra cost percentage when purchasing */
@JvmField var hurryCostModifier: Int = 0
@JvmField var isWonder = false
@ -42,16 +42,14 @@ class Building : NamedStats(), IConstruction, ICivilopedia {
/**
* The bonus stats that a resource gets when this building is built
*/
@JvmField var resourceBonusStats: FullStats? = null
@JvmField var resourceBonusStats: Stats? = null
fun getRequiredTech(): Technology {
return GameBasics.Technologies[requiredTech]!!
}
fun getRequiredTech(): Technology = GameBasics.Technologies[requiredTech]!!
fun getStats(adoptedPolicies: Linq<String>): FullStats {
fun getStats(adoptedPolicies: Linq<String>): Stats {
val stats = this.clone()
if (adoptedPolicies.contains("Organized Religion") && Linq("Monument", "Temple", "Monastery").contains(name))
stats.happiness += 1f
stats.happiness += 1
if (adoptedPolicies.contains("Free Religion") && Linq("Monument", "Temple", "Monastery").contains(name))
stats.culture += 1f
@ -63,7 +61,7 @@ class Building : NamedStats(), IConstruction, ICivilopedia {
stats.science += 1f
if (adoptedPolicies.contains("Theocracy") && name == "Temple")
percentStatBonus = object : FullStats() {
percentStatBonus = object : Stats() {
init {
gold = 10f
}
@ -136,18 +134,18 @@ class Building : NamedStats(), IConstruction, ICivilopedia {
override fun isBuildable(construction: CityConstructions): Boolean {
if (construction.isBuilt(name)) return false
val civInfo = construction.cityInfo.civInfo
if (requiredTech != null && !civInfo.tech.isResearched(requiredTech)) return false
if (requiredTech != null && !civInfo.tech.isResearched(requiredTech!!)) return false
if (isWonder && civInfo.cities.any {
it.cityConstructions.isBuilding(name) || it.cityConstructions.isBuilt(name)
})
return false
if (requiredBuilding != null && !construction.isBuilt(requiredBuilding)) return false
if (requiredBuildingInAllCities != null || civInfo.cities.any { it.cityConstructions.isBuilt(requiredBuildingInAllCities) })
if (requiredBuilding != null && !construction.isBuilt(requiredBuilding!!)) return false
if (requiredBuildingInAllCities != null && civInfo.cities.any { !it.cityConstructions.isBuilt(requiredBuildingInAllCities!!) })
return false
if (cannotBeBuiltWith != null && construction.isBuilt(cannotBeBuiltWith)) return false
if (cannotBeBuiltWith != null && construction.isBuilt(cannotBeBuiltWith!!)) return false
if ("MustBeNextToDesert" == unique && !civInfo.gameInfo.tileMap.getTilesInDistance(construction.cityInfo.cityLocation, 1).any { it.baseTerrain == "Desert" })
return false
if (requiredResource != null && !civInfo.civResources.containsKey(GameBasics.TileResources[requiredResource]))
if (requiredResource != null && !civInfo.getCivResources().containsKey(GameBasics.TileResources[requiredResource]))
return false // Only checks if exists, doesn't check amount - todo
@ -156,7 +154,7 @@ class Building : NamedStats(), IConstruction, ICivilopedia {
.any { tile ->
(tile.resource != null
&& requiredNearbyImprovedResources!!.contains(tile.resource)
&& tile.tileResource!!.improvement == tile.improvement)
&& tile.tileResource.improvement == tile.improvement)
}
if (!containsResourceWithImprovement) return false
}

View file

@ -3,5 +3,5 @@ package com.unciv.models.gamebasics
import com.unciv.models.linq.Linq
class PolicyBranch : Policy() {
@JvmField var policies: Linq<Policy>? = null
@JvmField var policies: Linq<Policy> = Linq()
}

View file

@ -3,10 +3,10 @@ package com.unciv.models.gamebasics
import java.util.HashSet
class Technology {
@JvmField var name: String? = null
lateinit var name: String
@JvmField var description: String? = null
@JvmField var cost: Int = 0
var description: String? = null
var cost: Int = 0
@JvmField var prerequisites = HashSet<String>()
@JvmField var column: TechColumn? = null // The column that this tech is in the tech tree

View file

@ -1,7 +1,7 @@
package com.unciv.models.gamebasics
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.models.stats.FullStats
import com.unciv.models.stats.Stats
import com.unciv.models.stats.NamedStats
import java.util.ArrayList
@ -13,7 +13,7 @@ class TileImprovement : NamedStats(), ICivilopedia {
@JvmField var techRequired: String? = null
@JvmField var improvingTech: String? = null
@JvmField var improvingTechStats: FullStats? = null
@JvmField var improvingTechStats: Stats? = null
private val turnsToBuild: Int = 0 // This is the base cost.
fun getTurnsToBuild(civInfo: CivilizationInfo): Int {

View file

@ -2,7 +2,7 @@ package com.unciv.models.gamebasics
import com.unciv.models.linq.Linq
import com.unciv.models.stats.NamedStats
import com.unciv.models.stats.FullStats
import com.unciv.models.stats.Stats
class TileResource : NamedStats(), ICivilopedia {
override val description: String
@ -19,7 +19,7 @@ class TileResource : NamedStats(), ICivilopedia {
@JvmField var resourceType: ResourceType = ResourceType.Bonus
@JvmField var terrainsCanBeFoundOn: Linq<String> = Linq()
@JvmField var improvement: String? = null
@JvmField var improvementStats: FullStats? = null
@JvmField var improvementStats: Stats? = null
/**
* The building that improves this resource, if any. E.G.: Granary for wheat, Stable for cattle.

View file

@ -40,10 +40,6 @@ public class Linq<T> extends ArrayList<T> {
public boolean any(Predicate<T> p){ return first(p) != null;}
public int count(Predicate<T> p) {
return where(p).size();
}
public <T2> Linq<T2> select(Func<T, T2> selector) {
Linq<T2> newCollection = new Linq<T2>();
for (T t : this) newCollection.add(selector.GetBy(t));

View file

@ -1,15 +1,3 @@
package com.unciv.models.stats
open class CivStats {
@JvmField var gold = 0f
@JvmField var science = 0f
@JvmField var culture = 0f
@JvmField var happiness = 0f
fun add(other: CivStats) {
gold += other.gold
science += other.science
happiness += other.happiness
culture += other.culture
}
}

View file

@ -1,58 +0,0 @@
package com.unciv.models.stats
import java.util.HashMap
open class FullStats : CivStats()
{
@JvmField var production: Float = 0f
@JvmField var food: Float = 0f
fun add(other: FullStats) {
production += other.production
food += other.food
super.add(other)
}
fun clone():FullStats {
val stats = FullStats()
stats.add(this)
return stats
}
fun getMinus(): FullStats {
val stats = FullStats()
stats.food = -food
stats.food = -food
stats.gold = -gold
stats.science = -science
stats.culture = -culture
stats.happiness = -happiness
return stats
}
operator fun times(number: Float): FullStats{
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()
}
fun toDict(): HashMap<String, Int> {
return hashMapOf("Production" to production.toInt(),
"Food" to food.toInt(),
"Gold" to gold.toInt(),
"Science" to science.toInt(),
"Culture" to culture.toInt()
)
}
}

View file

@ -1,7 +1,7 @@
package com.unciv.models.stats
open class NamedStats : FullStats(), INamed {
open class NamedStats : Stats(), INamed {
override lateinit var name: String
override fun toString(): String {

View file

@ -0,0 +1,77 @@
package com.unciv.models.stats
enum class Stat{
Production,
Food,
Gold,
Science,
Culture,
Happiness
}
open class Stats() {
var production: Float=0f
var food: Float=0f
var gold: Float=0f
var science: Float=0f
var culture: Float=0f
var happiness: Float=0f
constructor(hashMap: HashMap<Stat, Float>) : this() {
setStats(hashMap)
}
fun add(other: Stats) {
val hashMap = toHashMap()
for (stat in Stat.values())
hashMap[stat] = hashMap[stat]!! + other.toHashMap()[stat]!!
setStats(hashMap)
}
fun add(stat:Stat, value:Float) {
val hashMap = toHashMap()
hashMap[stat] = hashMap[stat]!!+value
setStats(hashMap)
}
fun clone(): Stats {
val stats = Stats()
stats.add(this)
return stats
}
operator fun unaryMinus(): Stats {
val hashMap = toHashMap()
for(stat in Stat.values()) hashMap[stat]= -hashMap[stat]!!
return Stats(hashMap)
}
operator fun times(number: Float): Stats {
val hashMap = toHashMap()
for(stat in Stat.values()) hashMap[stat]= number * hashMap[stat]!!
return Stats(hashMap)
}
override fun toString(): String {
return toHashMap().filter { it.value != 0f }.map { it.key.toString() + ": " + it.value }.joinToString()
}
fun toHashMap(): HashMap<Stat, Float> {
return hashMapOf(Stat.Production to production,
Stat.Culture to culture,
Stat.Gold to gold,
Stat.Food to food,
Stat.Happiness to happiness,
Stat.Science to science)
}
private fun setStats(hashMap:HashMap<Stat, Float>){
culture=hashMap[Stat.Culture]!!
gold=hashMap[Stat.Gold]!!
production=hashMap[Stat.Production]!!
food=hashMap[Stat.Food]!!
happiness=hashMap[Stat.Happiness]!!
science=hashMap[Stat.Science]!!
}
}

View file

@ -1,111 +0,0 @@
package com.unciv.ui;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.ui.Button;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.List;
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane;
import com.badlogic.gdx.scenes.scene2d.ui.SplitPane;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.ui.Value;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.badlogic.gdx.utils.Array;
import com.unciv.models.gamebasics.GameBasics;
import com.unciv.models.gamebasics.ICivilopedia;
import com.unciv.ui.utils.CameraStageBaseScreen;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
public class CivilopediaScreen extends CameraStageBaseScreen {
public CivilopediaScreen() {
Gdx.input.setInputProcessor(stage);
Table buttonTable = new Table();
buttonTable.pad(15);
Table entryTable = new Table();
SplitPane SP = new SplitPane(buttonTable, entryTable, true, skin);
SP.setSplitAmount(0.2f);
SP.setFillParent(true);
stage.addActor(SP);
final Label label = new Label("", skin);
label.setWrap(true);
TextButton goToGameButton = new TextButton("Return \r\nto game",skin);
goToGameButton.addListener(new ClickListener(){
@Override
public void clicked(InputEvent event, float x, float y) {
game.setWorldScreen();
dispose();
}
});
buttonTable.add(goToGameButton);
final LinkedHashMap<String, Collection<ICivilopedia>> map = new LinkedHashMap<String, Collection<ICivilopedia>>();
map.put("Basics", GameBasics.Helps.linqValues().as(ICivilopedia.class));
map.put("Buildings", GameBasics.Buildings.linqValues().as(ICivilopedia.class));
map.put("Resources", GameBasics.TileResources.linqValues().as(ICivilopedia.class));
map.put("Terrains", GameBasics.Terrains.linqValues().as(ICivilopedia.class));
map.put("Tile Improvements", GameBasics.TileImprovements.linqValues().as(ICivilopedia.class));
final List<ICivilopedia> nameList = new List<ICivilopedia>(skin);
final ClickListener namelistClickListener = new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
ICivilopedia building = nameList.getSelected();
if (building == null) return;
label.setText(building.getDescription());
super.clicked(event, x, y);
}
};
nameList.addListener(namelistClickListener);
nameList.getStyle().fontColorSelected = Color.BLACK;
nameList.getStyle().font.getData().setScale(1.5f);
final ArrayList<Button> buttons = new ArrayList<Button>();
boolean first = true;
for (final String str : map.keySet()) {
final TextButton button = new TextButton(str, skin);
button.getStyle().checkedFontColor = Color.BLACK;
buttons.add(button);
ClickListener listener = new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
Array<ICivilopedia> newArray = new Array<ICivilopedia>();
for (ICivilopedia civ : map.get(str)) newArray.add(civ);
nameList.setItems(newArray);
nameList.setSelected(nameList.getItems().get(0));
namelistClickListener.clicked(null, 0, 0); // fake-click the first item, so the text is displayed
for (Button btn : buttons) btn.setChecked(false);
button.setChecked(true);
}
};
if (first) {// Fake-click the first button so that the user sees results immediately
first = false;
listener.clicked(null, 0, 0);
}
button.addListener(listener);
button.getLabel().setFontScale(0.7f);
buttonTable.add(button).width(button.getWidth()*0.7f);
}
ScrollPane sp = new ScrollPane(nameList);
sp.setupOverscroll(5, 1, 200);
entryTable.add(sp).width(Value.percentWidth(0.25f, entryTable)).height(Value.percentHeight(0.7f, entryTable))
.pad(Value.percentWidth(0.02f, entryTable));
entryTable.add(label).colspan(4).width(Value.percentWidth(0.65f, entryTable)).height(Value.percentHeight(0.7f, entryTable))
.pad(Value.percentWidth(0.02f, entryTable));
buttonTable.setWidth(stage.getWidth());
}
}

View file

@ -0,0 +1,96 @@
package com.unciv.ui
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.InputEvent
import com.badlogic.gdx.scenes.scene2d.ui.*
import com.badlogic.gdx.scenes.scene2d.ui.List
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener
import com.badlogic.gdx.utils.Array
import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.gamebasics.ICivilopedia
import com.unciv.ui.cityscreen.addClickListener
import com.unciv.ui.utils.CameraStageBaseScreen
import java.util.*
class CivilopediaScreen : CameraStageBaseScreen() {
init {
Gdx.input.inputProcessor = stage
val buttonTable = Table()
buttonTable.pad(15f)
val entryTable = Table()
val splitPane = SplitPane(buttonTable, entryTable, true, CameraStageBaseScreen.skin)
splitPane.setSplitAmount(0.2f)
splitPane.setFillParent(true)
stage.addActor(splitPane)
val label = Label("", CameraStageBaseScreen.skin)
label.setWrap(true)
val goToGameButton = TextButton("Return \r\nto game", CameraStageBaseScreen.skin)
goToGameButton.addListener(object : ClickListener() {
override fun clicked(event: InputEvent?, x: Float, y: Float) {
game.setWorldScreen()
dispose()
}
})
buttonTable.add(goToGameButton)
val map = LinkedHashMap<String, Collection<ICivilopedia>>()
map["Basics"] = GameBasics.Helps.linqValues().`as`(ICivilopedia::class.java)
map["Buildings"] = GameBasics.Buildings.linqValues().`as`(ICivilopedia::class.java)
map["Resources"] = GameBasics.TileResources.linqValues().`as`(ICivilopedia::class.java)
map["Terrains"] = GameBasics.Terrains.linqValues().`as`(ICivilopedia::class.java)
map["Tile Improvements"] = GameBasics.TileImprovements.linqValues().`as`(ICivilopedia::class.java)
val nameList = List<ICivilopedia>(CameraStageBaseScreen.skin)
val nameListClickListener = {
if(nameList.selected!=null) {
val building = nameList.selected
label.setText(building.description)
}
}
nameList.addClickListener (nameListClickListener)
nameList.style.fontColorSelected = Color.BLACK
nameList.style.font.data.setScale(1.5f)
val buttons = ArrayList<Button>()
var first = true
for (str in map.keys) {
val button = TextButton(str, CameraStageBaseScreen.skin)
button.style.checkedFontColor = Color.BLACK
buttons.add(button)
val buttonClicked = {
val newArray = Array<ICivilopedia>()
for (civ in map[str]!!) newArray.add(civ)
nameList.setItems(newArray)
nameList.selected = nameList.items.get(0)
for (btn in buttons) btn.isChecked = false
button.isChecked = true
}
button.addClickListener(buttonClicked)
if (first) {// Fake-click the first button so that the user sees results immediately
first = false
buttonClicked()
}
button.label.setFontScale(0.7f)
buttonTable.add(button).width(button.width * 0.7f)
}
val sp = ScrollPane(nameList)
sp.setupOverscroll(5f, 1f, 200f)
entryTable.add(sp).width(Value.percentWidth(0.25f, entryTable)).height(Value.percentHeight(0.7f, entryTable))
.pad(Value.percentWidth(0.02f, entryTable))
entryTable.add(label).colspan(4).width(Value.percentWidth(0.65f, entryTable)).height(Value.percentHeight(0.7f, entryTable))
.pad(Value.percentWidth(0.02f, entryTable))
buttonTable.width = stage.width
}
}

View file

@ -1,73 +0,0 @@
package com.unciv.ui;
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.logic.civilization.Notification;
import com.unciv.logic.map.TileInfo;
import com.unciv.logic.map.TileMap;
import com.unciv.models.linq.Linq;
public class GameInfo{
public Linq<Notification> notifications = new Linq<Notification>();
public void addNotification(String text, Vector2 location){
notifications.add(new Notification(text,location));
}
public Linq<String> tutorial = new Linq<String>();
public Linq<CivilizationInfo> civilizations = new Linq<CivilizationInfo>();
public TileMap tileMap;
public int turns = 1;
public void nextTurn(){
notifications.clear();
for(CivilizationInfo civInfo : civilizations) civInfo.nextTurn();
for(TileInfo tile : tileMap.getValues().where(new Predicate<TileInfo>() {
@Override
public boolean evaluate(TileInfo arg0) {
return arg0.unit!=null;
}
})) tile.nextTurn();
// We need to update the stats after ALL the cities are done updating because
// maybe one of them has a wonder that affects the stats of all the rest of the cities
for(CivilizationInfo civInfo : civilizations)
for (CityInfo city : civInfo.cities)
city.cityStats.update();
turns++;
}
public void setTransients(){
tileMap.gameInfo=this;
tileMap.setTransients();
for(CivilizationInfo civInfo : civilizations){
civInfo.gameInfo = this;
civInfo.setTransients();
}
for(final TileInfo tile : tileMap.getValues())
if(tile.unit!=null) tile.unit.civInfo=civilizations.first(new Predicate<CivilizationInfo>() {
@Override
public boolean evaluate(CivilizationInfo arg0) {
return arg0.civName.equals(tile.unit.owner);
}
});
for(CivilizationInfo civInfo : civilizations)
for(CityInfo cityInfo : civInfo.cities)
cityInfo.cityStats.update();
}
public CivilizationInfo getPlayerCivilization() {
return civilizations.get(0);
}
}

View file

@ -1,11 +0,0 @@
package com.unciv.ui;
public class GameSettings{
public float labelScale = 1.5f;
public float buttonScale = 0.9f;
public float tilesZoom = 1;
public float cityTilesX =0;
public float cityTilesY =0;
float worldScrollX=0;
float worldScrollY=0;
}

View file

@ -0,0 +1,11 @@
package com.unciv.ui
class GameSettings {
var labelScale = 1.5f
var buttonScale = 0.9f
var tilesZoom = 1f
var cityTilesX = 0f
var cityTilesY = 0f
internal var worldScrollX = 0f
internal var worldScrollY = 0f
}

View file

@ -1,57 +0,0 @@
package com.unciv.ui;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.scenes.scene2d.Touchable;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.unciv.logic.civilization.CivilizationInfo;
import com.unciv.logic.civilization.ScienceVictoryManager;
import com.unciv.models.linq.Linq;
import com.unciv.models.linq.LinqCounter;
import com.unciv.ui.pickerscreens.PickerScreen;
public class ScienceVictoryScreen extends PickerScreen {
final CivilizationInfo civInfo;
public ScienceVictoryScreen(CivilizationInfo civInfo) {
this.civInfo = civInfo;
ScienceVictoryManager scienceVictory = civInfo.scienceVictory;
LinqCounter<String> builtSpaceshipParts = scienceVictory.currentParts.clone();
for (String key: scienceVictory.requiredParts.keySet()) // can't take the keyset because we would be modifying it!
for(int i = 0; i < scienceVictory.requiredParts.get(key); i++)
addPartButton(key,builtSpaceshipParts);
rightSideButton.setVisible(false);
if(!civInfo.getBuildingUniques().contains("ApolloProgram"))
descriptionLabel.setText("You must build the Apollo Program before you can build spaceship parts!");
else descriptionLabel.setText("Apollo program is built - you may construct spaceship parts in your cities!");
Linq<String> tutorial = new Linq<String>();
tutorial.add("This is the science victory screen, where you" +
"\r\n can see your progress towards constructing a " +
"\r\n spaceship to propel you towards the stars.");
tutorial.add("There are 6 spaceship parts you must build, " +
"\r\n and they all require advanced technologies");
if(!civInfo.getBuildingUniques().contains("ApolloProgram"))
tutorial.add("You can start constructing spaceship parts" +
"\r\n only after you have finished the Apollo Program");
displayTutorials("ScienceVictoryScreenEntered",tutorial);
}
private void addPartButton(String partName, LinqCounter<String> parts){
topTable.row();
TextButton button = new TextButton(partName,skin);
button.setTouchable(Touchable.disabled);
if(!civInfo.getBuildingUniques().contains("ApolloProgram"))
button.setColor(Color.GRAY);
else if (parts.get(partName)>0){
button.setColor(Color.GREEN);
parts.add(partName,-1);
}
topTable.add(button).pad(10);
}
}

View file

@ -0,0 +1,54 @@
package com.unciv.ui
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.Touchable
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.models.linq.Linq
import com.unciv.models.linq.LinqCounter
import com.unciv.ui.pickerscreens.PickerScreen
import com.unciv.ui.utils.CameraStageBaseScreen
class ScienceVictoryScreen(internal val civInfo: CivilizationInfo) : PickerScreen() {
init {
val scienceVictory = civInfo.scienceVictory
val builtSpaceshipParts = scienceVictory.currentParts.clone()
for (key in scienceVictory.requiredParts.keys)
// can't take the keyset because we would be modifying it!
for (i in 0 until scienceVictory.requiredParts[key]!!)
addPartButton(key, builtSpaceshipParts)
rightSideButton.isVisible = false
if (!civInfo.buildingUniques.contains("ApolloProgram"))
descriptionLabel.setText("You must build the Apollo Program before you can build spaceship parts!")
else
descriptionLabel.setText("Apollo program is built - you may construct spaceship parts in your cities!")
val tutorial = Linq<String>()
tutorial.add("This is the science victory screen, where you" +
"\r\n can see your progress towards constructing a " +
"\r\n spaceship to propel you towards the stars.")
tutorial.add("There are 6 spaceship parts you must build, " + "\r\n and they all require advanced technologies")
if (!civInfo.buildingUniques.contains("ApolloProgram"))
tutorial.add("You can start constructing spaceship parts" + "\r\n only after you have finished the Apollo Program")
displayTutorials("ScienceVictoryScreenEntered", tutorial)
}
private fun addPartButton(partName: String, parts: LinqCounter<String>) {
topTable.row()
val button = TextButton(partName, CameraStageBaseScreen.skin)
button.touchable = Touchable.disabled
if (!civInfo.buildingUniques.contains("ApolloProgram"))
button.color = Color.GRAY
else if (parts[partName]!! > 0) {
button.color = Color.GREEN
parts.add(partName, -1)
}
topTable.add<TextButton>(button).pad(10f)
}
}

View file

@ -1,118 +0,0 @@
package com.unciv.ui;
import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Json;
import com.unciv.logic.civilization.CivilizationInfo;
import com.unciv.logic.map.TileMap;
import com.unciv.models.gamebasics.Unit;
import com.unciv.models.linq.Linq;
import com.unciv.models.gamebasics.BasicHelp;
import com.unciv.models.gamebasics.Building;
import com.unciv.models.gamebasics.GameBasics;
import com.unciv.models.gamebasics.Policy;
import com.unciv.models.gamebasics.PolicyBranch;
import com.unciv.models.gamebasics.Technology;
import com.unciv.models.linq.LinqHashMap;
import com.unciv.models.gamebasics.TechColumn;
import com.unciv.models.gamebasics.Terrain;
import com.unciv.models.gamebasics.TileImprovement;
import com.unciv.models.gamebasics.TileResource;
import com.unciv.models.stats.INamed;
import com.unciv.ui.utils.GameSaver;
import com.unciv.ui.worldscreen.WorldScreen;
public class UnCivGame extends Game {
public static UnCivGame Current;
public GameInfo gameInfo;
public GameSettings settings = new GameSettings();
public WorldScreen worldScreen;
public void create() {
SetupGameBasics();
Current = this;
if(GameSaver.GetSave("Autosave").exists()) {
try {
GameSaver.LoadGame(this, "Autosave");
} catch(Exception ex){ // silent fail if we can't read the autosave
startNewGame();
}
}
else startNewGame();
worldScreen = new WorldScreen();
setWorldScreen();
}
public void startNewGame(){
gameInfo = new GameInfo();
gameInfo.tileMap = new TileMap(20);
gameInfo.civilizations.add(new CivilizationInfo("Player", Vector2.Zero,gameInfo));
gameInfo.setTransients();
worldScreen = new WorldScreen();
setWorldScreen();
}
public void setWorldScreen(){
setScreen(worldScreen);
worldScreen.update();
Gdx.input.setInputProcessor(worldScreen.stage);
}
private <T> T GetFromJson(Class<T> tClass, String name){
String jsonText = Gdx.files.internal("jsons/"+name+".json").readString();
return new Json().fromJson(tClass,jsonText);
}
private <T extends INamed> LinqHashMap<String,T> CreateHashmap(Class<T> tClass, T[] items){
LinqHashMap<String,T> hashMap = new LinqHashMap<String, T>();
for(T item:items) hashMap.put(item.getName(),item);
return hashMap;
}
private void SetupGameBasics() {
GameBasics.Buildings = CreateHashmap(Building.class,GetFromJson(Building[].class,"Buildings"));
GameBasics.Terrains = CreateHashmap(Terrain.class,GetFromJson(Terrain[].class,"Terrains"));
GameBasics.TileResources = CreateHashmap(TileResource.class,GetFromJson(TileResource[].class,"TileResources"));
GameBasics.TileImprovements = CreateHashmap(TileImprovement.class,GetFromJson(TileImprovement[].class,"TileImprovements"));
GameBasics.Helps = CreateHashmap(BasicHelp.class,GetFromJson(BasicHelp[].class,"BasicHelp"));
GameBasics.Units = CreateHashmap(Unit.class,GetFromJson(Unit[].class,"Units"));
GameBasics.PolicyBranches = CreateHashmap(PolicyBranch.class,GetFromJson(PolicyBranch[].class,"Policies"));
TechColumn[] TechColumns = GetFromJson(TechColumn[].class, "Techs");
GameBasics.Technologies = new LinqHashMap<String, Technology>();
for(TechColumn techColumn : TechColumns){
for(com.unciv.models.gamebasics.Technology tech : techColumn.techs){
tech.cost = techColumn.techCost;
tech.column = techColumn;
GameBasics.Technologies.put(tech.name,tech);
}
}
for(Building building : GameBasics.Buildings.values()) {
if (building.requiredTech == null) continue;
TechColumn column = building.getRequiredTech().column;
if(building.cost==0)
building.cost = building.isWonder ? column.wonderCost : column.buildingCost;
}
for(PolicyBranch branch : GameBasics.PolicyBranches.values()){
branch.requires=new Linq<String>();
branch.branch=branch.name;
for(Policy policy:branch.policies) {
policy.branch=branch.name;
if (policy.requires == null) {
policy.requires = new Linq<String>();
policy.requires.add(branch.name);
}
}
branch.policies.get(branch.policies.size()-1).name=branch.name+" Complete";
}
}
}

View file

@ -0,0 +1,115 @@
package com.unciv.ui
import com.badlogic.gdx.Game
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.math.Vector2
import com.badlogic.gdx.utils.Json
import com.unciv.logic.GameInfo
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.map.TileMap
import com.unciv.models.gamebasics.*
import com.unciv.models.gamebasics.Unit
import com.unciv.models.linq.Linq
import com.unciv.models.linq.LinqHashMap
import com.unciv.models.stats.INamed
import com.unciv.ui.utils.GameSaver
import com.unciv.ui.worldscreen.WorldScreen
import kotlin.Array
import kotlin.Exception
import kotlin.String
class UnCivGame : Game() {
var gameInfo: GameInfo = GameInfo()
var settings = GameSettings()
var worldScreen: WorldScreen? = null
override fun create() {
setupGameBasics()
Current = this
if (GameSaver.GetSave("Autosave").exists()) {
try {
GameSaver.LoadGame(this, "Autosave")
} catch (ex: Exception) { // silent fail if we can't read the autosave
startNewGame()
}
}
else startNewGame()
worldScreen = WorldScreen()
setWorldScreen()
}
fun startNewGame() {
gameInfo = GameInfo()
gameInfo.tileMap = TileMap(20)
gameInfo.civilizations.add(CivilizationInfo("Player", Vector2.Zero, gameInfo))
gameInfo.setTransients()
worldScreen = WorldScreen()
setWorldScreen()
}
fun setWorldScreen() {
setScreen(worldScreen)
worldScreen!!.update()
Gdx.input.inputProcessor = worldScreen!!.stage
}
private fun <T> getFromJson(tClass: Class<T>, name: String): T {
val jsonText = Gdx.files.internal("jsons/$name.json").readString()
return Json().fromJson(tClass, jsonText)
}
private fun <T : INamed> createHashmap(items: Array<T>): LinqHashMap<String, T> {
val hashMap = LinqHashMap<String, T>()
for (item in items)
hashMap[item.name] = item
return hashMap
}
private fun setupGameBasics() {
GameBasics.Buildings = createHashmap(getFromJson(Array<Building>::class.java, "Buildings"))
GameBasics.Terrains = createHashmap(getFromJson(Array<Terrain>::class.java, "Terrains"))
GameBasics.TileResources = createHashmap(getFromJson(Array<TileResource>::class.java, "TileResources"))
GameBasics.TileImprovements = createHashmap(getFromJson(Array<TileImprovement>::class.java, "TileImprovements"))
GameBasics.Helps = createHashmap(getFromJson(Array<BasicHelp>::class.java, "BasicHelp"))
GameBasics.Units = createHashmap(getFromJson(Array<Unit>::class.java, "Units"))
GameBasics.PolicyBranches = createHashmap(getFromJson(Array<PolicyBranch>::class.java, "Policies"))
val techColumns = getFromJson(Array<TechColumn>::class.java, "Techs")
GameBasics.Technologies = LinqHashMap()
for (techColumn in techColumns) {
for (tech in techColumn.techs) {
tech.cost = techColumn.techCost
tech.column = techColumn
GameBasics.Technologies[tech.name] = tech
}
}
for (building in GameBasics.Buildings.values) {
if (building.requiredTech == null) continue
val column = building.getRequiredTech().column
if (building.cost == 0)
building.cost = if (building.isWonder) column!!.wonderCost else column!!.buildingCost
}
for (branch in GameBasics.PolicyBranches.values) {
branch.requires = Linq()
branch.branch = branch.name
for (policy in branch.policies) {
policy.branch = branch.name
if (policy.requires == null) {
policy.requires = Linq()
policy.requires!!.add(branch.name)
}
}
branch.policies[branch.policies.size - 1].name = branch.name + " Complete"
}
}
companion object {
lateinit var Current: UnCivGame
}
}

View file

@ -1,37 +0,0 @@
package com.unciv.ui;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.unciv.ui.utils.CameraStageBaseScreen;
public class VictoryScreen extends CameraStageBaseScreen{
public VictoryScreen() {
Table table = new Table();
Label label = new Label("A resounding victory!",skin);
label.setFontScale(2);
table.add(label).pad(20).row();
TextButton newGameButton = new TextButton("New game!",skin);
newGameButton.addListener(new ClickListener(){
@Override
public void clicked(InputEvent event, float x, float y) {
game.startNewGame();
}
});
table.add(newGameButton).pad(20).row();
table.pack();
table.setPosition((stage.getWidth()-table.getWidth())/2 , (stage.getHeight()-table.getHeight())/2 );
stage.addActor(table);
}
}

View file

@ -0,0 +1,30 @@
package com.unciv.ui
import com.badlogic.gdx.scenes.scene2d.ui.Label
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
import com.unciv.ui.cityscreen.addClickListener
import com.unciv.ui.utils.CameraStageBaseScreen
class VictoryScreen : CameraStageBaseScreen() {
init {
val table = Table()
val label = Label("A resounding victory!", CameraStageBaseScreen.skin)
label.setFontScale(2f)
table.add(label).pad(20f).row()
val newGameButton = TextButton("New game!", CameraStageBaseScreen.skin)
newGameButton.addClickListener { game.startNewGame() }
table.add(newGameButton).pad(20f).row()
table.pack()
table.setPosition((stage.width - table.width) / 2, (stage.height - table.height) / 2)
stage.addActor(table)
}
}

View file

@ -1,123 +0,0 @@
package com.unciv.ui.cityscreen;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.unciv.logic.city.CityInfo;
import com.unciv.models.gamebasics.Building;
import com.unciv.models.linq.Linq;
import com.unciv.models.stats.FullStats;
import com.unciv.ui.utils.CameraStageBaseScreen;
public class BuildingsTable extends Table {
final CityScreen cityScreen;
public BuildingsTable(CityScreen cityScreen) {
this.cityScreen = cityScreen;
}
private Image getSpecialistIcon(String imageName, final String building, final boolean isFilled, final FullStats specialistType) {
Image specialist = com.unciv.ui.utils.ImageGetter.getImage(imageName);
specialist.setSize(50,50);
if(!isFilled) specialist.setColor(Color.GRAY);
specialist.addListener(new ClickListener(){
@Override
public void clicked(InputEvent event, float x, float y) {
CityInfo cityInfo = cityScreen.city;
if(isFilled) cityInfo.population.buildingsSpecialists.get(building).add(specialistType.getMinus()); //unassign
else if(cityInfo.population.getFreePopulation()==0) return;
else {
if(!cityInfo.population.buildingsSpecialists.containsKey(building))
cityInfo.population.buildingsSpecialists.put(building,new FullStats());
cityInfo.population.buildingsSpecialists.get(building).add(specialistType); //assign!}
}
cityInfo.cityStats.update();
cityScreen.update();
}
});
return specialist;
}
void update(){
clear();
Skin skin = CameraStageBaseScreen.skin;
CityInfo cityInfo = cityScreen.city;
Linq<Building> Wonders = new Linq<Building>();
Linq<Building> SpecialistBuildings = new Linq<Building>();
Linq<Building> Others = new Linq<Building>();
for(Building building : cityInfo.cityConstructions.getBuiltBuildings()) {
if (building.isWonder) Wonders.add(building);
else if (building.specialistSlots != null) SpecialistBuildings.add(building);
else Others.add(building);
}
if(!Wonders.isEmpty()) {
Label label = new Label("Wonders", skin);
label.setFontScale(1.5f);
label.setColor(Color.GREEN);
add(label).pad(5).row();
for (Building building : Wonders)
add(new Label(building.name, skin)).pad(5).row();
}
if(!SpecialistBuildings.isEmpty()) {
Label label = new Label("Specialist Buildings", skin);
label.setFontScale(1.5f);
label.setColor(Color.GREEN);
add(label).pad(5).row();
for (Building building : SpecialistBuildings) {
add(new Label(building.name, skin)).pad(5);
Table specialists = new Table();
specialists.row().size(20).pad(5);
if (!cityInfo.population.buildingsSpecialists.containsKey(building.name))
cityInfo.population.buildingsSpecialists.put(building.name, new FullStats());
FullStats currentBuildingSpecialists = cityInfo.population.buildingsSpecialists.get(building.name);
for (int i = 0; i < building.specialistSlots.production; i++) {
specialists.add(getSpecialistIcon("StatIcons/populationBrown.png", building.name,
currentBuildingSpecialists.production > i, new FullStats() {{
production = 1;
}}));
}
for (int i = 0; i < building.specialistSlots.science; i++) {
specialists.add(getSpecialistIcon("StatIcons/populationBlue.png", building.name,
currentBuildingSpecialists.science > i, new FullStats() {{
science = 1;
}}));
}
for (int i = 0; i < building.specialistSlots.culture; i++) {
specialists.add(getSpecialistIcon("StatIcons/populationPurple.png", building.name,
currentBuildingSpecialists.culture > i, new FullStats() {{
culture = 1;
}}));
}
for (int i = 0; i < building.specialistSlots.gold; i++) {
specialists.add(getSpecialistIcon("StatIcons/populationYellow.png", building.name,
currentBuildingSpecialists.gold > i, new FullStats() {{
gold = 1;
}}));
}
add(specialists).row();
}
}
if(!Others.isEmpty()) {
Label label = new Label("Buildings", skin);
label.setFontScale(1.5f);
label.setColor(Color.GREEN);
add(label).pad(5).row();
for (Building building : Others)
add(new Label(building.name, skin)).pad(5).row();
}
pack();
}
}

View file

@ -0,0 +1,113 @@
package com.unciv.ui.cityscreen
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.Actor
import com.badlogic.gdx.scenes.scene2d.InputEvent
import com.badlogic.gdx.scenes.scene2d.ui.Image
import com.badlogic.gdx.scenes.scene2d.ui.Label
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener
import com.unciv.models.gamebasics.Building
import com.unciv.models.linq.Linq
import com.unciv.models.stats.Stat
import com.unciv.models.stats.Stats
import com.unciv.ui.utils.CameraStageBaseScreen
import com.unciv.ui.utils.ImageGetter.getImage
class BuildingsTable(private val cityScreen: CityScreen) : Table() {
internal fun update() {
clear()
val skin = CameraStageBaseScreen.skin
val cityInfo = cityScreen.city
val wonders = Linq<Building>()
val specialistBuildings = Linq<Building>()
val others = Linq<Building>()
for (building in cityInfo.cityConstructions.getBuiltBuildings()) {
when {
building.isWonder -> wonders.add(building)
building.specialistSlots != null -> specialistBuildings.add(building)
else -> others.add(building)
}
}
if (!wonders.isEmpty()) {
val label = Label("Wonders", skin)
label.setFontScale(1.5f)
label.color = Color.GREEN
add(label).pad(5f).row()
for (building in wonders)
add(Label(building.name, skin)).pad(5f).row()
}
if (!specialistBuildings.isEmpty()) {
val label = Label("Specialist Buildings", skin)
label.setFontScale(1.5f)
label.color = Color.GREEN
add(label).pad(5f).row()
for (building in specialistBuildings) {
add(Label(building.name, skin)).pad(5f)
val specialists = Table()
specialists.row().size(20f).pad(5f)
if (!cityInfo.population.buildingsSpecialists.containsKey(building.name))
cityInfo.population.buildingsSpecialists[building.name] = Stats()
val currentBuildingSpecialists = cityInfo.population.buildingsSpecialists[building.name]!!.toHashMap()
for(stat in Stat.values()){
for (i in 1..(currentBuildingSpecialists[stat]!!).toInt()) {
specialists.add(getSpecialistIcon(
"StatIcons/${stat}Specialist.png", building.name,
currentBuildingSpecialists[stat]!! > i, stat))
}
}
add(specialists).row()
}
}
if (!others.isEmpty()) {
val label = Label("Buildings", skin)
label.setFontScale(1.5f)
label.color = Color.GREEN
add(label).pad(5f).row()
for (building in others)
add(Label(building.name, skin)).pad(5f).row()
}
pack()
}
private fun getSpecialistIcon(imageName: String, building: String, isFilled: Boolean, stat: Stat): Image {
val specialist = getImage(imageName)
specialist.setSize(50f, 50f)
if (!isFilled) specialist.color = Color.GRAY
specialist.addClickListener( {
val cityInfo = cityScreen.city
when {
isFilled -> cityInfo.population.buildingsSpecialists[building]!!.add(stat,-1f) //unassign
cityInfo.population.freePopulation == 0 -> return@addClickListener
else -> {
if (!cityInfo.population.buildingsSpecialists.containsKey(building))
cityInfo.population.buildingsSpecialists[building] = Stats()
cityInfo.population.buildingsSpecialists[building]!!.add(stat,1f) //assign!}
}
}
cityInfo.cityStats.update()
cityScreen.update()
})
return specialist
}
}
fun Actor.addClickListener(function: () -> Unit) {
this.addListener(object : ClickListener() {
override fun clicked(event: InputEvent?, x: Float, y: Float) {
function()
}
} )
}

View file

@ -1,351 +0,0 @@
package com.unciv.ui.cityscreen;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.Group;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Touchable;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.utils.ActorGestureListener;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.badlogic.gdx.scenes.scene2d.utils.Drawable;
import com.badlogic.gdx.utils.Align;
import com.unciv.logic.city.CityInfo;
import com.unciv.logic.civilization.CivilizationInfo;
import com.unciv.logic.city.IConstruction;
import com.unciv.logic.map.TileInfo;
import com.unciv.ui.tilegroups.TileGroup;
import com.unciv.ui.utils.CameraStageBaseScreen;
import com.unciv.ui.utils.HexMath;
import com.unciv.models.linq.Linq;
import com.unciv.models.gamebasics.Building;
import com.unciv.models.stats.FullStats;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
public class CityScreen extends CameraStageBaseScreen {
final CityInfo city;
TileInfo selectedTile = null;
float buttonScale = game.settings.buttonScale;
Table tileTable = new Table();
BuildingsTable buildingsTable = new BuildingsTable(this);
Table cityStatsTable = new Table();
Table cityPickerTable = new Table();
TextButton goToWorldButton = new TextButton("Exit city",skin);
public ArrayList<TileGroup> tileGroups = new ArrayList<TileGroup>();
public CityScreen(CityInfo city) {
this.city = city;
new Label("",skin).getStyle().font.getData().setScale(game.settings.labelScale);
addTiles();
stage.addActor(tileTable);
Drawable tileTableBackground = com.unciv.ui.utils.ImageGetter.getDrawable("skin/tileTableBackground.png")
.tint(new Color(0x0040804f));
tileTableBackground.setMinHeight(0);
tileTableBackground.setMinWidth(0);
tileTable.setBackground(tileTableBackground);
Table BuildingsTableContainer = new Table();
BuildingsTableContainer.pad(20);
BuildingsTableContainer.setBackground(tileTableBackground);
//BuildingsTableContainer.add(new Label("Buildings",skin)).row();
buildingsTable.update();
ScrollPane buildingsScroll = new ScrollPane(buildingsTable);
BuildingsTableContainer.add(buildingsScroll).height(stage.getHeight()/2);
BuildingsTableContainer.pack();
BuildingsTableContainer.setPosition(stage.getWidth()-BuildingsTableContainer.getWidth(),
stage.getHeight()-BuildingsTableContainer.getHeight());
cityStatsTable.setBackground(tileTableBackground);
stage.addActor(cityStatsTable);
stage.addActor(goToWorldButton);
stage.addActor(cityPickerTable);
stage.addActor(BuildingsTableContainer);
update();
Linq<String> tutorial = new Linq<String>();
tutorial.add("Welcome to your first city!" +
"\r\nAs on now, you only have 1 population," +
"\r\n but this will grow when you amass enough surplus food");
tutorial.add("Similarly, your city's borders grow when you" +
"\r\n amass enough culture, which is not generated" +
"\r\n by tiles but rather by buildings.");
tutorial.add("Each population in your city can work" +
"\r\n a single tile, providing the city with that tile's yields.");
tutorial.add("Population can be assigned and unassigned" +
"\r\n by clicking on the green population symbols on the tiles - " +
"\r\n but of course, you can only assign population" +
"\r\n if you have idle population to spare!");
tutorial.add("The center tile off a city is always worked," +
"\r\n and doesn't require population," +
"\r\n but it cannot be improved by tile improvements.");
tutorial.add("The city's production always goes towards the" +
"\r\n current construction - you can pick the city's" +
"\r\n construction by clicking on the construction" +
"\r\n button on the bottom-left");
displayTutorials("CityEntered",tutorial);
}
void update(){
buildingsTable.update();
updateCityPickerTable();
updateCityTable();
updateGoToWorldButton();
updateTileTable();
updateTileGroups();
}
private void updateTileGroups(){
for(TileGroup HG : tileGroups) {
HG.update();
}
}
private void updateCityPickerTable() {
cityPickerTable.clear();
cityPickerTable.row().pad(20);
final CivilizationInfo civInfo = city.civInfo;
if(civInfo.cities.size()>1) {
TextButton prevCityButton = new TextButton("<", skin);
prevCityButton.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
int indexOfCity = civInfo.cities.indexOf(city);
int indexOfNextCity = indexOfCity == 0 ? civInfo.cities.size() - 1 : indexOfCity-1;
game.setScreen(new CityScreen(civInfo.cities.get(indexOfNextCity)));
dispose();
}
});
cityPickerTable.add(prevCityButton);
}
Label currentCityLabel = new Label(city.name, skin);
currentCityLabel.setFontScale(2);
cityPickerTable.add(currentCityLabel);
if(civInfo.cities.size()>1) {
TextButton nextCityButton = new TextButton(">", skin);
nextCityButton.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
int indexOfCity = civInfo.cities.indexOf(city);
int indexOfNextCity = indexOfCity == civInfo.cities.size() - 1 ? 0 : indexOfCity+1;
game.setScreen(new CityScreen(civInfo.cities.get(indexOfNextCity)));
dispose();
}
});
cityPickerTable.add(nextCityButton);
}
cityPickerTable.pack();
cityPickerTable.setPosition(stage.getWidth()/2- cityPickerTable.getWidth()/2,0);
stage.addActor(cityPickerTable);
}
private void updateGoToWorldButton() {
goToWorldButton.clearListeners();
goToWorldButton.addListener(new ClickListener(){
@Override
public void clicked(InputEvent event, float x, float y) {
game.setWorldScreen();
game.worldScreen.tileMapHolder.setCenterPosition(city.cityLocation);
dispose();
}
});
goToWorldButton.setSize(goToWorldButton.getPrefWidth(), goToWorldButton.getPrefHeight());
goToWorldButton.setPosition(10, stage.getHeight() - goToWorldButton.getHeight()-5);
}
private void addTiles() {
final CityInfo cityInfo = city;
Group allTiles = new Group();
for(final TileInfo tileInfo : game.gameInfo.tileMap.getTilesInDistance(cityInfo.cityLocation,5)){
if(!tileInfo.explored) continue; // Don't even bother to display it.
CityTileGroup group = new CityTileGroup(cityInfo, tileInfo);
group.addListener(new ClickListener(){
@Override
public void clicked(InputEvent event, float x, float y) {
selectedTile = tileInfo;
update();
}
});
if(!cityInfo.getTilesInRange().contains(tileInfo) ||
(tileInfo.workingCity!=null && !tileInfo.workingCity.equals(cityInfo.name))) {
group.setColor(0, 0, 0, 0.3f);
group.yield.setVisible(false);
}
else if(!tileInfo.isCityCenter()) {
group.addPopulationIcon();
group.populationImage.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
if(tileInfo.workingCity ==null && cityInfo.population.getFreePopulation() > 0) tileInfo.workingCity = cityInfo.name;
else if(cityInfo.name.equals(tileInfo.workingCity)) tileInfo.workingCity = null;
cityInfo.cityStats.update();
update();
}
});
}
Vector2 positionalVector = HexMath.Hex2WorldCoords(tileInfo.position.cpy().sub(cityInfo.cityLocation));
int groupSize = 50;
group.setPosition(stage.getWidth()/2 + positionalVector.x*0.8f * groupSize,
stage.getHeight()/2 + positionalVector.y*0.8f * groupSize);
tileGroups.add(group);
allTiles.addActor(group);
}
final ScrollPane scrollPane = new ScrollPane(allTiles);
scrollPane.setFillParent(true);
scrollPane.setPosition(game.settings.cityTilesX, game.settings.cityTilesY);
scrollPane.setOrigin(stage.getWidth()/2,stage.getHeight()/2);
scrollPane.addListener(new ActorGestureListener(){
public float lastScale =1;
float lastInitialDistance=0;
@Override
public void zoom(InputEvent event, float initialDistance, float distance) {
if(lastInitialDistance!=initialDistance){
lastInitialDistance = initialDistance;
lastScale = scrollPane.getScaleX();
}
float scale = (float) Math.sqrt(distance/initialDistance)* lastScale;
scrollPane.setScale(scale);
}
@Override
public void pan(InputEvent event, float x, float y, float deltaX, float deltaY) {
scrollPane.moveBy(deltaX*scrollPane.getScaleX(),deltaY*scrollPane.getScaleX());
game.settings.cityTilesX = scrollPane.getX();
game.settings.cityTilesY = scrollPane.getY();
}
});
stage.addActor(scrollPane);
}
private void updateCityTable() {
FullStats stats = city.cityStats.currentCityStats;
cityStatsTable.pad(20);
cityStatsTable.columnDefaults(0).padRight(10);
cityStatsTable.clear();
Label cityStatsHeader = new Label("City Stats",skin);
cityStatsHeader.setFontScale(2);
cityStatsTable.add(cityStatsHeader).colspan(2).pad(10);
cityStatsTable.row();
HashMap<String,String> CityStatsValues = new LinkedHashMap<String, String>();
CityStatsValues.put("Production",Math.round(stats.production)
+city.cityConstructions.getAmountConstructedText());
CityStatsValues.put("Food",Math.round(stats.food)
+" ("+city.population.foodStored+"/"+city.population.foodToNextPopulation()+")");
CityStatsValues.put("Gold",Math.round(stats.gold) +"");
CityStatsValues.put("Science",Math.round(stats.science) +"");
CityStatsValues.put("Culture",Math.round(stats.culture)
+" ("+city.expansion.cultureStored+"/"+city.expansion.getCultureToNextTile()+")");
CityStatsValues.put("Population",city.population.getFreePopulation()+"/"+city.population.population);
for(String key : CityStatsValues.keySet()){
cityStatsTable.add(com.unciv.ui.utils.ImageGetter.getStatIcon(key)).align(Align.right);
cityStatsTable.add(new Label(CityStatsValues.get(key),skin)).align(Align.left);
cityStatsTable.row();
}
String CurrentBuilding = city.cityConstructions.currentConstruction;
String BuildingText = "Pick building";
if(CurrentBuilding != null) BuildingText = city.cityConstructions.getCityProductionTextForCityButton();
TextButton buildingPickButton = new TextButton(BuildingText,skin);
buildingPickButton.addListener(new ClickListener(){
@Override
public void clicked(InputEvent event, float x, float y) {
game.setScreen(new com.unciv.ui.pickerscreens.ConstructionPickerScreen(city));
dispose();
}
});
buildingPickButton.getLabel().setFontScale(buttonScale);
cityStatsTable.add(buildingPickButton).colspan(2).pad(10)
.size(buildingPickButton.getWidth()*buttonScale,buildingPickButton.getHeight()*buttonScale);
// https://forums.civfanatics.com/threads/rush-buying-formula.393892/
IConstruction construction = city.cityConstructions.getCurrentConstruction();
if(construction != null && !(construction instanceof Building && ((Building)construction).isWonder)) {
cityStatsTable.row();
int buildingGoldCost = construction.getGoldCost(city.civInfo.policies.getAdoptedPolicies());
TextButton buildingBuyButton = new TextButton("Buy for \r\n"+buildingGoldCost+" gold", skin);
buildingBuyButton.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
city.cityConstructions.purchaseBuilding(city.cityConstructions.currentConstruction);
update();
}
});
if(buildingGoldCost > city.civInfo.gold){
buildingBuyButton.setColor(Color.GRAY);
buildingBuyButton.setTouchable(Touchable.disabled);
}
buildingBuyButton.getLabel().setFontScale(buttonScale);
cityStatsTable.add(buildingBuyButton).colspan(2).pad(10)
.size(buildingBuyButton.getWidth() * buttonScale, buildingBuyButton.getHeight() * buttonScale);
}
cityStatsTable.setPosition(10,10);
cityStatsTable.pack();
}
private void updateTileTable() {
if(selectedTile == null) return;
tileTable.clearChildren();
FullStats stats = selectedTile.getTileStats(city,city.civInfo);
tileTable.pad(20);
tileTable.columnDefaults(0).padRight(10);
Label cityStatsHeader = new Label("Tile Stats",skin);
cityStatsHeader.setFontScale(2);
tileTable.add(cityStatsHeader).colspan(2).pad(10);
tileTable.row();
tileTable.add(new Label(selectedTile.toString(),skin)).colspan(2);
tileTable.row();
HashMap<String,Float> TileStatsValues = new HashMap<String, Float>();
TileStatsValues.put("Production",stats.production);
TileStatsValues.put("Food",stats.food);
TileStatsValues.put("Gold",stats.gold);
TileStatsValues.put("Science",stats.science);
TileStatsValues.put("Culture",stats.culture);
for(String key : TileStatsValues.keySet()){
if(TileStatsValues.get(key) == 0) continue; // this tile gives nothing of this stat, so why even display it?
tileTable.add(com.unciv.ui.utils.ImageGetter.getStatIcon(key)).align(Align.right);
tileTable.add(new Label(Math.round(TileStatsValues.get(key))+"",skin)).align(Align.left);
tileTable.row();
}
tileTable.pack();
tileTable.setPosition(stage.getWidth()-10- tileTable.getWidth(), 10);
}
}

View file

@ -0,0 +1,301 @@
package com.unciv.ui.cityscreen
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.Group
import com.badlogic.gdx.scenes.scene2d.InputEvent
import com.badlogic.gdx.scenes.scene2d.Touchable
import com.badlogic.gdx.scenes.scene2d.ui.*
import com.badlogic.gdx.scenes.scene2d.utils.ActorGestureListener
import com.badlogic.gdx.utils.Align
import com.unciv.logic.city.CityInfo
import com.unciv.logic.map.TileInfo
import com.unciv.models.gamebasics.Building
import com.unciv.models.linq.Linq
import com.unciv.ui.tilegroups.TileGroup
import com.unciv.ui.utils.CameraStageBaseScreen
import com.unciv.ui.utils.HexMath
import com.unciv.ui.utils.ImageGetter
import java.util.*
class CityScreen(internal val city: CityInfo) : CameraStageBaseScreen() {
private var selectedTile: TileInfo? = null
private var buttonScale = game.settings.buttonScale
private var tileTable = Table()
private var buildingsTable = BuildingsTable(this)
private var cityStatsTable = Table()
private var cityPickerTable = Table()
private var goToWorldButton = TextButton("Exit city", CameraStageBaseScreen.skin)
private var tileGroups = ArrayList<TileGroup>()
init {
Label("", CameraStageBaseScreen.skin).style.font.data.setScale(game.settings.labelScale)
addTiles()
stage.addActor(tileTable)
val tileTableBackground = com.unciv.ui.utils.ImageGetter.getDrawable("skin/tileTableBackground.png")
.tint(Color(0x0040804f))
tileTableBackground.minHeight = 0f
tileTableBackground.minWidth = 0f
tileTable.background = tileTableBackground
val buildingsTableContainer = Table()
buildingsTableContainer.pad(20f)
buildingsTableContainer.background = tileTableBackground
//BuildingsTableContainer.add(new Label("Buildings",skin)).row();
buildingsTable.update()
val buildingsScroll = ScrollPane(buildingsTable)
buildingsTableContainer.add(buildingsScroll).height(stage.height / 2)
buildingsTableContainer.pack()
buildingsTableContainer.setPosition(stage.width - buildingsTableContainer.width,
stage.height - buildingsTableContainer.height)
cityStatsTable.background = tileTableBackground
stage.addActor(cityStatsTable)
stage.addActor(goToWorldButton)
stage.addActor(cityPickerTable)
stage.addActor(buildingsTableContainer)
update()
val tutorial = Linq<String>()
tutorial.add("Welcome to your first city!" +
"\r\nAs on now, you only have 1 population," +
"\r\n but this will grow when you amass enough surplus food")
tutorial.add("Similarly, your city's borders grow when you" +
"\r\n amass enough culture, which is not generated" +
"\r\n by tiles but rather by buildings.")
tutorial.add("Each population in your city can work" + "\r\n a single tile, providing the city with that tile's yields.")
tutorial.add("Population can be assigned and unassigned" +
"\r\n by clicking on the green population symbols on the tiles - " +
"\r\n but of course, you can only assign population" +
"\r\n if you have idle population to spare!")
tutorial.add("The center tile off a city is always worked," +
"\r\n and doesn't require population," +
"\r\n but it cannot be improved by tile improvements.")
tutorial.add("The city's production always goes towards the" +
"\r\n current construction - you can pick the city's" +
"\r\n construction by clicking on the construction" +
"\r\n button on the bottom-left")
displayTutorials("CityEntered", tutorial)
}
internal fun update() {
buildingsTable.update()
updateCityPickerTable()
updateCityTable()
updateGoToWorldButton()
updateTileTable()
updateTileGroups()
}
private fun updateTileGroups() {
for (HG in tileGroups) {
HG.update()
}
}
private fun updateCityPickerTable() {
cityPickerTable.clear()
cityPickerTable.row().pad(20f)
val civInfo = city.civInfo
if (civInfo.cities.size > 1) {
val prevCityButton = TextButton("<", CameraStageBaseScreen.skin)
prevCityButton.addClickListener {
val indexOfCity = civInfo.cities.indexOf(city)
val indexOfNextCity = if (indexOfCity == 0) civInfo.cities.size - 1 else indexOfCity - 1
game.screen = CityScreen(civInfo.cities[indexOfNextCity])
dispose()
}
cityPickerTable.add(prevCityButton)
}
val currentCityLabel = Label(city.name, CameraStageBaseScreen.skin)
currentCityLabel.setFontScale(2f)
cityPickerTable.add(currentCityLabel)
if (civInfo.cities.size > 1) {
val nextCityButton = TextButton(">", CameraStageBaseScreen.skin)
nextCityButton.addClickListener {
val indexOfCity = civInfo.cities.indexOf(city)
val indexOfNextCity = if (indexOfCity == civInfo.cities.size - 1) 0 else indexOfCity + 1
game.screen = CityScreen(civInfo.cities[indexOfNextCity])
dispose()
}
cityPickerTable.add(nextCityButton)
}
cityPickerTable.pack()
cityPickerTable.setPosition(stage.width / 2 - cityPickerTable.width / 2, 0f)
stage.addActor(cityPickerTable)
}
private fun updateGoToWorldButton() {
goToWorldButton.clearListeners()
goToWorldButton.addClickListener {
game.setWorldScreen()
game.worldScreen!!.tileMapHolder.setCenterPosition(city.cityLocation)
dispose()
}
goToWorldButton.setSize(goToWorldButton.prefWidth, goToWorldButton.prefHeight)
goToWorldButton.setPosition(10f, stage.height - goToWorldButton.height - 5f)
}
private fun addTiles() {
val cityInfo = city
val allTiles = Group()
for (tileInfo in game.gameInfo.tileMap.getTilesInDistance(cityInfo.cityLocation, 5)) {
if (!tileInfo.explored) continue // Don't even bother to display it.
val group = CityTileGroup(cityInfo, tileInfo)
group.addClickListener {
selectedTile = tileInfo
update()
}
if (!cityInfo.tilesInRange.contains(tileInfo) || tileInfo.workingCity != null && tileInfo.workingCity != cityInfo.name) {
group.setColor(0f, 0f, 0f, 0.3f)
group.yieldGroup.isVisible = false
} else if (!tileInfo.isCityCenter) {
group.addPopulationIcon()
group.populationImage!!.addClickListener {
if (tileInfo.workingCity == null && cityInfo.population.freePopulation > 0)
tileInfo.workingCity = cityInfo.name
else if (cityInfo.name == tileInfo.workingCity) tileInfo.workingCity = null
cityInfo.cityStats.update()
update()
}
}
val positionalVector = HexMath.Hex2WorldCoords(tileInfo.position.cpy().sub(cityInfo.cityLocation))
val groupSize = 50
group.setPosition(stage.width / 2 + positionalVector.x * 0.8f * groupSize.toFloat(),
stage.height / 2 + positionalVector.y * 0.8f * groupSize.toFloat())
tileGroups.add(group)
allTiles.addActor(group)
}
val scrollPane = ScrollPane(allTiles)
scrollPane.setFillParent(true)
scrollPane.setPosition(game.settings.cityTilesX, game.settings.cityTilesY)
scrollPane.setOrigin(stage.width / 2, stage.height / 2)
scrollPane.addListener(object : ActorGestureListener() {
var lastScale = 1f
internal var lastInitialDistance = 0f
override fun zoom(event: InputEvent?, initialDistance: Float, distance: Float) {
if (lastInitialDistance != initialDistance) {
lastInitialDistance = initialDistance
lastScale = scrollPane.scaleX
}
val scale = Math.sqrt((distance / initialDistance).toDouble()).toFloat() * lastScale
scrollPane.setScale(scale)
}
override fun pan(event: InputEvent?, x: Float, y: Float, deltaX: Float, deltaY: Float) {
scrollPane.moveBy(deltaX * scrollPane.scaleX, deltaY * scrollPane.scaleX)
game.settings.cityTilesX = scrollPane.x
game.settings.cityTilesY = scrollPane.y
}
})
stage.addActor(scrollPane)
}
private fun updateCityTable() {
val stats = city.cityStats.currentCityStats
cityStatsTable.pad(20f)
cityStatsTable.columnDefaults(0).padRight(10f)
cityStatsTable.clear()
val cityStatsHeader = Label("City Stats", CameraStageBaseScreen.skin)
cityStatsHeader.setFontScale(2f)
cityStatsTable.add(cityStatsHeader).colspan(2).pad(10f)
cityStatsTable.row()
val cityStatsValues = LinkedHashMap<String, String>()
cityStatsValues["Production"] = Math.round(stats.production).toString() + city.cityConstructions.getAmountConstructedText()
cityStatsValues["Food"] = (Math.round(stats.food).toString()
+ " (" + city.population.foodStored + "/" + city.population.foodToNextPopulation + ")")
cityStatsValues["Gold"] = Math.round(stats.gold).toString() + ""
cityStatsValues["Science"] = Math.round(stats.science).toString() + ""
cityStatsValues["Culture"] = (Math.round(stats.culture).toString()
+ " (" + city.expansion.cultureStored + "/" + city.expansion.cultureToNextTile + ")")
cityStatsValues["Population"] = city.population.freePopulation.toString() + "/" + city.population.population
for (key in cityStatsValues.keys) {
cityStatsTable.add<Image>(com.unciv.ui.utils.ImageGetter.getStatIcon(key)).align(Align.right)
cityStatsTable.add(Label(cityStatsValues[key], CameraStageBaseScreen.skin)).align(Align.left)
cityStatsTable.row()
}
val buildingText = city.cityConstructions.getCityProductionTextForCityButton()
val buildingPickButton = TextButton(buildingText, CameraStageBaseScreen.skin)
buildingPickButton.addClickListener {
game.screen = com.unciv.ui.pickerscreens.ConstructionPickerScreen(city)
dispose()
}
buildingPickButton.label.setFontScale(buttonScale)
cityStatsTable.add(buildingPickButton).colspan(2).pad(10f)
.size(buildingPickButton.width * buttonScale, buildingPickButton.height * buttonScale)
// https://forums.civfanatics.com/threads/rush-buying-formula.393892/
val construction = city.cityConstructions.getCurrentConstruction()
if (!(construction is Building && construction.isWonder)) {
cityStatsTable.row()
val buildingGoldCost = construction.getGoldCost(city.civInfo.policies.getAdoptedPolicies())
val buildingBuyButton = TextButton("Buy for \r\n$buildingGoldCost gold", CameraStageBaseScreen.skin)
buildingBuyButton.addClickListener {
city.cityConstructions.purchaseBuilding(city.cityConstructions.currentConstruction)
update()
}
if (buildingGoldCost > city.civInfo.gold) {
buildingBuyButton.color = Color.GRAY
buildingBuyButton.touchable = Touchable.disabled
}
buildingBuyButton.label.setFontScale(buttonScale)
cityStatsTable.add(buildingBuyButton).colspan(2).pad(10f)
.size(buildingBuyButton.width * buttonScale, buildingBuyButton.height * buttonScale)
}
cityStatsTable.setPosition(10f, 10f)
cityStatsTable.pack()
}
private fun updateTileTable() {
if (selectedTile == null) return
tileTable.clearChildren()
val stats = selectedTile!!.getTileStats(city, city.civInfo)
tileTable.pad(20f)
tileTable.columnDefaults(0).padRight(10f)
val cityStatsHeader = Label("Tile Stats", CameraStageBaseScreen.skin)
cityStatsHeader.setFontScale(2f)
tileTable.add(cityStatsHeader).colspan(2).pad(10f)
tileTable.row()
tileTable.add(Label(selectedTile!!.toString(), CameraStageBaseScreen.skin)).colspan(2)
tileTable.row()
for (entry in stats.toHashMap().filterNot { it.value==0f }) {
tileTable.add<Image>(ImageGetter.getStatIcon(entry.key.toString())).align(Align.right)
tileTable.add(Label(Math.round(entry.value).toString() + "", CameraStageBaseScreen.skin)).align(Align.left)
tileTable.row()
}
tileTable.pack()
tileTable.setPosition(stage.width - 10f - tileTable.width, 10f)
}
}

View file

@ -1,47 +0,0 @@
package com.unciv.ui.cityscreen;
import com.badlogic.gdx.utils.Align;
import com.unciv.logic.city.CityInfo;
import com.unciv.logic.map.TileInfo;
import com.unciv.ui.tilegroups.TileGroup;
import com.unciv.ui.utils.ImageGetter;
public class CityTileGroup extends TileGroup {
public YieldGroup yield = new YieldGroup();
private final CityInfo city;
public CityTileGroup(CityInfo city, TileInfo tileInfo) {
super(tileInfo);
this.city = city;
addActor(yield);
if(city.cityLocation.equals(tileInfo.position)){
populationImage = ImageGetter.getImage("StatIcons/City_Center_(Civ6).png");
addActor(populationImage);
}
}
public void update(){
super.update();
if(populationImage!=null) {
populationImage.setSize(30, 30);
populationImage.setPosition(getWidth()/2-populationImage.getWidth()/2,
getHeight()*0.85f-populationImage.getHeight()/2);
}
if(improvementImage!=null) improvementImage.setColor(1, 1, 1, 0.5f);
if(unitImage!=null) unitImage.setColor(1, 1, 1, 0.5f);
if(resourceImage!=null) resourceImage.setColor(1, 1, 1, 0.5f);
yield.setStats(tileInfo.getTileStats(city,city.civInfo.gameInfo.getPlayerCivilization()));
yield.setOrigin(Align.center);
yield.setScale(0.7f);
yield.toFront();
yield.setPosition(getWidth() / 2 - yield.getWidth() / 2, getHeight() *0.25f - yield.getHeight() / 2);
}
}

View file

@ -0,0 +1,45 @@
package com.unciv.ui.cityscreen
import com.badlogic.gdx.utils.Align
import com.unciv.logic.city.CityInfo
import com.unciv.logic.map.TileInfo
import com.unciv.ui.tilegroups.TileGroup
import com.unciv.ui.utils.ImageGetter
class CityTileGroup : TileGroup {
private val city: CityInfo
constructor(city: CityInfo, tileInfo: TileInfo) : super(tileInfo) {
this.city = city
this.yieldGroup = YieldGroup()
addActor(yieldGroup)
if (city.cityLocation == tileInfo.position) {
populationImage = ImageGetter.getImage("StatIcons/City_Center_(Civ6).png")
addActor(populationImage)
}
}
var yieldGroup: YieldGroup
override fun update() {
super.update()
if (populationImage != null) {
populationImage!!.setSize(30f, 30f)
populationImage!!.setPosition(width / 2 - populationImage!!.width / 2,
height * 0.85f - populationImage!!.height / 2)
}
if (improvementImage != null) improvementImage!!.setColor(1f, 1f, 1f, 0.5f)
if (unitImage != null) unitImage!!.setColor(1f, 1f, 1f, 0.5f)
if (resourceImage != null) resourceImage!!.setColor(1f, 1f, 1f, 0.5f)
yieldGroup.setStats(tileInfo.getTileStats(city, city.civInfo.gameInfo.getPlayerCivilization()))
yieldGroup.setOrigin(Align.center)
yieldGroup.setScale(0.7f)
yieldGroup.toFront()
yieldGroup.setPosition(width / 2 - yieldGroup.width / 2, height * 0.25f - yieldGroup.height / 2)
}
}

View file

@ -1,50 +0,0 @@
package com.unciv.ui.cityscreen;
import com.badlogic.gdx.scenes.scene2d.ui.HorizontalGroup;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.unciv.models.stats.FullStats;
import com.unciv.ui.utils.ImageGetter;
import java.util.HashMap;
public class YieldGroup extends HorizontalGroup {
public void setStats(FullStats stats) {
clearChildren();
HashMap<String,Integer> dict = stats.toDict();
for(String key : dict.keySet()){
int value = dict.get(key);
if(value >0) addActor(getStatTable(key,value));
}
pack();
}
Table getStatTable(String statName, int number){
Table table = new Table();
if(number==1){
table.add(ImageGetter.getStatIcon(statName));
}
else if(number==2){
table.add(ImageGetter.getStatIcon(statName)).row();
table.add(ImageGetter.getStatIcon(statName));
}
else if(number==3){
table.add(ImageGetter.getStatIcon(statName)).colspan(2).row();
table.add(ImageGetter.getStatIcon(statName));
table.add(ImageGetter.getStatIcon(statName));
}
else if(number==4){
table.add(ImageGetter.getStatIcon(statName));
table.add(ImageGetter.getStatIcon(statName)).row();
table.add(ImageGetter.getStatIcon(statName));
table.add(ImageGetter.getStatIcon(statName));
}
else{
Image largeImage = ImageGetter.getStatIcon(statName);
table.add(largeImage).size(largeImage.getWidth()*1.5f, largeImage.getHeight()*1.5f);
}
table.pack();
return table;
}
}

View file

@ -0,0 +1,45 @@
package com.unciv.ui.cityscreen
import com.badlogic.gdx.scenes.scene2d.ui.HorizontalGroup
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.unciv.models.stats.Stats
import com.unciv.ui.utils.ImageGetter
class YieldGroup : HorizontalGroup() {
fun setStats(stats: Stats) {
clearChildren()
for (entry in stats.toHashMap().filter { it.value>0 }) {
addActor(getStatIconsTable(entry.key.toString(), entry.value.toInt()))
}
pack()
}
private fun getStatIconsTable(statName: String, number: Int): Table {
val table = Table()
when (number) {
1 -> table.add(ImageGetter.getStatIcon(statName))
2 -> {
table.add(ImageGetter.getStatIcon(statName)).row()
table.add(ImageGetter.getStatIcon(statName))
}
3 -> {
table.add(ImageGetter.getStatIcon(statName)).colspan(2).row()
table.add(ImageGetter.getStatIcon(statName))
table.add(ImageGetter.getStatIcon(statName))
}
4 -> {
table.add(ImageGetter.getStatIcon(statName))
table.add(ImageGetter.getStatIcon(statName)).row()
table.add(ImageGetter.getStatIcon(statName))
table.add(ImageGetter.getStatIcon(statName))
}
else -> {
val largeImage = ImageGetter.getStatIcon(statName)
table.add(largeImage).size(largeImage.width * 1.5f, largeImage.height * 1.5f)
}
}
table.pack()
return table
}
}

View file

@ -1,94 +0,0 @@
package com.unciv.ui.pickerscreens;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.ui.VerticalGroup;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.unciv.logic.city.CityConstructions;
import com.unciv.logic.city.CityInfo;
import com.unciv.logic.civilization.CivilizationInfo;
import com.unciv.models.gamebasics.Unit;
import com.unciv.ui.cityscreen.CityScreen;
import com.unciv.models.gamebasics.Building;
import com.unciv.models.gamebasics.GameBasics;
public class ConstructionPickerScreen extends PickerScreen {
public final CityInfo city;
public String selectedProduction;
TextButton getProductionButton(final String production, String buttonText,
final String description, final String rightSideButtonText){
TextButton TB = new TextButton(buttonText, skin);
TB.addListener(new ClickListener(){
@Override
public void clicked(InputEvent event, float x, float y) {
selectedProduction = production;
pick(rightSideButtonText);
descriptionLabel.setText(description);
}
});
return TB;
}
public ConstructionPickerScreen(final CityInfo city) {
this.city = city;
final CivilizationInfo civInfo = game.gameInfo.getPlayerCivilization();
closeButton.clearListeners(); // Don't go back to the world screen, unlike the other picker screens!
closeButton.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
game.setScreen(new CityScreen(ConstructionPickerScreen.this.city));
dispose();
}
});
rightSideButton.setText("Pick building");
rightSideButton.addListener(new ClickListener(){
@Override
public void clicked(InputEvent event, float x, float y) {
city.cityConstructions.currentConstruction = selectedProduction;
city.cityStats.update(); // Because maybe we set/removed the science or gold production options.
game.setScreen(new CityScreen(ConstructionPickerScreen.this.city));
dispose();
}
});
CityConstructions cityConstructions = city.cityConstructions;
VerticalGroup regularBuildings = new VerticalGroup().space(10),
wonders = new VerticalGroup().space(10),
units = new VerticalGroup().space(10),
specials = new VerticalGroup().space(10);
for(final Building building : GameBasics.Buildings.values()) {
if(!building.isBuildable(cityConstructions)) continue;
TextButton TB = getProductionButton(building.name,
building.name +"\r\n"+cityConstructions.turnsToConstruction(building.name)+" turns",
building.getDescription(true,civInfo.policies.getAdoptedPolicies()),
"Build "+building.name);
if(building.isWonder) wonders.addActor(TB);
else regularBuildings.addActor(TB);
}
for(Unit unit : GameBasics.Units.values()){
if(!unit.isConstructable()) continue;
units.addActor(getProductionButton(unit.name,
unit.name+"\r\n"+cityConstructions.turnsToConstruction(unit.name)+" turns",
unit.description, "Train "+unit.name));
}
if(civInfo.tech.isResearched("Education"))
specials.addActor(getProductionButton("Science","Produce Science",
"Convert production to science at a rate of 4 to 1", "Produce Science"));
if(civInfo.tech.isResearched("Currency"))
specials.addActor(getProductionButton("Gold","Produce Gold",
"Convert production to gold at a rate of 4 to 1", "Produce Gold"));
topTable.add(units);
topTable.add(regularBuildings);
topTable.add(wonders);
topTable.add(specials);
}
}

View file

@ -0,0 +1,87 @@
package com.unciv.ui.pickerscreens
import com.badlogic.gdx.scenes.scene2d.InputEvent
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
import com.badlogic.gdx.scenes.scene2d.ui.VerticalGroup
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener
import com.unciv.logic.city.CityInfo
import com.unciv.models.gamebasics.GameBasics
import com.unciv.ui.cityscreen.CityScreen
import com.unciv.ui.utils.CameraStageBaseScreen
class ConstructionPickerScreen(val city: CityInfo) : PickerScreen() {
var selectedProduction: String?=null
private fun getProductionButton(production: String, buttonText: String,
description: String?, rightSideButtonText: String): TextButton {
val productionTextButton = TextButton(buttonText, CameraStageBaseScreen.skin)
productionTextButton.addListener(object : ClickListener() {
override fun clicked(event: InputEvent?, x: Float, y: Float) {
selectedProduction = production
pick(rightSideButtonText)
descriptionLabel.setText(description)
}
})
return productionTextButton
}
init {
val civInfo = game.gameInfo.getPlayerCivilization()
closeButton.clearListeners() // Don't go back to the world screen, unlike the other picker screens!
closeButton.addListener(object : ClickListener() {
override fun clicked(event: InputEvent?, x: Float, y: Float) {
game.screen = CityScreen(this@ConstructionPickerScreen.city)
dispose()
}
})
rightSideButton.setText("Pick building")
rightSideButton.addListener(object : ClickListener() {
override fun clicked(event: InputEvent?, x: Float, y: Float) {
city.cityConstructions.currentConstruction = selectedProduction!!
city.cityStats.update() // Because maybe we set/removed the science or gold production options.
game.screen = CityScreen(this@ConstructionPickerScreen.city)
dispose()
}
})
val cityConstructions = city.cityConstructions
val regularBuildings = VerticalGroup().space(10f)
val wonders = VerticalGroup().space(10f)
val units = VerticalGroup().space(10f)
val specials = VerticalGroup().space(10f)
for (building in GameBasics.Buildings.values) {
if (!building.isBuildable(cityConstructions)) continue
val productionTextButton = getProductionButton(building.name,
building.name + "\r\n" + cityConstructions.turnsToConstruction(building.name) + " turns",
building.getDescription(true, civInfo.policies.getAdoptedPolicies()),
"Build " + building.name)
if (building.isWonder)
wonders.addActor(productionTextButton)
else
regularBuildings.addActor(productionTextButton)
}
for (unit in GameBasics.Units.values.filter { it.isConstructable }) {
units.addActor(getProductionButton(unit.name,
unit.name + "\r\n" + cityConstructions.turnsToConstruction(unit.name) + " turns",
unit.description, "Train " + unit.name))
}
if (civInfo.tech.isResearched("Education"))
specials.addActor(getProductionButton("Science", "Produce Science",
"Convert production to science at a rate of 4 to 1", "Produce Science"))
if (civInfo.tech.isResearched("Currency"))
specials.addActor(getProductionButton("Gold", "Produce Gold",
"Convert production to gold at a rate of 4 to 1", "Produce Gold"))
topTable.add(units)
topTable.add(regularBuildings)
topTable.add(wonders)
topTable.add(specials)
}
}

View file

@ -1,35 +0,0 @@
package com.unciv.ui.pickerscreens;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.unciv.logic.civilization.CivilizationInfo;
import com.unciv.models.gamebasics.Unit;
import com.unciv.models.gamebasics.GameBasics;
public class GreatPersonPickerScreen extends PickerScreen{
Unit theChosenOne;
CivilizationInfo civInfo;
public GreatPersonPickerScreen(){
rightSideButton.setText("Choose a free great person");
for(final Unit unit : GameBasics.Units.linqValues()){
if(!unit.name.startsWith("Great")) continue;
TextButton button = new TextButton(unit.name,skin);
button.addListener(new ClickListener(){
@Override
public void clicked(InputEvent event, float x, float y) {
theChosenOne=unit;
pick(unit.name);
}
});
topTable.add(button).pad(10);
}
rightSideButton.addListener(new ClickListener(){
@Override
public void clicked(InputEvent event, float x, float y) {
civInfo.placeUnitNearTile(civInfo.cities.get(0).cityLocation, theChosenOne.name);
}
});
}
}

View file

@ -0,0 +1,31 @@
package com.unciv.ui.pickerscreens
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.gamebasics.Unit
import com.unciv.ui.cityscreen.addClickListener
import com.unciv.ui.utils.CameraStageBaseScreen
class GreatPersonPickerScreen : PickerScreen() {
private var theChosenOne: Unit? = null
internal var civInfo: CivilizationInfo? = null
init {
rightSideButton.setText("Choose a free great person")
for (unit in GameBasics.Units.linqValues()) {
if (!unit.name.startsWith("Great")) continue
val button = TextButton(unit.name, CameraStageBaseScreen.skin)
button.addClickListener {
theChosenOne = unit
pick(unit.name)
}
topTable.add(button).pad(10f)
}
rightSideButton.addClickListener {
civInfo!!.placeUnitNearTile(civInfo!!.cities[0].cityLocation, theChosenOne!!.name)
}
}
}

View file

@ -1,46 +0,0 @@
package com.unciv.ui.pickerscreens;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.ui.VerticalGroup;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.unciv.logic.civilization.CivilizationInfo;
import com.unciv.logic.map.TileInfo;
import com.unciv.models.gamebasics.GameBasics;
import com.unciv.models.gamebasics.TileImprovement;
public class ImprovementPickerScreen extends PickerScreen {
private TileImprovement SelectedImprovement;
public ImprovementPickerScreen(final TileInfo tileInfo) {
final CivilizationInfo civInfo = game.gameInfo.getPlayerCivilization();
rightSideButton.setText("Pick improvement");
rightSideButton.addListener(new ClickListener(){
@Override
public void clicked(InputEvent event, float x, float y) {
tileInfo.startWorkingOnImprovement(SelectedImprovement,civInfo);
game.setWorldScreen();
dispose();
}
});
VerticalGroup regularImprovements = new VerticalGroup();
regularImprovements.space(10);
for(final TileImprovement improvement : GameBasics.TileImprovements.values()) {
if(!tileInfo.canBuildImprovement(improvement,civInfo) || improvement.name.equals(tileInfo.improvement)) continue;
TextButton TB = new TextButton(improvement.name +"\r\n"+improvement.getTurnsToBuild(civInfo)+" turns", skin);
TB.addListener(new ClickListener(){
@Override
public void clicked(InputEvent event, float x, float y) {
SelectedImprovement = improvement;
pick(improvement.name);
descriptionLabel.setText(improvement.getDescription());
}
});
regularImprovements.addActor(TB);
}
topTable.add(regularImprovements);
}
}

View file

@ -0,0 +1,42 @@
package com.unciv.ui.pickerscreens
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
import com.badlogic.gdx.scenes.scene2d.ui.VerticalGroup
import com.unciv.logic.map.TileInfo
import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.gamebasics.TileImprovement
import com.unciv.ui.cityscreen.addClickListener
import com.unciv.ui.utils.CameraStageBaseScreen
class ImprovementPickerScreen(tileInfo: TileInfo) : PickerScreen() {
private var selectedImprovement: TileImprovement? = null
init {
val civInfo = game.gameInfo.getPlayerCivilization()
rightSideButton.setText("Pick improvement")
rightSideButton.addClickListener {
tileInfo.startWorkingOnImprovement(selectedImprovement!!, civInfo)
game.setWorldScreen()
dispose()
}
val regularImprovements = VerticalGroup()
regularImprovements.space(10f)
for (improvement in GameBasics.TileImprovements.values) {
if (!tileInfo.canBuildImprovement(improvement, civInfo) || improvement.name == tileInfo.improvement) continue
val improvementTextButton = TextButton(
improvement.name + "\r\n" + improvement.getTurnsToBuild(civInfo) + " turns",
CameraStageBaseScreen.skin
)
improvementTextButton.addClickListener {
selectedImprovement = improvement
pick(improvement.name)
descriptionLabel.setText(improvement.description)
}
regularImprovements.addActor(improvementTextButton)
}
topTable.add(regularImprovements)
}
}

View file

@ -1,68 +0,0 @@
package com.unciv.ui.pickerscreens;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Touchable;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane;
import com.badlogic.gdx.scenes.scene2d.ui.SplitPane;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.badlogic.gdx.utils.Align;
import com.unciv.ui.utils.CameraStageBaseScreen;
public class PickerScreen extends CameraStageBaseScreen {
TextButton closeButton;
protected Label descriptionLabel;
protected TextButton rightSideButton;
float screenSplit = 0.85f;
protected Table topTable;
SplitPane splitPane;
public PickerScreen() {
Table buttonTable = new Table();
closeButton = new TextButton("Close", skin);
closeButton.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
game.setWorldScreen();
dispose();
}
});
buttonTable.add(closeButton).width(stage.getWidth() / 4);
descriptionLabel = new Label("", skin);
descriptionLabel.setWrap(true);
descriptionLabel.setFontScale(game.settings.labelScale);
descriptionLabel.setWidth(stage.getWidth() / 2);
buttonTable.add(descriptionLabel).pad(5).width(stage.getWidth() / 2);
rightSideButton = new TextButton("", skin);
buttonTable.add(rightSideButton).width(stage.getWidth() / 4);
buttonTable.setHeight(stage.getHeight()*(1-screenSplit));
buttonTable.align(Align.center);
rightSideButton.setColor(Color.GRAY);
rightSideButton.setTouchable(Touchable.disabled);
topTable = new Table();
ScrollPane scrollPane = new ScrollPane(topTable);
scrollPane.setSize(stage.getWidth(), stage.getHeight() * screenSplit);
splitPane = new SplitPane(scrollPane, buttonTable, true, skin);
splitPane.setSplitAmount(screenSplit);
splitPane.setFillParent(true);
stage.addActor(splitPane);
}
protected void pick(String rightButtonText){
rightSideButton.setTouchable(Touchable.enabled);
rightSideButton.setColor(Color.WHITE);
rightSideButton.setText(rightButtonText);
}
}

View file

@ -0,0 +1,66 @@
package com.unciv.ui.pickerscreens
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.InputEvent
import com.badlogic.gdx.scenes.scene2d.Touchable
import com.badlogic.gdx.scenes.scene2d.ui.Label
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane
import com.badlogic.gdx.scenes.scene2d.ui.SplitPane
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener
import com.badlogic.gdx.utils.Align
import com.unciv.ui.utils.CameraStageBaseScreen
open class PickerScreen : CameraStageBaseScreen() {
internal var closeButton: TextButton
protected var descriptionLabel: Label
protected var rightSideButton: TextButton
internal var screenSplit = 0.85f
protected var topTable: Table
internal var splitPane: SplitPane
init {
val buttonTable = Table()
closeButton = TextButton("Close", CameraStageBaseScreen.skin)
closeButton.addListener(object : ClickListener() {
override fun clicked(event: InputEvent?, x: Float, y: Float) {
game.setWorldScreen()
dispose()
}
})
buttonTable.add(closeButton).width(stage.width / 4)
descriptionLabel = Label("", CameraStageBaseScreen.skin)
descriptionLabel.setWrap(true)
descriptionLabel.setFontScale(game.settings.labelScale)
descriptionLabel.width = stage.width / 2
buttonTable.add(descriptionLabel).pad(5f).width(stage.width / 2)
rightSideButton = TextButton("", CameraStageBaseScreen.skin)
buttonTable.add(rightSideButton).width(stage.width / 4)
buttonTable.height = stage.height * (1 - screenSplit)
buttonTable.align(Align.center)
rightSideButton.color = Color.GRAY
rightSideButton.touchable = Touchable.disabled
topTable = Table()
val scrollPane = ScrollPane(topTable)
scrollPane.setSize(stage.width, stage.height * screenSplit)
splitPane = SplitPane(scrollPane, buttonTable, true, CameraStageBaseScreen.skin)
splitPane.setSplitAmount(screenSplit)
splitPane.setFillParent(true)
stage.addActor(splitPane)
}
protected fun pick(rightButtonText: String) {
rightSideButton.touchable = Touchable.enabled
rightSideButton.color = Color.WHITE
rightSideButton.setText(rightButtonText)
}
}

View file

@ -1,136 +0,0 @@
package com.unciv.ui.pickerscreens;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Touchable;
import com.badlogic.gdx.scenes.scene2d.ui.Button;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.unciv.logic.civilization.CivilizationInfo;
import com.unciv.logic.civilization.PolicyManager;
import com.unciv.models.linq.Linq;
import com.unciv.models.gamebasics.GameBasics;
import com.unciv.models.gamebasics.Policy;
import com.unciv.models.gamebasics.PolicyBranch;
import com.unciv.models.gamebasics.StringUtils;
import com.unciv.ui.utils.ImageGetter;
public class PolicyPickerScreen extends PickerScreen {
final CivilizationInfo civInfo;
private Policy pickedPolicy;
public PolicyPickerScreen(final CivilizationInfo civInfo) {
this.civInfo = civInfo;
final PolicyManager policies = civInfo.policies;
Linq<String> tutorial = new Linq<String>();
tutorial.add("Each turn, the culture you gain from all your " +
"\r\n cities is added to your Civilization's culture." +
"\r\nWhen you have enough culture, you may pick a " +
"\r\n Social Policy, each one giving you a certain bonus.");
tutorial.add("The policies are organized into branches, with each" +
"\r\n branch providing a bonus ability when all policies " +
"\r\n in the branch have been adopted.");
tutorial.add("With each policy adopted, and with each city built," +
"\r\n the cost of adopting another policy rises - so choose wisely!");
displayTutorials("PolicyPickerScreen",tutorial);
rightSideButton.setText("Adopt policy\r\n(" + policies.storedCulture + "/" + policies.getCultureNeededForNextPolicy() + ")");
if(policies.freePolicies>0) {
rightSideButton.setText("Adopt free policy");
closeButton.setColor(Color.GRAY);
closeButton.setTouchable(Touchable.disabled);
}
rightSideButton.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
if(policies.freePolicies>0) policies.freePolicies--;
else policies.storedCulture -= policies.getCultureNeededForNextPolicy();
civInfo.policies.adopt(pickedPolicy);
game.setScreen(new PolicyPickerScreen(civInfo));
}
});
topTable.row().pad(30);
for (PolicyBranch branch : GameBasics.PolicyBranches.values()) {
if (branch.name.equals("Commerce")) topTable.row();
Table branchGroup = new Table();
branchGroup.row().pad(20);
branchGroup.add(getPolicyButton(branch, false)).row();
int currentRow = 1;
int currentColumn = 1;
Table branchTable = new Table();
for (Policy policy : branch.policies) {
if (policy.name.endsWith("Complete")) continue;
if (policy.row > currentRow) {
branchTable.row();
currentRow++;
currentColumn = 1;
}
if (policy.column > currentColumn) {
branchTable.add().colspan(policy.column - currentColumn); // empty space
}
branchTable.add(getPolicyButton(policy, true)).colspan(2);
currentColumn = policy.column + 2;
}
branchTable.pack();
branchGroup.add(branchTable).height(150).row();
branchGroup.add(getPolicyButton(branch.policies.get(branch.policies.size() - 1), false)); // finisher
topTable.add(branchGroup);
}
topTable.pack();
}
public void pickPolicy(Policy policy) {
if (civInfo.policies.isAdopted(policy.name)
|| !civInfo.policies.getAdoptedPolicies().containsAll(policy.requires)
|| !civInfo.policies.canAdoptPolicy()) {
rightSideButton.setTouchable(Touchable.disabled);
rightSideButton.setColor(Color.GRAY);
} else {
rightSideButton.setColor(Color.WHITE);
rightSideButton.setTouchable(Touchable.enabled);
}
pickedPolicy = policy;
String policyText = policy.name + "\r\n" + policy.description + "\r\n";
if (!policy.name.endsWith("Complete") && policy.requires.size() > 0)
policyText += "Requires " + StringUtils.join(", ", policy.requires);
descriptionLabel.setText(policyText);
}
public Button getPolicyButton(final Policy policy, boolean image) {
Button toReturn = new Button(skin);
if (image) {
Image policyImage = ImageGetter.getImage("PolicyIcons/" + policy.name.replace(" ", "_") + "_(Civ5).png");
toReturn.add(policyImage).size(30);
} else toReturn = new TextButton(policy.name, skin);
if (civInfo.policies.isAdopted(policy.name)) { // existing
toReturn.setColor(Color.GREEN);
} else if (!civInfo.policies.getAdoptedPolicies().containsAll(policy.requires)) // non-available
{
toReturn.setColor(Color.GRAY);
}
toReturn.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
pickPolicy(policy);
}
});
toReturn.pack();
return toReturn;
}
}

View file

@ -0,0 +1,126 @@
package com.unciv.ui.pickerscreens
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.Touchable
import com.badlogic.gdx.scenes.scene2d.ui.Button
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.gamebasics.Policy
import com.unciv.models.gamebasics.StringUtils
import com.unciv.models.linq.Linq
import com.unciv.ui.cityscreen.addClickListener
import com.unciv.ui.utils.CameraStageBaseScreen
import com.unciv.ui.utils.ImageGetter
class PolicyPickerScreen(internal val civInfo: CivilizationInfo) : PickerScreen() {
private var pickedPolicy: Policy? = null
init {
val policies = civInfo.policies
val tutorial = Linq<String>()
tutorial.add("Each turn, the culture you gain from all your " +
"\r\n cities is added to your Civilization's culture." +
"\r\nWhen you have enough culture, you may pick a " +
"\r\n Social Policy, each one giving you a certain bonus.")
tutorial.add("The policies are organized into branches, with each" +
"\r\n branch providing a bonus ability when all policies " +
"\r\n in the branch have been adopted.")
tutorial.add("With each policy adopted, and with each city built," + "\r\n the cost of adopting another policy rises - so choose wisely!")
displayTutorials("PolicyPickerScreen", tutorial)
rightSideButton.setText("Adopt policy\r\n(" + policies.storedCulture + "/" + policies.getCultureNeededForNextPolicy() + ")")
if (policies.freePolicies > 0) {
rightSideButton.setText("Adopt free policy")
closeButton.color = Color.GRAY
closeButton.touchable = Touchable.disabled
}
rightSideButton.addClickListener {
if (policies.freePolicies > 0)
policies.freePolicies--
else
policies.storedCulture -= policies.getCultureNeededForNextPolicy()
civInfo.policies.adopt(pickedPolicy!!)
game.screen = PolicyPickerScreen(civInfo)
}
topTable.row().pad(30f)
for (branch in GameBasics.PolicyBranches.values) {
if (branch.name == "Commerce") topTable.row()
val branchGroup = Table()
branchGroup.row().pad(20f)
branchGroup.add(getPolicyButton(branch, false)).row()
var currentRow = 1
var currentColumn = 1
val branchTable = Table()
for (policy in branch.policies) {
if (policy.name.endsWith("Complete")) continue
if (policy.row > currentRow) {
branchTable.row()
currentRow++
currentColumn = 1
}
if (policy.column > currentColumn) {
branchTable.add().colspan(policy.column - currentColumn) // empty space
}
branchTable.add(getPolicyButton(policy, true)).colspan(2)
currentColumn = policy.column + 2
}
branchTable.pack()
branchGroup.add(branchTable).height(150f).row()
branchGroup.add(getPolicyButton(branch.policies[branch.policies.size - 1], false)) // finisher
topTable.add(branchGroup)
}
topTable.pack()
}
private fun pickPolicy(policy: Policy) {
if (civInfo.policies.isAdopted(policy.name)
|| !civInfo.policies.getAdoptedPolicies().containsAll(policy.requires!!)
|| !civInfo.policies.canAdoptPolicy()) {
rightSideButton.touchable = Touchable.disabled
rightSideButton.color = Color.GRAY
} else {
rightSideButton.color = Color.WHITE
rightSideButton.touchable = Touchable.enabled
}
pickedPolicy = policy
var policyText = policy.name + "\r\n" + policy.description + "\r\n"
if (!policy.name.endsWith("Complete") && policy.requires!!.size > 0)
policyText += "Requires " + StringUtils.join(", ", policy.requires)
descriptionLabel.setText(policyText)
}
private fun getPolicyButton(policy: Policy, image: Boolean): Button {
var toReturn = Button(CameraStageBaseScreen.skin)
if (image) {
val policyImage = ImageGetter.getImage("PolicyIcons/" + policy.name.replace(" ", "_") + "_(Civ5).png")
toReturn.add(policyImage).size(30f)
} else
toReturn = TextButton(policy.name, CameraStageBaseScreen.skin)
if (civInfo.policies.isAdopted(policy.name)) { // existing
toReturn.color = Color.GREEN
} else if (!civInfo.policies.getAdoptedPolicies().containsAll(policy.requires!!))
// non-available
{
toReturn.color = Color.GRAY
}
toReturn.addClickListener { pickPolicy(policy) }
toReturn.pack()
return toReturn
}
}

View file

@ -1,173 +0,0 @@
package com.unciv.ui.pickerscreens;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Touchable;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.unciv.logic.civilization.CivilizationInfo;
import com.unciv.logic.civilization.TechManager;
import com.unciv.models.linq.Linq;
import com.unciv.models.gamebasics.GameBasics;
import com.unciv.models.gamebasics.Technology;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Stack;
public class TechPickerScreen extends PickerScreen {
HashMap<String, TextButton> techNameToButton = new HashMap<String, TextButton>();
boolean isFreeTechPick;
Technology selectedTech;
final CivilizationInfo civInfo;
TechManager civTech;
ArrayList<String> techsToResearch;
public TechPickerScreen(boolean freeTechPick, CivilizationInfo civInfo){
this(civInfo);
isFreeTechPick=freeTechPick;
}
public TechPickerScreen(final CivilizationInfo civInfo) {
this.civInfo = civInfo;
civTech = civInfo.tech;
techsToResearch = new ArrayList<String>(civTech.techsToResearch);
Technology[][] techMatrix = new Technology[17][10]; // Divided into columns, then rows
for (Technology technology : GameBasics.Technologies.linqValues()) {
techMatrix[technology.column.columnNumber-1][technology.row - 1] = technology;
}
for (int i = 0; i < 10; i++) {
topTable.row().pad(5);
for (int j = 0; j < techMatrix.length; j++) {
final Technology tech = techMatrix[j][i];
if (tech == null) topTable.add(); // empty cell
else {
final TextButton TB = new TextButton("", skin);
techNameToButton.put(tech.name, TB);
TB.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
selectTechnology(tech);
}
});
topTable.add(TB);
}
}
}
setButtonsInfo();
rightSideButton.setText("Pick a tech");
rightSideButton.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
if (isFreeTechPick) {
civTech.techsResearched.add(selectedTech.name);
civTech.freeTechs-=1;
civInfo.gameInfo.addNotification("We have stumbled upon the discovery of "+selectedTech.name+"!",null);
if(selectedTech.name.equals(civTech.currentTechnology()))
civTech.techsToResearch.remove(selectedTech.name);
}
else civTech.techsToResearch = techsToResearch;
game.setWorldScreen();
game.worldScreen.update();
dispose();
}
});
Linq<String> tutorial = new Linq<String>();
tutorial.add("Technology is central to your civilization," +
"\r\n as technological progress brings with it" +
"\r\n more construction options, improvements, and abilities");
tutorial.add("Most technologies are dependant on" +
"\r\n other technologies being researched - " +
"\r\n but you can choose a technology to aspire to," +
"\r\n and your civilization will research the" +
"\r\n necessary technologies to get there");
displayTutorials("TechPickerScreen",tutorial);
}
public void setButtonsInfo() {
for (String techName : techNameToButton.keySet()) {
TextButton TB = techNameToButton.get(techName);
//TB.getStyle().checkedFontColor = Color.BLACK;
if (civTech.isResearched(techName)) TB.setColor(Color.GREEN);
else if (techsToResearch.contains(techName)) TB.setColor(Color.BLUE.cpy().lerp(Color.WHITE,0.3f));
else if (civTech.canBeResearched(techName)) TB.setColor(Color.WHITE);
else TB.setColor(Color.BLACK);
TB.setChecked(false);
StringBuilder text = new StringBuilder(techName);
if (selectedTech != null) {
if (techName.equals(selectedTech.name)) {
TB.setChecked(true);
TB.setColor(TB.getColor().cpy().lerp(Color.LIGHT_GRAY, 0.5f));
}
}
if (techsToResearch.contains(techName) && techsToResearch.size()>1) {
text.append(" (").append(techsToResearch.indexOf(techName)+1).append(")");
}
if(!civTech.isResearched(techName)) text.append("\r\n"+civInfo.turnsToTech(techName) + " turns");
TB.setText(text.toString());
}
}
public void selectTechnology(Technology tech) {
selectedTech = tech;
descriptionLabel.setText(tech.description);
if(isFreeTechPick) {selectTechnologyForFreeTech(tech); return;}
if (civTech.isResearched(tech.name)) {
rightSideButton.setText("Research");
rightSideButton.setTouchable(Touchable.disabled);
rightSideButton.setColor(Color.GRAY);
setButtonsInfo();
return;
}
if (civTech.canBeResearched(tech.name)) {
techsToResearch.clear();
techsToResearch.add(tech.name);
} else {
Stack<String> Prerequisites = new Stack<String>();
ArrayDeque<String> CheckPrerequisites = new ArrayDeque<String>();
CheckPrerequisites.add(tech.name);
while (!CheckPrerequisites.isEmpty()) {
String techNameToCheck = CheckPrerequisites.pop();
if (civTech.isResearched(techNameToCheck) || Prerequisites.contains(techNameToCheck))
continue; //no need to add or check prerequisites
Technology techToCheck = GameBasics.Technologies.get(techNameToCheck);
for (String str : techToCheck.prerequisites)
if (!CheckPrerequisites.contains(str)) CheckPrerequisites.add(str);
Prerequisites.add(techNameToCheck);
}
techsToResearch.clear();
while (!Prerequisites.isEmpty()) techsToResearch.add(Prerequisites.pop());
}
pick("Research \r\n" + techsToResearch.get(0));
setButtonsInfo();
}
private void selectTechnologyForFreeTech(Technology tech){
if (civTech.canBeResearched(tech.name)) {
pick("Pick " + selectedTech.name+"\r\n as free tech!");
}
else {
rightSideButton.setText("Pick a free tech");
rightSideButton.setTouchable(Touchable.disabled);
rightSideButton.setColor(Color.GRAY);
}
}
}

View file

@ -0,0 +1,166 @@
package com.unciv.ui.pickerscreens
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.Touchable
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.civilization.TechManager
import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.gamebasics.Technology
import com.unciv.models.linq.Linq
import com.unciv.ui.cityscreen.addClickListener
import com.unciv.ui.utils.CameraStageBaseScreen
import java.util.*
class TechPickerScreen(internal val civInfo: CivilizationInfo) : PickerScreen() {
internal var techNameToButton = HashMap<String, TextButton>()
internal var isFreeTechPick: Boolean = false
internal var selectedTech: Technology? = null
internal var civTech: TechManager
internal var techsToResearch: ArrayList<String>
constructor(freeTechPick: Boolean, civInfo: CivilizationInfo) : this(civInfo) {
isFreeTechPick = freeTechPick
}
init {
civTech = civInfo.tech
techsToResearch = ArrayList(civTech.techsToResearch)
val techMatrix = Array<Array<Technology?>>(17) { arrayOfNulls(10) } // Divided into columns, then rows
for (technology in GameBasics.Technologies.linqValues()) {
techMatrix[technology.column!!.columnNumber - 1][technology.row - 1] = technology
}
for (i in 0..9) {
topTable.row().pad(5f)
for (j in techMatrix.indices) {
val tech = techMatrix[j][i]
if (tech == null)
topTable.add() // empty cell
else {
val TB = TextButton("", CameraStageBaseScreen.skin)
techNameToButton[tech.name] = TB
TB.addClickListener {
selectTechnology(tech)
}
topTable.add<TextButton>(TB)
}
}
}
setButtonsInfo()
rightSideButton.setText("Pick a tech")
rightSideButton.addClickListener {
if (isFreeTechPick) {
civTech.techsResearched.add(selectedTech!!.name)
civTech.freeTechs -= 1
civInfo.gameInfo.addNotification("We have stumbled upon the discovery of " + selectedTech!!.name + "!", null)
if (selectedTech!!.name == civTech.currentTechnology())
civTech.techsToResearch.remove(selectedTech!!.name)
} else
civTech.techsToResearch = techsToResearch
game.setWorldScreen()
game.worldScreen!!.update()
dispose()
}
val tutorial = Linq<String>()
tutorial.add("Technology is central to your civilization," +
"\r\n as technological progress brings with it" +
"\r\n more construction options, improvements, and abilities")
tutorial.add("Most technologies are dependant on" +
"\r\n other technologies being researched - " +
"\r\n but you can choose a technology to aspire to," +
"\r\n and your civilization will research the" +
"\r\n necessary technologies to get there")
displayTutorials("TechPickerScreen", tutorial)
}
fun setButtonsInfo() {
for (techName in techNameToButton.keys) {
val TB = techNameToButton[techName]!!
//TB.getStyle().checkedFontColor = Color.BLACK;
if (civTech.isResearched(techName))
TB.color = Color.GREEN
else if (techsToResearch.contains(techName))
TB.color = Color.BLUE.cpy().lerp(Color.WHITE, 0.3f)
else if (civTech.canBeResearched(techName))
TB.color = Color.WHITE
else
TB.color = Color.BLACK
TB.isChecked = false
val text = StringBuilder(techName)
if (selectedTech != null) {
if (techName == selectedTech!!.name) {
TB.isChecked = true
TB.color = TB.color.cpy().lerp(Color.LIGHT_GRAY, 0.5f)
}
}
if (techsToResearch.contains(techName) && techsToResearch.size > 1) {
text.append(" (").append(techsToResearch.indexOf(techName) + 1).append(")")
}
if (!civTech.isResearched(techName)) text.append("\r\n" + civInfo.turnsToTech(techName) + " turns")
TB.setText(text.toString())
}
}
fun selectTechnology(tech: Technology?) {
selectedTech = tech
descriptionLabel.setText(tech!!.description)
if (isFreeTechPick) {
selectTechnologyForFreeTech(tech)
return
}
if (civTech.isResearched(tech.name)) {
rightSideButton.setText("Research")
rightSideButton.touchable = Touchable.disabled
rightSideButton.color = Color.GRAY
setButtonsInfo()
return
}
if (civTech.canBeResearched(tech.name)) {
techsToResearch.clear()
techsToResearch.add(tech.name)
} else {
val prerequisites = Stack<String>()
val CheckPrerequisites = ArrayDeque<String>()
CheckPrerequisites.add(tech.name)
while (!CheckPrerequisites.isEmpty()) {
val techNameToCheck = CheckPrerequisites.pop()
if (civTech.isResearched(techNameToCheck) || prerequisites.contains(techNameToCheck))
continue //no need to add or check prerequisites
val techToCheck = GameBasics.Technologies[techNameToCheck]
for (str in techToCheck!!.prerequisites)
if (!CheckPrerequisites.contains(str)) CheckPrerequisites.add(str)
prerequisites.add(techNameToCheck)
}
techsToResearch.clear()
while (!prerequisites.isEmpty()) techsToResearch.add(prerequisites.pop())
}
pick("Research \r\n" + techsToResearch[0])
setButtonsInfo()
}
private fun selectTechnologyForFreeTech(tech: Technology) {
if (civTech.canBeResearched(tech.name)) {
pick("Pick " + selectedTech!!.name + "\r\n as free tech!")
} else {
rightSideButton.setText("Pick a free tech")
rightSideButton.touchable = Touchable.disabled
rightSideButton.color = Color.GRAY
}
}
}

View file

@ -1,136 +0,0 @@
package com.unciv.ui.tilegroups;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.Group;
import com.badlogic.gdx.scenes.scene2d.ui.Container;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.unciv.logic.map.RoadStatus;
import com.unciv.logic.map.TileInfo;
import com.unciv.models.linq.LinqHashMap;
import com.unciv.ui.utils.HexMath;
import com.unciv.ui.utils.ImageGetter;
public class TileGroup extends Group {
protected Image terrainImage;
String terrainType;
protected Image resourceImage;
protected Image unitImage;
protected Image improvementImage;
String improvementType;
public Image populationImage;
LinqHashMap<String,Image> roadImages = new LinqHashMap<String, Image>();
protected Image hexagon;
protected Container<TextButton> cityButton;
public TileInfo tileInfo;
public TileGroup(TileInfo tileInfo){
this.tileInfo = tileInfo;
terrainType = tileInfo.getLastTerrain().name;
String terrainFileName = "TerrainIcons/" + terrainType.replace(' ','_') + "_(Civ5).png";
terrainImage = ImageGetter.getImage(terrainFileName);
int groupSize = 50;
terrainImage.setSize(groupSize,groupSize);
setSize(groupSize,groupSize);
addActor(terrainImage);
}
public void addPopulationIcon(){
populationImage = ImageGetter.getImage("StatIcons/populationGreen.png");
populationImage.setSize(20,20);
populationImage.moveBy(0, terrainImage.getHeight()-populationImage.getHeight()); // top left
addActor(populationImage);
}
protected void removePopulationIcon(){
populationImage.remove();
populationImage = null;
}
public void update() {
if (tileInfo.explored) {
terrainImage.setColor(Color.WHITE);
} else {
terrainImage.setColor(Color.BLACK);
return;
}
if (!terrainType.equals(tileInfo.getLastTerrain().name)) {
terrainType = tileInfo.getLastTerrain().name;
String terrainFileName = "TerrainIcons/" + terrainType.replace(' ', '_') + "_(Civ5).png";
terrainImage.setDrawable(ImageGetter.getDrawable(terrainFileName)); // In case we e.g. removed a jungle
}
if (tileInfo.hasViewableResource(tileInfo.tileMap.gameInfo.getPlayerCivilization()) && resourceImage == null) { // Need to add the resource image!
String fileName = "ResourceIcons/" + tileInfo.resource + "_(Civ5).png";
resourceImage = ImageGetter.getImage(fileName);
resourceImage.setSize(20, 20);
resourceImage.moveBy(terrainImage.getWidth() - resourceImage.getWidth(), 0); // bottom right
addActor(resourceImage);
}
if (tileInfo.unit != null && unitImage == null) {
unitImage = ImageGetter.getImage("UnitIcons/" + tileInfo.unit.name.replace(" ", "_") + "_(Civ5).png");
addActor(unitImage);
unitImage.setSize(20, 20); // not moved - is at bottom left
}
if (tileInfo.unit == null && unitImage != null) {
unitImage.remove();
unitImage = null;
}
if (unitImage != null) {
if (!tileInfo.hasIdleUnit()) unitImage.setColor(Color.GRAY);
else unitImage.setColor(Color.WHITE);
}
if (tileInfo.improvement != null && !tileInfo.improvement.equals(improvementType)) {
improvementImage = ImageGetter.getImage("ImprovementIcons/" + tileInfo.improvement.replace(' ', '_') + "_(Civ5).png");
addActor(improvementImage);
improvementImage.setSize(20, 20);
improvementImage.moveBy(terrainImage.getWidth() - improvementImage.getWidth(),
terrainImage.getHeight() - improvementImage.getHeight()); // top right
improvementType = tileInfo.improvement;
}
if (populationImage != null) {
if (tileInfo.workingCity != null) populationImage.setColor(Color.WHITE);
else populationImage.setColor(Color.GRAY);
}
if (tileInfo.roadStatus != RoadStatus.None) {
for (TileInfo neighbor : tileInfo.getNeighbors()) {
if (neighbor.roadStatus == RoadStatus.None) continue;
if (!roadImages.containsKey(neighbor.position.toString())) {
Image image = ImageGetter.getImage(ImageGetter.WhiteDot);
roadImages.put(neighbor.position.toString(), image);
Vector2 relativeHexPosition = tileInfo.position.cpy().sub(neighbor.position);
Vector2 relativeWorldPosition = HexMath.Hex2WorldCoords(relativeHexPosition);
// This is some crazy voodoo magic so I'll explain.
image.moveBy(25, 25); // Move road to center of tile
// in addTiles, we set the position of groups by relative world position *0.8*groupSize, where groupSize = 50
// Here, we want to have the roads start HALFWAY THERE and extend towards the tiles, so we give them a position of 0.8*25.
image.moveBy(-relativeWorldPosition.x * 0.8f * 25, -relativeWorldPosition.y * 0.8f * 25);
image.setSize(10, 2);
addActor(image);
image.setOrigin(0, 1); // This is so that the rotation is calculated from the middle of the road and not the edge
image.setRotation((float) (180 / Math.PI * Math.atan2(relativeWorldPosition.y, relativeWorldPosition.x)));
}
if (tileInfo.roadStatus == RoadStatus.Railroad && neighbor.roadStatus == RoadStatus.Railroad)
roadImages.get(neighbor.position.toString()).setColor(Color.GRAY); // railroad
else roadImages.get(neighbor.position.toString()).setColor(Color.BROWN); // road
}
}
}
}

View file

@ -0,0 +1,142 @@
package com.unciv.ui.tilegroups
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.Group
import com.badlogic.gdx.scenes.scene2d.ui.Container
import com.badlogic.gdx.scenes.scene2d.ui.Image
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
import com.unciv.logic.map.RoadStatus
import com.unciv.logic.map.TileInfo
import com.unciv.models.linq.LinqHashMap
import com.unciv.ui.utils.HexMath
import com.unciv.ui.utils.ImageGetter
open class TileGroup(var tileInfo: TileInfo) : Group() {
protected var terrainImage: Image
private var terrainType: String
protected var resourceImage: Image? = null
protected var unitImage: Image? = null
protected var improvementImage: Image? =null
private var improvementType: String? = null
var populationImage: Image? = null
private var roadImages = LinqHashMap<String, Image>()
protected var hexagon: Image? = null
protected var cityButton: Container<TextButton>? = null
init {
terrainType = tileInfo.lastTerrain.name
val terrainFileName = "TerrainIcons/" + terrainType.replace(' ', '_') + "_(Civ5).png"
terrainImage = ImageGetter.getImage(terrainFileName)
val groupSize = 50
terrainImage.setSize(groupSize.toFloat(), groupSize.toFloat())
this.setSize(groupSize.toFloat(), groupSize.toFloat())
this.addActor(terrainImage)
}
fun addPopulationIcon() {
populationImage = ImageGetter.getImage("StatIcons/populationGreen.png")
populationImage!!.run {
setSize(20f, 20f)
moveBy(0f, terrainImage.height - populationImage!!.height)
} // top left
addActor(populationImage!!)
}
protected fun removePopulationIcon() {
populationImage!!.remove()
populationImage = null
}
open fun update() {
if (!tileInfo.explored) {
terrainImage.color = Color.BLACK
return
}
terrainImage.color = Color.WHITE
if (terrainType != tileInfo.lastTerrain.name) {
terrainType = tileInfo.lastTerrain.name
val terrainFileName = "TerrainIcons/" + terrainType.replace(' ', '_') + "_(Civ5).png"
terrainImage.drawable = ImageGetter.getDrawable(terrainFileName) // In case we e.g. removed a jungle
}
if (tileInfo.hasViewableResource(tileInfo.tileMap!!.gameInfo!!.getPlayerCivilization()) && resourceImage == null) { // Need to add the resource image!
val fileName = "ResourceIcons/" + tileInfo.resource + "_(Civ5).png"
resourceImage = ImageGetter.getImage(fileName)
resourceImage!!.setSize(20f, 20f)
resourceImage!!.moveBy(terrainImage.width - resourceImage!!.width, 0f) // bottom right
addActor(resourceImage!!)
}
if (tileInfo.unit != null && unitImage == null) {
unitImage = ImageGetter.getImage("UnitIcons/" + tileInfo.unit!!.name!!.replace(" ", "_") + "_(Civ5).png")
addActor(unitImage!!)
unitImage!!.setSize(20f, 20f) // not moved - is at bottom left
}
if (tileInfo.unit == null && unitImage != null) {
unitImage!!.remove()
unitImage = null
}
if (unitImage != null) {
if (!tileInfo.hasIdleUnit())
unitImage!!.color = Color.GRAY
else
unitImage!!.color = Color.WHITE
}
if (tileInfo.improvement != null && tileInfo.improvement != improvementType) {
improvementImage = ImageGetter.getImage("ImprovementIcons/" + tileInfo.improvement!!.replace(' ', '_') + "_(Civ5).png")
addActor(improvementImage)
improvementImage!!.run {
setSize(20f, 20f)
moveBy(terrainImage.width - width,
terrainImage.height - height)
} // top right
improvementType = tileInfo.improvement
}
if (populationImage != null) {
if (tileInfo.workingCity != null)
populationImage!!.color = Color.WHITE
else
populationImage!!.color = Color.GRAY
}
if (tileInfo.roadStatus !== RoadStatus.None) {
for (neighbor in tileInfo.neighbors) {
if (neighbor.roadStatus === RoadStatus.None) continue
if (!roadImages.containsKey(neighbor.position.toString())) {
val image = ImageGetter.getImage(ImageGetter.WhiteDot)
roadImages[neighbor.position.toString()] = image
val relativeHexPosition = tileInfo.position.cpy().sub(neighbor.position)
val relativeWorldPosition = HexMath.Hex2WorldCoords(relativeHexPosition)
// This is some crazy voodoo magic so I'll explain.
image.moveBy(25f, 25f) // Move road to center of tile
// in addTiles, we set the position of groups by relative world position *0.8*groupSize, where groupSize = 50
// Here, we want to have the roads start HALFWAY THERE and extend towards the tiles, so we give them a position of 0.8*25.
image.moveBy(-relativeWorldPosition.x * 0.8f * 25f, -relativeWorldPosition.y * 0.8f * 25f)
image.setSize(10f, 2f)
addActor(image)
image.setOrigin(0f, 1f) // This is so that the rotation is calculated from the middle of the road and not the edge
image.rotation = (180 / Math.PI * Math.atan2(relativeWorldPosition.y.toDouble(), relativeWorldPosition.x.toDouble())).toFloat()
}
if (tileInfo.roadStatus === RoadStatus.Railroad && neighbor.roadStatus === RoadStatus.Railroad)
roadImages[neighbor.position.toString()]!!.color = Color.GRAY // railroad
else
roadImages[neighbor.position.toString()]!!.color = Color.BROWN // road
}
}
}
}

View file

@ -1,82 +0,0 @@
package com.unciv.ui.tilegroups;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.ui.Container;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.unciv.logic.city.CityInfo;
import com.unciv.logic.map.TileInfo;
import com.unciv.ui.cityscreen.CityScreen;
import com.unciv.ui.UnCivGame;
import com.unciv.ui.utils.CameraStageBaseScreen;
import com.unciv.ui.utils.ImageGetter;
import com.unciv.ui.worldscreen.WorldScreen;
public class WorldTileGroup extends TileGroup {
public WorldTileGroup(TileInfo tileInfo) {
super(tileInfo);
}
public void setIsViewable(boolean isViewable) {
if (isViewable) {
setColor(0, 0, 0, 1); // Only alpha really changes anything
tileInfo.explored=true;
update();
}
else setColor(0, 0, 0, 0.3f);
}
public void update(WorldScreen worldScreen) {
super.update();
if(tileInfo.workingCity != null && populationImage==null) addPopulationIcon();
if(tileInfo.workingCity == null && populationImage!=null) removePopulationIcon();
if (tileInfo.owner != null && hexagon == null) {
hexagon = ImageGetter.getImage("TerrainIcons/Hexagon.png");
float imageScale = terrainImage.getWidth() * 1.3f / hexagon.getWidth();
hexagon.setScale(imageScale);
hexagon.setPosition((getWidth() - hexagon.getWidth() * imageScale) / 2,
(getHeight() - hexagon.getHeight() * imageScale) / 2);
addActor(hexagon);
hexagon.setZIndex(0);
}
final CityInfo city = tileInfo.getCity();
if (tileInfo.isCityCenter()) {
float buttonScale = 0.7f;
if (cityButton == null) {
cityButton = new Container<TextButton>();
cityButton.setActor(new TextButton("", CameraStageBaseScreen.skin));
cityButton.getActor().getLabel().setFontScale(buttonScale);
final UnCivGame game = worldScreen.game;
cityButton.getActor().addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
game.setScreen(new CityScreen(city));
}
});
addActor(cityButton);
setZIndex(getParent().getChildren().size); // so this tile is rendered over neighboring tiles
}
String cityButtonText = city.name +" ("+city.population.population+")";
TextButton button = cityButton.getActor();
button.setText(cityButtonText);
button.setSize(button.getPrefWidth(), button.getPrefHeight());
cityButton.setPosition((getWidth() - cityButton.getWidth()) / 2,
getHeight() * 0.9f);
cityButton.setZIndex(cityButton.getParent().getChildren().size); // so city button is rendere over oeverything else in this tile
}
}
}

View file

@ -0,0 +1,77 @@
package com.unciv.ui.tilegroups
import com.badlogic.gdx.scenes.scene2d.InputEvent
import com.badlogic.gdx.scenes.scene2d.ui.Container
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener
import com.unciv.logic.city.CityInfo
import com.unciv.logic.map.TileInfo
import com.unciv.ui.cityscreen.CityScreen
import com.unciv.ui.UnCivGame
import com.unciv.ui.utils.CameraStageBaseScreen
import com.unciv.ui.utils.ImageGetter
import com.unciv.ui.worldscreen.WorldScreen
class WorldTileGroup(tileInfo: TileInfo) : TileGroup(tileInfo) {
fun setIsViewable(isViewable: Boolean) {
if (isViewable) {
setColor(0f, 0f, 0f, 1f) // Only alpha really changes anything
tileInfo.explored = true
update()
} else
setColor(0f, 0f, 0f, 0.3f)
}
fun update(worldScreen: WorldScreen) {
super.update()
if (tileInfo.workingCity != null && populationImage == null) addPopulationIcon()
if (tileInfo.workingCity == null && populationImage != null) removePopulationIcon()
if (tileInfo.owner != null && hexagon == null) {
hexagon = ImageGetter.getImage("TerrainIcons/Hexagon.png")
val imageScale = terrainImage.width * 1.3f / hexagon!!.width
hexagon!!.setScale(imageScale)
hexagon!!.setPosition((width - hexagon!!.width * imageScale) / 2,
(height - hexagon!!.height * imageScale) / 2)
addActor(hexagon!!)
hexagon!!.zIndex = 0
}
val city = tileInfo.city
if (tileInfo.isCityCenter) {
val buttonScale = 0.7f
if (cityButton == null) {
cityButton = Container()
cityButton!!.actor = TextButton("", CameraStageBaseScreen.skin)
cityButton!!.actor.label.setFontScale(buttonScale)
val game = worldScreen.game
cityButton!!.actor.addListener(object : ClickListener() {
override fun clicked(event: InputEvent?, x: Float, y: Float) {
game.screen = CityScreen(city!!)
}
})
addActor(cityButton!!)
zIndex = parent.children.size // so this tile is rendered over neighboring tiles
}
val cityButtonText = city!!.name + " (" + city.population.population + ")"
val button = cityButton!!.actor
button.setText(cityButtonText)
button.setSize(button.prefWidth, button.prefHeight)
cityButton!!.setPosition((width - cityButton!!.width) / 2,
height * 0.9f)
cityButton!!.zIndex = cityButton!!.parent.children.size // so city button is rendere over oeverything else in this tile
}
}
}

View file

@ -1,102 +0,0 @@
package com.unciv.ui.utils;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.badlogic.gdx.utils.Align;
import com.badlogic.gdx.utils.viewport.ExtendViewport;
import com.unciv.models.linq.Linq;
import com.unciv.ui.UnCivGame;
public class CameraStageBaseScreen implements Screen {
public UnCivGame game;
public Stage stage;
public static Skin skin = new Skin(Gdx.files.internal("skin/flat-earth-ui.json"));
static Batch batch = new SpriteBatch();
public CameraStageBaseScreen() {
this.game = UnCivGame.Current;
stage = new Stage(new ExtendViewport(1000,600
),batch);// FitViewport(1000,600)
Gdx.input.setInputProcessor(stage);
}
@Override
public void show() { }
@Override
public void render(float delta) {
Gdx.gl.glClearColor(0, 0, 0.2f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
stage.act();
stage.draw();
}
@Override
public void resize(int width, int height) {
stage.getViewport().update(width,height,true);
}
@Override
public void pause() { }
@Override
public void resume() { }
@Override
public void hide() { }
@Override
public void dispose() { }
private Linq<String> tutorialTexts = new Linq<String>();
public void displayTutorials(String name, Linq<String> texts){
if(game.gameInfo.tutorial.contains(name)) return;
game.gameInfo.tutorial.add(name);
tutorialTexts.addAll(texts);
if(!isTutorialShowing) displayTutorial();
}
boolean isTutorialShowing=false;
public void displayTutorial(){
isTutorialShowing=true;
final Table tutorialTable = new Table().pad(10);
tutorialTable.background(ImageGetter.getDrawable("skin/tileTableBackground.png")
.tint(new Color(0x101050cf)));
Label label = new Label(tutorialTexts.get(0),skin);
label.setFontScale(1.5f);
label.setAlignment(Align.center);
tutorialTexts.remove(0);
tutorialTable.add(label).pad(10).row();
TextButton button = new TextButton("Close",skin);
button.addListener(new ClickListener(){
@Override
public void clicked(InputEvent event, float x, float y) {
tutorialTable.remove();
if(!tutorialTexts.isEmpty()) displayTutorial();
else isTutorialShowing=false;
}
});
tutorialTable.add(button).pad(10);
tutorialTable.pack();
tutorialTable.setPosition(stage.getWidth()/2-tutorialTable.getWidth()/2,
stage.getHeight()/2-tutorialTable.getHeight()/2);
stage.addActor(tutorialTable);
}
}

View file

@ -0,0 +1,99 @@
package com.unciv.ui.utils
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.Screen
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.GL20
import com.badlogic.gdx.graphics.g2d.Batch
import com.badlogic.gdx.graphics.g2d.SpriteBatch
import com.badlogic.gdx.scenes.scene2d.InputEvent
import com.badlogic.gdx.scenes.scene2d.Stage
import com.badlogic.gdx.scenes.scene2d.ui.Label
import com.badlogic.gdx.scenes.scene2d.ui.Skin
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener
import com.badlogic.gdx.utils.Align
import com.badlogic.gdx.utils.viewport.ExtendViewport
import com.unciv.models.linq.Linq
import com.unciv.ui.UnCivGame
open class CameraStageBaseScreen : Screen {
var game: UnCivGame
var stage: Stage
private val tutorialTexts = Linq<String>()
internal var isTutorialShowing = false
init {
this.game = UnCivGame.Current
stage = Stage(ExtendViewport(1000f, 600f
), batch)// FitViewport(1000,600)
Gdx.input.inputProcessor = stage
}
override fun show() {}
override fun render(delta: Float) {
Gdx.gl.glClearColor(0f, 0f, 0.2f, 1f)
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
stage.act()
stage.draw()
}
override fun resize(width: Int, height: Int) {
stage.viewport.update(width, height, true)
}
override fun pause() {}
override fun resume() {}
override fun hide() {}
override fun dispose() {}
fun displayTutorials(name: String, texts: Linq<String>) {
if (game.gameInfo.tutorial.contains(name)) return
game.gameInfo.tutorial.add(name)
tutorialTexts.addAll(texts)
if (!isTutorialShowing) displayTutorial()
}
fun displayTutorial() {
isTutorialShowing = true
val tutorialTable = Table().pad(10f)
tutorialTable.background(ImageGetter.getDrawable("skin/tileTableBackground.png")
.tint(Color(0x101050cf)))
val label = Label(tutorialTexts[0], skin)
label.setFontScale(1.5f)
label.setAlignment(Align.center)
tutorialTexts.removeAt(0)
tutorialTable.add(label).pad(10f).row()
val button = TextButton("Close", skin)
button.addListener(object : ClickListener() {
override fun clicked(event: InputEvent?, x: Float, y: Float) {
tutorialTable.remove()
if (!tutorialTexts.isEmpty())
displayTutorial()
else
isTutorialShowing = false
}
})
tutorialTable.add(button).pad(10f)
tutorialTable.pack()
tutorialTable.setPosition(stage.width / 2 - tutorialTable.width / 2,
stage.height / 2 - tutorialTable.height / 2)
stage.addActor(tutorialTable)
}
companion object {
var skin = Skin(Gdx.files.internal("skin/flat-earth-ui.json"))
internal var batch: Batch = SpriteBatch()
}
}

View file

@ -1,24 +0,0 @@
package com.unciv.ui.utils;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.utils.Json;
import com.unciv.ui.GameInfo;
import com.unciv.ui.UnCivGame;
public class GameSaver {
public static final String saveFilesFolder = "SaveFiles";
public static FileHandle GetSave(String GameName) {
return Gdx.files.local(saveFilesFolder + "/" + GameName);
}
public static void SaveGame(UnCivGame game, String GameName) {
GetSave(GameName).writeString(new Json().toJson(game.gameInfo), false);
}
public static void LoadGame(UnCivGame game, String GameName) {
game.gameInfo = new Json().fromJson(GameInfo.class, GetSave(GameName).readString());
game.gameInfo.setTransients();
}
}

View file

@ -0,0 +1,24 @@
package com.unciv.ui.utils
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.files.FileHandle
import com.badlogic.gdx.utils.Json
import com.unciv.logic.GameInfo
import com.unciv.ui.UnCivGame
object GameSaver {
val saveFilesFolder = "SaveFiles"
fun GetSave(GameName: String): FileHandle {
return Gdx.files.local(saveFilesFolder + "/" + GameName)
}
fun SaveGame(game: UnCivGame, GameName: String) {
GetSave(GameName).writeString(Json().toJson(game.gameInfo), false)
}
fun LoadGame(game: UnCivGame, GameName: String) {
game.gameInfo = Json().fromJson(GameInfo::class.java, GetSave(GameName).readString())
game.gameInfo.setTransients()
}
}

View file

@ -1,89 +0,0 @@
package com.unciv.ui.utils;
import com.badlogic.gdx.math.Vector2;
import com.unciv.models.linq.Linq;
import java.util.ArrayList;
public class HexMath
{
public static Vector2 GetVectorForAngle(float angle)
{
return new Vector2((float)Math.sin(angle), (float) Math.cos(angle));
}
public static Vector2 GetVectorByClockHour(int hour)
{
return GetVectorForAngle((float) ((2 * Math.PI) * (hour / 12f)));
}
// HexCoordinates are a (x,y) vector, where x is the vector getting us to the top-left hex (e.g. 10 o'clock)
// and y is the vector getting us to the top-right hex (e.g. 2 o'clock)
// Each (1,1) vector effectively brings us up a layer.
// For example, to get to the cell above me, I'll use a (1,1) vector.
// To get to the cell below the cell to my bottom-right, I'll use a (-1,-2) vector.
public static Vector2 Hex2WorldCoords(Vector2 hexCoord)
{
// Distance between cells = 2* normal of triangle = 2* (sqrt(3)/2) = sqrt(3)
Vector2 xVector = GetVectorByClockHour(10).scl((float) Math.sqrt(3));
Vector2 yVector = GetVectorByClockHour(2).scl((float) Math.sqrt(3));
return xVector.scl(hexCoord.x).add(yVector.scl(hexCoord.y));
}
public static ArrayList<Vector2> GetAdjacentVectors(Vector2 origin){
ArrayList<Vector2> vectors = new ArrayList<Vector2>();
vectors.add(new Vector2(1, 0));
vectors.add(new Vector2(1, 1));
vectors.add(new Vector2(0, 1));
vectors.add(new Vector2(-1, 0));
vectors.add(new Vector2(-1, -1));
vectors.add(new Vector2(0, -1));
for(Vector2 vector : vectors) vector.add(origin);
return vectors;
}
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
vectors.add(Current.cpy());
vectors.add(origin.cpy().scl(2).sub(Current)); // Get vector on other side of cloick
Current.add(1,0);
}
for (int i = 0; i < distance; i++) { // 8 to 10
vectors.add(Current.cpy());
vectors.add(origin.cpy().scl(2).sub(Current)); // Get vector on other side of cloick
Current.add(1,1);
}
for (int i = 0; i < distance; i++) { // 10 to 12
vectors.add(Current.cpy());
vectors.add(origin.cpy().scl(2).sub(Current)); // Get vector on other side of cloick
Current.add(0,1);
}
return vectors;
}
public static Linq<Vector2> GetVectorsInDistance(Vector2 origin, int distance) {
Linq<Vector2> hexesToReturn = new Linq<Vector2>();
for (int i = 0; i < distance + 1; i++) {
hexesToReturn.addAll(GetVectorsAtDistance(origin, i));
}
return hexesToReturn;
}
public static int GetDistance(Vector2 origin, Vector2 destination){ // Yes, this is a dumb implementation. But I can't be arsed to think of a better one right now, other stuff to do.
int distance = 0;
while(true){
if(GetVectorsAtDistance(origin,distance).contains(destination)) return distance;
distance++;
}
}
}

View file

@ -0,0 +1,86 @@
package com.unciv.ui.utils
import com.badlogic.gdx.math.Vector2
import com.unciv.models.linq.Linq
import java.util.ArrayList
object HexMath {
fun GetVectorForAngle(angle: Float): Vector2 {
return Vector2(Math.sin(angle.toDouble()).toFloat(), Math.cos(angle.toDouble()).toFloat())
}
fun GetVectorByClockHour(hour: Int): Vector2 {
return GetVectorForAngle((2 * Math.PI * (hour / 12f)).toFloat())
}
// HexCoordinates are a (x,y) vector, where x is the vector getting us to the top-left hex (e.g. 10 o'clock)
// and y is the vector getting us to the top-right hex (e.g. 2 o'clock)
// Each (1,1) vector effectively brings us up a layer.
// For example, to get to the cell above me, I'll use a (1,1) vector.
// To get to the cell below the cell to my bottom-right, I'll use a (-1,-2) vector.
fun Hex2WorldCoords(hexCoord: Vector2): Vector2 {
// Distance between cells = 2* normal of triangle = 2* (sqrt(3)/2) = sqrt(3)
val xVector = GetVectorByClockHour(10).scl(Math.sqrt(3.0).toFloat())
val yVector = GetVectorByClockHour(2).scl(Math.sqrt(3.0).toFloat())
return xVector.scl(hexCoord.x).add(yVector.scl(hexCoord.y))
}
fun GetAdjacentVectors(origin: Vector2): ArrayList<Vector2> {
val vectors = ArrayList<Vector2>()
vectors.add(Vector2(1f, 0f))
vectors.add(Vector2(1f, 1f))
vectors.add(Vector2(0f, 1f))
vectors.add(Vector2(-1f, 0f))
vectors.add(Vector2(-1f, -1f))
vectors.add(Vector2(0f, -1f))
for (vector in vectors) vector.add(origin)
return vectors
}
fun GetVectorsAtDistance(origin: Vector2, distance: Int): Linq<Vector2> {
val vectors = Linq<Vector2>()
if (distance == 0) {
vectors.add(origin.cpy())
return vectors
}
val Current = origin.cpy().sub(distance.toFloat(), distance.toFloat()) // start at 6 o clock
for (i in 0 until distance) { // From 6 to 8
vectors.add(Current.cpy())
vectors.add(origin.cpy().scl(2f).sub(Current)) // Get vector on other side of cloick
Current.add(1f, 0f)
}
for (i in 0 until distance) { // 8 to 10
vectors.add(Current.cpy())
vectors.add(origin.cpy().scl(2f).sub(Current)) // Get vector on other side of cloick
Current.add(1f, 1f)
}
for (i in 0 until distance) { // 10 to 12
vectors.add(Current.cpy())
vectors.add(origin.cpy().scl(2f).sub(Current)) // Get vector on other side of cloick
Current.add(0f, 1f)
}
return vectors
}
fun GetVectorsInDistance(origin: Vector2, distance: Int): Linq<Vector2> {
val hexesToReturn = Linq<Vector2>()
for (i in 0 until distance + 1) {
hexesToReturn.addAll(GetVectorsAtDistance(origin, i))
}
return hexesToReturn
}
fun GetDistance(origin: Vector2, destination: Vector2): Int { // Yes, this is a dumb implementation. But I can't be arsed to think of a better one right now, other stuff to do.
var distance = 0
while (true) {
if (GetVectorsAtDistance(origin, distance).contains(destination)) return distance
distance++
}
}
}

View file

@ -1,46 +0,0 @@
package com.unciv.ui.utils;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.utils.Drawable;
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable;
import java.util.HashMap;
public class ImageGetter {
public static HashMap<String, TextureRegion> textureRegionByFileName = new HashMap<String, TextureRegion>();
public static final String WhiteDot="skin/whiteDot.png";
public static Image getImage(String fileName) {
return new Image(getTextureRegion(fileName));
}
public static TextureRegionDrawable getDrawable(String fileName) {
TextureRegionDrawable drawable = new TextureRegionDrawable(getTextureRegion(fileName));
drawable.setMinHeight(0);
drawable.setMinWidth(0);
return drawable;
}
public static Drawable getSingleColorDrawable(Color color){
return getDrawable("skin/whiteDot.png").tint(color);
}
private static TextureRegion getTextureRegion(String fileName) {
try {
if (!textureRegionByFileName.containsKey(fileName))
textureRegionByFileName.put(fileName, new TextureRegion(new Texture(Gdx.files.internal(fileName))));
}catch (Exception ex){
System.out.print("File "+fileName+" not found!");
}
return textureRegionByFileName.get(fileName);
}
public static Image getStatIcon(String name) {
return getImage("StatIcons/20x" + name + "5.png");
}
}

View file

@ -0,0 +1,48 @@
package com.unciv.ui.utils
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.graphics.Texture
import com.badlogic.gdx.graphics.g2d.TextureRegion
import com.badlogic.gdx.scenes.scene2d.ui.Image
import com.badlogic.gdx.scenes.scene2d.utils.Drawable
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable
import java.util.HashMap
object ImageGetter {
var textureRegionByFileName = HashMap<String, TextureRegion>()
val WhiteDot = "skin/whiteDot.png"
fun getImage(fileName: String): Image {
return Image(getTextureRegion(fileName))
}
fun getDrawable(fileName: String): TextureRegionDrawable {
val drawable = TextureRegionDrawable(getTextureRegion(fileName))
drawable.minHeight = 0f
drawable.minWidth = 0f
return drawable
}
fun getSingleColorDrawable(color: Color): Drawable {
return getDrawable(WhiteDot).tint(color)
}
private fun getTextureRegion(fileName: String): TextureRegion {
try {
if (!textureRegionByFileName.containsKey(fileName))
textureRegionByFileName[fileName] = TextureRegion(Texture(Gdx.files.internal(fileName)))
} catch (ex: Exception) {
print("File $fileName not found!")
throw ex
}
return textureRegionByFileName[fileName]!!
}
fun getStatIcon(name: String): Image {
return getImage("StatIcons/20x" + name + "5.png")
}
}

View file

@ -1,75 +0,0 @@
package com.unciv.ui.worldscreen;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable;
import com.badlogic.gdx.utils.Align;
import com.unciv.logic.civilization.CivilizationInfo;
import com.unciv.models.stats.CivStats;
import com.unciv.ui.utils.CameraStageBaseScreen;
import com.unciv.ui.utils.ImageGetter;
public class CivStatsTable extends Table {
CivStatsTable(){
TextureRegionDrawable civBackground = ImageGetter.getDrawable("skin/civTableBackground.png");
setBackground(civBackground.tint(new Color(0x004085bf)));
}
void update(final WorldScreen screen) {
CivilizationInfo civInfo = screen.civInfo;
Skin skin = CameraStageBaseScreen.skin;
clear();
row().pad(15);
TextButton CivilopediaButton = new TextButton("Menu", skin);
CivilopediaButton.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
screen.optionsTable.setVisible(!screen.optionsTable.isVisible());
}
});
CivilopediaButton.getLabel().setFontScale(screen.buttonScale);
add(CivilopediaButton)
.size(CivilopediaButton.getWidth() * screen.buttonScale, CivilopediaButton.getHeight() * screen.buttonScale);
add(new Label("Turns: " + civInfo.gameInfo.turns + "/400", skin));
CivStats nextTurnStats = civInfo.getStatsForNextTurn();
add(new Label("Gold: " + Math.round(civInfo.gold)
+ "(" + (nextTurnStats.gold > 0 ? "+" : "") + Math.round(nextTurnStats.gold) + ")", skin));
Label scienceLabel = new Label("Science: +" + Math.round(nextTurnStats.science)
+ "\r\n" + civInfo.tech.getAmountResearchedText(), skin);
scienceLabel.setAlignment(Align.center);
add(scienceLabel);
String happinessText = "Happiness: " + Math.round(civInfo.getHappinessForNextTurn());
if (civInfo.goldenAges.isGoldenAge())
happinessText += "\r\n GOLDEN AGE (" + civInfo.goldenAges.turnsLeftForCurrentGoldenAge + ")";
else
happinessText += "\r\n (" + civInfo.goldenAges.storedHappiness + "/"
+ civInfo.goldenAges.happinessRequiredForNextGoldenAge() + ")";
Label happinessLabel = new Label(happinessText, skin);
happinessLabel.setAlignment(Align.center);
add(happinessLabel);
String cultureString = "Culture: " + "+" + Math.round(nextTurnStats.culture) + "\r\n"
+ "(" + civInfo.policies.storedCulture + "/" + civInfo.policies.getCultureNeededForNextPolicy() + ")";
Label cultureLabel = new Label(cultureString, skin);
cultureLabel.setAlignment(Align.center);
add(cultureLabel);
pack();
setPosition(10, screen.stage.getHeight() - 10 - getHeight());
setWidth(screen.stage.getWidth() - 20);
}
}

View file

@ -0,0 +1,67 @@
package com.unciv.ui.worldscreen
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.ui.Label
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
import com.badlogic.gdx.utils.Align
import com.unciv.ui.cityscreen.addClickListener
import com.unciv.ui.utils.CameraStageBaseScreen
import com.unciv.ui.utils.ImageGetter
class CivStatsTable internal constructor() : Table() {
init {
val civBackground = ImageGetter.getDrawable("skin/civTableBackground.png")
background = civBackground.tint(Color(0x004085bf))
}
internal fun update(screen: WorldScreen) {
val civInfo = screen.civInfo
val skin = CameraStageBaseScreen.skin
clear()
row().pad(15f)
val civilopediaButton = TextButton("Menu", skin)
civilopediaButton.addClickListener {
screen.optionsTable.isVisible = !screen.optionsTable.isVisible
}
civilopediaButton.label.setFontScale(screen.buttonScale)
add(civilopediaButton)
.size(civilopediaButton.width * screen.buttonScale, civilopediaButton.height * screen.buttonScale)
add(Label("Turns: " + civInfo.gameInfo.turns + "/400", skin))
val nextTurnStats = civInfo.getStatsForNextTurn()
add(Label("Gold: " + Math.round(civInfo.gold.toFloat())
+ "(" + (if (nextTurnStats.gold > 0) "+" else "") + Math.round(nextTurnStats.gold) + ")", skin))
val scienceLabel = Label("Science: +" + Math.round(nextTurnStats.science)
+ "\r\n" + civInfo.tech.getAmountResearchedText(), skin)
scienceLabel.setAlignment(Align.center)
add(scienceLabel)
var happinessText = "Happiness: " + civInfo.happiness
if (civInfo.goldenAges.isGoldenAge())
happinessText += "\r\n GOLDEN AGE (" + civInfo.goldenAges.turnsLeftForCurrentGoldenAge + ")"
else
happinessText += ("\r\n (" + civInfo.goldenAges.storedHappiness + "/"
+ civInfo.goldenAges.happinessRequiredForNextGoldenAge() + ")")
val happinessLabel = Label(happinessText, skin)
happinessLabel.setAlignment(Align.center)
add(happinessLabel)
val cultureString = ("Culture: " + "+" + Math.round(nextTurnStats.culture) + "\r\n"
+ "(" + civInfo.policies.storedCulture + "/" + civInfo.policies.getCultureNeededForNextPolicy() + ")")
val cultureLabel = Label(cultureString, skin)
cultureLabel.setAlignment(Align.center)
add(cultureLabel)
pack()
setPosition(10f, screen.stage.height - 10f - height)
width = screen.stage.width - 20
}
}

View file

@ -1,59 +0,0 @@
package com.unciv.ui.worldscreen;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Touchable;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.badlogic.gdx.utils.Predicate;
import com.unciv.logic.map.TileInfo;
import com.unciv.models.linq.Linq;
import com.unciv.ui.utils.CameraStageBaseScreen;
public class IdleUnitButton extends TextButton {
final WorldScreen worldScreen;
IdleUnitButton(final WorldScreen worldScreen) {
super("Select next idle unit", CameraStageBaseScreen.skin);
this.worldScreen = worldScreen;
setPosition(worldScreen.stage.getWidth() / 2 - getWidth() / 2, 5);
addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
Linq<TileInfo> tilesWithIdleUnits = worldScreen.civInfo.gameInfo.tileMap.getValues().where(new Predicate<TileInfo>() {
@Override
public boolean evaluate(TileInfo arg0) {
return arg0.hasIdleUnit();
}
});
TileInfo tileToSelect;
if (!tilesWithIdleUnits.contains(worldScreen.tileMapHolder.selectedTile))
tileToSelect = tilesWithIdleUnits.get(0);
else {
int index = tilesWithIdleUnits.indexOf(worldScreen.tileMapHolder.selectedTile) + 1;
if (tilesWithIdleUnits.size() == index) index = 0;
tileToSelect = tilesWithIdleUnits.get(index);
}
worldScreen.tileMapHolder.setCenterPosition(tileToSelect.position);
worldScreen.tileMapHolder.selectedTile = tileToSelect;
worldScreen.update();
}
});
}
void update() {
if (worldScreen.civInfo.gameInfo.tileMap.getValues().any(new Predicate<TileInfo>() {
@Override
public boolean evaluate(TileInfo arg0) {
return arg0.hasIdleUnit();
}
})) {
worldScreen.idleUnitButton.setColor(Color.WHITE);
worldScreen.idleUnitButton.setTouchable(Touchable.enabled);
} else {
worldScreen.idleUnitButton.setColor(Color.GRAY);
worldScreen.idleUnitButton.setTouchable(Touchable.disabled);
}
}
}

View file

@ -0,0 +1,39 @@
package com.unciv.ui.worldscreen
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.Touchable
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
import com.unciv.logic.map.TileInfo
import com.unciv.ui.cityscreen.addClickListener
import com.unciv.ui.utils.CameraStageBaseScreen
class IdleUnitButton internal constructor(internal val worldScreen: WorldScreen) : TextButton("Select next idle unit", CameraStageBaseScreen.skin) {
init {
setPosition(worldScreen.stage.width / 2 - width / 2, 5f)
addClickListener {
val tilesWithIdleUnits = worldScreen.civInfo.gameInfo.tileMap.values.where { arg0 -> arg0.hasIdleUnit() }
val tileToSelect: TileInfo
if (!tilesWithIdleUnits.contains(worldScreen.tileMapHolder.selectedTile))
tileToSelect = tilesWithIdleUnits[0]
else {
var index = tilesWithIdleUnits.indexOf(worldScreen.tileMapHolder.selectedTile) + 1
if (tilesWithIdleUnits.size == index) index = 0
tileToSelect = tilesWithIdleUnits[index]
}
worldScreen.tileMapHolder.setCenterPosition(tileToSelect.position)
worldScreen.tileMapHolder.selectedTile = tileToSelect
worldScreen.update()
}
}
internal fun update() {
if (worldScreen.civInfo.gameInfo.tileMap.values.any { arg0 -> arg0.hasIdleUnit() }) {
worldScreen.idleUnitButton.color = Color.WHITE
worldScreen.idleUnitButton.touchable = Touchable.enabled
} else {
worldScreen.idleUnitButton.color = Color.GRAY
worldScreen.idleUnitButton.touchable = Touchable.disabled
}
}
}

View file

@ -1,57 +0,0 @@
package com.unciv.ui.worldscreen;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.unciv.logic.civilization.Notification;
import com.unciv.models.linq.Linq;
import com.unciv.ui.utils.CameraStageBaseScreen;
import com.unciv.ui.utils.ImageGetter;
public class NotificationsScroll extends ScrollPane {
final Linq<Notification> notifications;
Table notificationsTable = new Table();
final WorldScreen worldScreen;
public NotificationsScroll(Linq<Notification> notifications, WorldScreen worldScreen) {
super(null);
this.notifications = notifications;
this.worldScreen = worldScreen;
setWidget(notificationsTable);
}
void update() {
notificationsTable.clearChildren();
for (final Notification notification : notifications) {
Label label = new Label(notification.text, CameraStageBaseScreen.skin);
label.setColor(Color.WHITE);
label.setFontScale(1.2f);
Table minitable = new Table();
minitable.background(ImageGetter.getDrawable("skin/civTableBackground.png")
.tint(new Color(0x004085bf)));
minitable.add(label).pad(5);
if(notification.location!=null){
minitable.addListener(new ClickListener(){
@Override
public void clicked(InputEvent event, float x, float y) {
worldScreen.tileMapHolder.setCenterPosition(notification.location);
}
});
}
notificationsTable.add(minitable).pad(5);
notificationsTable.row();
}
notificationsTable.pack();
setSize(worldScreen.stage.getWidth() / 3,
Math.min(notificationsTable.getHeight(),worldScreen.stage.getHeight() / 3));
}
}

View file

@ -0,0 +1,47 @@
package com.unciv.ui.worldscreen
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.ui.Label
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.unciv.logic.civilization.Notification
import com.unciv.models.linq.Linq
import com.unciv.ui.cityscreen.addClickListener
import com.unciv.ui.utils.CameraStageBaseScreen
import com.unciv.ui.utils.ImageGetter
class NotificationsScroll(private val notifications: Linq<Notification>, internal val worldScreen: WorldScreen) : ScrollPane(null) {
private var notificationsTable = Table()
init {
widget = notificationsTable
}
internal fun update() {
notificationsTable.clearChildren()
for (notification in notifications) {
val label = Label(notification.text, CameraStageBaseScreen.skin)
label.color = Color.WHITE
label.setFontScale(1.2f)
val minitable = Table()
minitable.background(ImageGetter.getDrawable("skin/civTableBackground.png")
.tint(Color(0x004085bf)))
minitable.add(label).pad(5f)
if (notification.location != null) {
minitable.addClickListener {
worldScreen.tileMapHolder.setCenterPosition(notification.location!!)
}
}
notificationsTable.add(minitable).pad(5f)
notificationsTable.row()
}
notificationsTable.pack()
setSize(worldScreen.stage.width / 3,
Math.min(notificationsTable.height, worldScreen.stage.height / 3))
}
}

View file

@ -1,272 +0,0 @@
package com.unciv.ui.worldscreen;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.Touchable;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.badlogic.gdx.scenes.scene2d.utils.Drawable;
import com.badlogic.gdx.utils.Align;
import com.badlogic.gdx.utils.Predicate;
import com.unciv.logic.civilization.CivilizationInfo;
import com.unciv.logic.map.TileInfo;
import com.unciv.models.gamebasics.Building;
import com.unciv.models.gamebasics.GameBasics;
import com.unciv.models.gamebasics.TileImprovement;
import com.unciv.models.linq.Linq;
import com.unciv.models.stats.FullStats;
import com.unciv.ui.tilegroups.TileGroup;
import com.unciv.ui.pickerscreens.TechPickerScreen;
import com.unciv.ui.utils.CameraStageBaseScreen;
import com.unciv.ui.utils.ImageGetter;
import java.util.HashMap;
public class TileInfoTable extends Table {
private final WorldScreen worldScreen;
final CivilizationInfo civInfo;
public TileInfoTable(WorldScreen worldScreen, CivilizationInfo civInfo){
this.worldScreen = worldScreen;
this.civInfo = civInfo;
Drawable tileTableBackground = ImageGetter.getDrawable("skin/tileTableBackground.png")
.tint(new Color(0x004085bf));
tileTableBackground.setMinHeight(0);
tileTableBackground.setMinWidth(0);
setBackground(tileTableBackground);
}
void updateTileTable(final TileInfo selectedTile) {
if (selectedTile == null) return;
clearChildren();
FullStats stats = selectedTile.getTileStats(civInfo);
pad(20);
columnDefaults(0).padRight(10);
Skin skin = CameraStageBaseScreen.skin;
if (selectedTile.explored) {
add(new Label(selectedTile.toString(), skin)).colspan(2);
row();
HashMap<String, Integer> TileStatsValues = stats.toDict();
for (String key : TileStatsValues.keySet()) {
if (TileStatsValues.get(key) == 0)
continue; // this tile gives nothing of this stat, so why even display it?
add(ImageGetter.getStatIcon(key)).align(Align.right);
add(new Label(TileStatsValues.get(key) + "", skin)).align(Align.left);
row();
}
}
if (selectedTile.unit != null) {
TextButton moveUnitButton = new TextButton("Move to", skin);
if (worldScreen.tileMapHolder.unitTile == selectedTile) moveUnitButton = new TextButton("Stop movement", skin);
moveUnitButton.getLabel().setFontScale(worldScreen.buttonScale);
if (selectedTile.unit.currentMovement == 0) {
moveUnitButton.setColor(Color.GRAY);
moveUnitButton.setTouchable(Touchable.disabled);
}
moveUnitButton.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
if (worldScreen.tileMapHolder.unitTile != null) {
worldScreen.tileMapHolder.unitTile = null;
worldScreen.update();
return;
}
worldScreen.tileMapHolder.unitTile = selectedTile;
// Set all tiles transparent except those in unit range
for (TileGroup TG : worldScreen.tileGroups.linqValues()) TG.setColor(0, 0, 0, 0.3f);
for (TileInfo tile : civInfo.gameInfo.tileMap.getDistanceToTilesWithinTurn(worldScreen.tileMapHolder.unitTile.position, worldScreen.tileMapHolder.unitTile.unit.currentMovement, civInfo.tech.isResearched("Machinery")).keySet()) {
worldScreen.tileGroups.get(tile.position.toString()).setColor(Color.WHITE);
}
worldScreen.update();
}
});
add(moveUnitButton).colspan(2)
.size(moveUnitButton.getWidth() * worldScreen.buttonScale, moveUnitButton.getHeight() * worldScreen.buttonScale);
if (selectedTile.unit.name.equals("Settler")) {
addUnitAction("Found City",
!civInfo.gameInfo.tileMap.getTilesInDistance(selectedTile.position, 2).any(new Predicate<TileInfo>() {
@Override
public boolean evaluate(TileInfo arg0) {
return arg0.isCityCenter();
}
}),
new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
Linq<String> tutorial = new Linq<String>();
tutorial.add("You have founded a city!" +
"\r\nCities are the lifeblood of your empire," +
"\r\n providing gold and science empire-wide," +
"\r\n which are displayed on the top bar.");
tutorial.add("Science is used to research technologies." +
"\r\nYou can enter the technology screen by clicking" +
"\r\n on the button on the top-left, underneath the bar");
tutorial.add("You can click the city name to enter" +
"\r\n the city screen to assign population," +
"\r\n choose production, and see information on the city");
worldScreen.displayTutorials("CityFounded",tutorial);
civInfo.addCity(selectedTile.position);
if (worldScreen.tileMapHolder.unitTile == selectedTile)
worldScreen.tileMapHolder.unitTile = null; // The settler was in the middle of moving and we then founded a city with it
selectedTile.unit = null; // Remove settler!
worldScreen.update();
}
});
}
if (selectedTile.unit.name.equals("Worker")) {
String improvementButtonText = selectedTile.improvementInProgress == null ?
"Construct\r\nimprovement" : selectedTile.improvementInProgress + "\r\nin progress";
addUnitAction(improvementButtonText, !selectedTile.isCityCenter() ||
GameBasics.TileImprovements.linqValues().any(new Predicate<TileImprovement>() {
@Override
public boolean evaluate(TileImprovement arg0) {
return selectedTile.canBuildImprovement(arg0,civInfo);
}
})
, new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
worldScreen.game.setScreen(new com.unciv.ui.pickerscreens.ImprovementPickerScreen(selectedTile));
}
});
addUnitAction("automation".equals(selectedTile.unit.action) ? "Stop automation" : "Automate", true,
new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
if ("automation".equals(selectedTile.unit.action))
selectedTile.unit.action = null;
else {
selectedTile.unit.action = "automation";
selectedTile.unit.doAutomatedAction(selectedTile);
}
worldScreen.update();
}
});
}
if (selectedTile.unit.name.equals("Great Scientist")) {
addUnitAction("Discover Technology", true,
new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
civInfo.tech.freeTechs += 1;
selectedTile.unit = null;// destroy!
worldScreen.game.setScreen(new TechPickerScreen(true, civInfo));
}
});
addUnitAction("Construct Academy", true,
new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
selectedTile.improvement = "Academy";
selectedTile.unit = null;// destroy!
worldScreen.update();
}
});
}
if (selectedTile.unit.name.equals("Great Artist")) {
addUnitAction("Start Golden Age", true,
new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
civInfo.goldenAges.enterGoldenAge();
selectedTile.unit = null;// destroy!
worldScreen.update();
}
});
addUnitAction("Construct Landmark", true,
new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
selectedTile.improvement = "Landmark";
selectedTile.unit = null;// destroy!
worldScreen.update();
}
});
}
if (selectedTile.unit.name.equals("Great Engineer")) {
addUnitAction("Hurry Wonder", selectedTile.isCityCenter() &&
selectedTile.getCity().cityConstructions.getCurrentConstruction() instanceof Building &&
((Building) selectedTile.getCity().cityConstructions.getCurrentConstruction()).isWonder,
new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
selectedTile.getCity().cityConstructions.addConstruction(300 + (30 * selectedTile.getCity().population.population)); //http://civilization.wikia.com/wiki/Great_engineer_(Civ5)
selectedTile.unit = null; // destroy!
worldScreen.update();
}
});
addUnitAction("Construct Manufactory", true,
new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
selectedTile.improvement = "Manufactory";
selectedTile.unit = null;// destroy!
worldScreen.update();
}
});
}
if (selectedTile.unit.name.equals("Great Merchant")) {
addUnitAction("Conduct Trade Mission", true,
new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
civInfo.gold += 350; // + 50 * era_number - todo!
selectedTile.unit = null; // destroy!
worldScreen.update();
}
});
addUnitAction("Construct Customs House", true,
new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
selectedTile.improvement = "Customs House";
selectedTile.unit = null;// destroy!
worldScreen.update();
}
});
}
}
pack();
setPosition(worldScreen.stage.getWidth() - 10 - getWidth(), 10);
}
private void addUnitAction(String actionText, boolean canAct, ClickListener action) {
TextButton actionButton = new TextButton(actionText, CameraStageBaseScreen.skin);
actionButton.getLabel().setFontScale(worldScreen.buttonScale);
actionButton.addListener(action);
if (worldScreen.tileMapHolder.selectedTile.unit.currentMovement == 0 || !canAct) {
actionButton.setColor(Color.GRAY);
actionButton.setTouchable(Touchable.disabled);
}
row();
add(actionButton).colspan(2)
.size(actionButton.getWidth() * worldScreen.buttonScale, actionButton.getHeight() * worldScreen.buttonScale);
}
}

View file

@ -0,0 +1,216 @@
package com.unciv.ui.worldscreen
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.InputEvent
import com.badlogic.gdx.scenes.scene2d.Touchable
import com.badlogic.gdx.scenes.scene2d.ui.Label
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener
import com.badlogic.gdx.utils.Align
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.map.TileInfo
import com.unciv.models.gamebasics.Building
import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.linq.Linq
import com.unciv.ui.cityscreen.addClickListener
import com.unciv.ui.pickerscreens.TechPickerScreen
import com.unciv.ui.utils.CameraStageBaseScreen
import com.unciv.ui.utils.ImageGetter
class TileInfoTable(private val worldScreen: WorldScreen, internal val civInfo: CivilizationInfo) : Table() {
init {
val tileTableBackground = ImageGetter.getDrawable("skin/tileTableBackground.png")
.tint(Color(0x004085bf))
tileTableBackground.minHeight = 0f
tileTableBackground.minWidth = 0f
background = tileTableBackground
}
internal fun updateTileTable(selectedTile: TileInfo) {
clearChildren()
val stats = selectedTile.getTileStats(civInfo)
pad(20f)
columnDefaults(0).padRight(10f)
val skin = CameraStageBaseScreen.skin
if (selectedTile.explored) {
add(Label(selectedTile.toString(), skin)).colspan(2)
row()
for (entry in stats.toHashMap().filterNot { it.value == 0f }) {
add(ImageGetter.getStatIcon(entry.key.toString())).align(Align.right)
add(Label(entry.value.toInt().toString(), skin)).align(Align.left)
row()
}
}
if (selectedTile.unit != null) {
var moveUnitButton = TextButton("Move to", skin)
if (worldScreen.tileMapHolder.unitTile == selectedTile) moveUnitButton = TextButton("Stop movement", skin)
moveUnitButton.label.setFontScale(worldScreen.buttonScale)
if (selectedTile.unit!!.currentMovement == 0f) {
moveUnitButton.color = Color.GRAY
moveUnitButton.touchable = Touchable.disabled
}
moveUnitButton.addListener(object : ClickListener() {
override fun clicked(event: InputEvent?, x: Float, y: Float) {
if (worldScreen.tileMapHolder.unitTile != null) {
worldScreen.tileMapHolder.unitTile = null
worldScreen.update()
return
}
worldScreen.tileMapHolder.unitTile = selectedTile
// Set all tiles transparent except those in unit range
for (TG in worldScreen.tileGroups.linqValues()) TG.setColor(0f, 0f, 0f, 0.3f)
for (tile in civInfo.gameInfo.tileMap.getDistanceToTilesWithinTurn(
worldScreen.tileMapHolder.unitTile!!.position,
worldScreen.tileMapHolder.unitTile!!.unit!!.currentMovement,
civInfo.tech.isResearched("Machinery")
).keys) {
worldScreen.tileGroups[tile.position.toString()]!!.color = Color.WHITE
}
worldScreen.update()
}
})
add(moveUnitButton).colspan(2)
.size(moveUnitButton.width * worldScreen.buttonScale, moveUnitButton.height * worldScreen.buttonScale)
if (selectedTile.unit!!.name == "Settler") {
addUnitAction("Found City",
!civInfo.gameInfo.tileMap.getTilesInDistance(selectedTile.position, 2).any { it.isCityCenter },
{
val tutorial = Linq<String>()
tutorial.add("You have founded a city!" +
"\r\nCities are the lifeblood of your empire," +
"\r\n providing gold and science empire-wide," +
"\r\n which are displayed on the top bar.")
tutorial.add("Science is used to research technologies." +
"\r\nYou can enter the technology screen by clicking" +
"\r\n on the button on the top-left, underneath the bar")
tutorial.add("You can click the city name to enter" +
"\r\n the city screen to assign population," +
"\r\n choose production, and see information on the city")
worldScreen.displayTutorials("CityFounded", tutorial)
civInfo.addCity(selectedTile.position)
if (worldScreen.tileMapHolder.unitTile == selectedTile)
worldScreen.tileMapHolder.unitTile = null // The settler was in the middle of moving and we then founded a city with it
selectedTile.unit = null // Remove settler!
worldScreen.update()
})
}
if (selectedTile.unit!!.name == "Worker") {
val improvementButtonText = if (selectedTile.improvementInProgress == null)
"Construct\r\nimprovement"
else
selectedTile.improvementInProgress!! + "\r\nin progress"
addUnitAction(improvementButtonText, !selectedTile.isCityCenter || GameBasics.TileImprovements.linqValues().any { arg0 -> selectedTile.canBuildImprovement(arg0, civInfo) },
{ worldScreen.game.screen = com.unciv.ui.pickerscreens.ImprovementPickerScreen(selectedTile) })
addUnitAction(if ("automation" == selectedTile.unit!!.action) "Stop automation" else "Automate", true, {
if ("automation" == selectedTile.unit!!.action)
selectedTile.unit!!.action = null
else {
selectedTile.unit!!.action = "automation"
selectedTile.unit!!.doAutomatedAction(selectedTile)
}
worldScreen.update()
})
}
if (selectedTile.unit!!.name == "Great Scientist") {
addUnitAction("Discover Technology", true,
{
civInfo.tech.freeTechs += 1
selectedTile.unit = null// destroy!
worldScreen.game.screen = TechPickerScreen(true, civInfo)
})
addUnitAction("Construct Academy", true, {
selectedTile.improvement = "Academy"
selectedTile.unit = null// destroy!
worldScreen.update()
}
)
}
if (selectedTile.unit!!.name == "Great Artist") {
addUnitAction("Start Golden Age", true,
{
civInfo.goldenAges.enterGoldenAge()
selectedTile.unit = null// destroy!
worldScreen.update()
}
)
addUnitAction("Construct Landmark", true,
{
selectedTile.improvement = "Landmark"
selectedTile.unit = null// destroy!
worldScreen.update()
}
)
}
if (selectedTile.unit!!.name == "Great Engineer") {
addUnitAction("Hurry Wonder", selectedTile.isCityCenter &&
selectedTile.city!!.cityConstructions.getCurrentConstruction() is Building &&
(selectedTile.city!!.cityConstructions.getCurrentConstruction() as Building).isWonder,
{
selectedTile.city!!.cityConstructions.addConstruction(300 + 30 * selectedTile.city!!.population.population) //http://civilization.wikia.com/wiki/Great_engineer_(Civ5)
selectedTile.unit = null // destroy!
worldScreen.update()
})
addUnitAction("Construct Manufactory", true,
{
selectedTile.improvement = "Manufactory"
selectedTile.unit = null// destroy!
worldScreen.update()
})
}
if (selectedTile.unit!!.name == "Great Merchant") {
addUnitAction("Conduct Trade Mission", true,
{
civInfo.gold += 350 // + 50 * era_number - todo!
selectedTile.unit = null // destroy!
worldScreen.update()
})
addUnitAction("Construct Customs House", true,
{
selectedTile.improvement = "Customs House"
selectedTile.unit = null// destroy!
worldScreen.update()
})
}
}
pack()
setPosition(worldScreen.stage.width - 10f - width, 10f)
}
private fun addUnitAction(actionText: String, canAct: Boolean, action: ()->Unit) {
val actionButton = TextButton(actionText, CameraStageBaseScreen.skin)
actionButton.label.setFontScale(worldScreen.buttonScale)
actionButton.addClickListener(action)
if (worldScreen.tileMapHolder.selectedTile!!.unit!!.currentMovement == 0f || !canAct) {
actionButton.color = Color.GRAY
actionButton.touchable = Touchable.disabled
}
row()
add(actionButton).colspan(2)
.size(actionButton.width * worldScreen.buttonScale, actionButton.height * worldScreen.buttonScale)
}
}

View file

@ -1,172 +0,0 @@
package com.unciv.ui.worldscreen;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.Group;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane;
import com.badlogic.gdx.scenes.scene2d.utils.ActorGestureListener;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.badlogic.gdx.utils.Predicate;
import com.unciv.logic.civilization.CivilizationInfo;
import com.unciv.logic.map.TileInfo;
import com.unciv.logic.map.TileMap;
import com.unciv.models.linq.Linq;
import com.unciv.models.linq.LinqHashMap;
import com.unciv.ui.tilegroups.TileGroup;
import com.unciv.ui.tilegroups.WorldTileGroup;
import com.unciv.ui.utils.HexMath;
import java.util.HashSet;
public class TileMapHolder extends ScrollPane {
final WorldScreen worldScreen;
final TileMap tileMap;
final CivilizationInfo civInfo;
TileInfo selectedTile = null;
TileInfo unitTile = null;
public TileMapHolder(final WorldScreen worldScreen, TileMap tileMap, CivilizationInfo civInfo) {
super(null);
this.worldScreen=worldScreen;
this.tileMap = tileMap;
this.civInfo = civInfo;
}
void addTiles() {
final Group allTiles = new Group();
float topX = 0;
float topY = 0;
float bottomX = 0;
float bottomY = 0;
for (final TileInfo tileInfo : tileMap.getValues()) {
final WorldTileGroup group = new WorldTileGroup(tileInfo);
group.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
Linq<String> tutorial = new Linq<String>();
tutorial.add("Clicking on a tile selects that tile," +
"\r\n and displays information on that tile on the bottom-right," +
"\r\n as well as unit actions, if the tile contains a unit");
worldScreen.displayTutorials("TileClicked",tutorial);
selectedTile = tileInfo;
if (unitTile != null && group.tileInfo.unit == null) {
LinqHashMap<TileInfo, Float> distanceToTiles = tileMap.getDistanceToTilesWithinTurn(unitTile.position, unitTile.unit.currentMovement, civInfo.tech.isResearched("Machinery"));
if (distanceToTiles.containsKey(selectedTile)) {
unitTile.moveUnitToTile(group.tileInfo, distanceToTiles.get(selectedTile));
} else {
unitTile.unit.action = "moveTo " + ((int) selectedTile.position.x) + "," + ((int) selectedTile.position.y);
unitTile.unit.doPreTurnAction(unitTile);
}
unitTile = null;
selectedTile = group.tileInfo;
}
worldScreen.update();
}
});
Vector2 positionalVector = HexMath.Hex2WorldCoords(tileInfo.position);
int groupSize = 50;
group.setPosition(worldScreen.stage.getWidth() / 2 + positionalVector.x * 0.8f * groupSize,
worldScreen.stage.getHeight() / 2 + positionalVector.y * 0.8f * groupSize);
worldScreen.tileGroups.put(tileInfo.position.toString(), group);
allTiles.addActor(group);
topX = Math.max(topX, group.getX() + groupSize);
topY = Math.max(topY, group.getY() + groupSize);
bottomX = Math.min(bottomX, group.getX());
bottomY = Math.min(bottomY, group.getY());
}
for (TileGroup group : worldScreen.tileGroups.linqValues()) {
group.moveBy(-bottomX+50, -bottomY+50);
}
// there are tiles "below the zero",
// so we zero out the starting position of the whole board so they will be displayed as well
allTiles.setSize(100 + topX - bottomX, 100 + topY - bottomY);
setWidget(allTiles);
setFillParent(true);
setOrigin(worldScreen.stage.getWidth() / 2, worldScreen.stage.getHeight() / 2);
setSize(worldScreen.stage.getWidth(), worldScreen.stage.getHeight());
addListener(new ActorGestureListener() {
public float lastScale = 1;
float lastInitialDistance = 0;
@Override
public void zoom(InputEvent event, float initialDistance, float distance) {
if (lastInitialDistance != initialDistance) {
lastInitialDistance = initialDistance;
lastScale = getScaleX();
}
float scale = (float) Math.sqrt(distance / initialDistance) * lastScale;
if (scale < 1) return;
setScale(scale);
}
});
}
void updateTiles() {
for (WorldTileGroup WG : worldScreen.tileGroups.linqValues()) WG.update(worldScreen);
if (unitTile != null)
return; // While we're in "unit move" mode, no tiles but the tiles the unit can move to will be "visible"
// YES A TRIPLE FOR, GOT PROBLEMS WITH THAT?
// Seriously though, there is probably a more efficient way of doing this, probably?
// The original implementation caused serious lag on android, so efficiency is key, here
for (WorldTileGroup WG : worldScreen.tileGroups.linqValues()) WG.setIsViewable(false);
HashSet<String> ViewableVectorStrings = new HashSet<String>();
// tiles adjacent to city tiles
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.getValues()
.where(new Predicate<TileInfo>() {
@Override
public boolean evaluate(TileInfo arg0) {
return arg0.unit != null;
}
}))
for (TileInfo tileInfo : tileMap.getViewableTiles(tile.position,2))
ViewableVectorStrings.add(tileInfo.position.toString());
for (String string : ViewableVectorStrings)
if (worldScreen.tileGroups.containsKey(string))
worldScreen.tileGroups.get(string).setIsViewable(true);
}
public void setCenterPosition(final Vector2 vector) {
TileGroup TG = worldScreen.tileGroups.linqValues().first(new Predicate<WorldTileGroup>() {
@Override
public boolean evaluate(WorldTileGroup arg0) {
return arg0.tileInfo.position.equals(vector);
}
});
layout(); // Fit the scroll pane to the contents - otherwise, setScroll won't work!
// We want to center on the middle of TG (TG.getX()+TG.getWidth()/2)
// and so the scroll position (== where the screen starts) needs to be half a screen away
setScrollX(TG.getX() + TG.getWidth() / 2 - worldScreen.stage.getWidth() / 2);
// Here it's the same, only the Y axis is inverted - when at 0 we're at the top, not bottom - so we invert it back.
setScrollY(getMaxY() - (TG.getY() + TG.getWidth() / 2 - worldScreen.stage.getHeight() / 2));
updateVisualScroll();
}
}

View file

@ -0,0 +1,142 @@
package com.unciv.ui.worldscreen
import com.badlogic.gdx.math.Vector2
import com.badlogic.gdx.scenes.scene2d.Group
import com.badlogic.gdx.scenes.scene2d.InputEvent
import com.badlogic.gdx.scenes.scene2d.ui.ScrollPane
import com.badlogic.gdx.scenes.scene2d.utils.ActorGestureListener
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.logic.map.TileInfo
import com.unciv.logic.map.TileMap
import com.unciv.models.linq.Linq
import com.unciv.ui.cityscreen.addClickListener
import com.unciv.ui.tilegroups.WorldTileGroup
import com.unciv.ui.utils.HexMath
import java.util.*
class TileMapHolder(internal val worldScreen: WorldScreen, internal val tileMap: TileMap, internal val civInfo: CivilizationInfo) : ScrollPane(null) {
internal var selectedTile: TileInfo? = null
internal var unitTile: TileInfo? = null
internal fun addTiles() {
val allTiles = Group()
var topX = 0f
var topY = 0f
var bottomX = 0f
var bottomY = 0f
for (tileInfo in tileMap.values) {
val group = WorldTileGroup(tileInfo)
group.addClickListener {
val tutorial = Linq<String>()
tutorial.add("Clicking on a tile selects that tile," +
"\r\n and displays information on that tile on the bottom-right," +
"\r\n as well as unit actions, if the tile contains a unit")
worldScreen.displayTutorials("TileClicked", tutorial)
selectedTile = tileInfo
if (unitTile != null && group.tileInfo.unit == null) {
val distanceToTiles = tileMap.getDistanceToTilesWithinTurn(unitTile!!.position, unitTile!!.unit!!.currentMovement, civInfo.tech.isResearched("Machinery"))
if (distanceToTiles.containsKey(selectedTile)) {
unitTile!!.moveUnitToTile(group.tileInfo, distanceToTiles[selectedTile]!!)
} else {
unitTile!!.unit!!.action = "moveTo " + selectedTile!!.position.x.toInt() + "," + selectedTile!!.position.y.toInt()
unitTile!!.unit!!.doPreTurnAction(unitTile!!)
}
unitTile = null
selectedTile = group.tileInfo
}
worldScreen.update()
}
val positionalVector = HexMath.Hex2WorldCoords(tileInfo.position)
val groupSize = 50
group.setPosition(worldScreen.stage.width / 2 + positionalVector.x * 0.8f * groupSize.toFloat(),
worldScreen.stage.height / 2 + positionalVector.y * 0.8f * groupSize.toFloat())
worldScreen.tileGroups[tileInfo.position.toString()] = group
allTiles.addActor(group)
topX = Math.max(topX, group.x + groupSize)
topY = Math.max(topY, group.y + groupSize)
bottomX = Math.min(bottomX, group.x)
bottomY = Math.min(bottomY, group.y)
}
for (group in worldScreen.tileGroups.linqValues()) {
group.moveBy(-bottomX + 50, -bottomY + 50)
}
// there are tiles "below the zero",
// so we zero out the starting position of the whole board so they will be displayed as well
allTiles.setSize(100 + topX - bottomX, 100 + topY - bottomY)
widget = allTiles
setFillParent(true)
setOrigin(worldScreen.stage.width / 2, worldScreen.stage.height / 2)
setSize(worldScreen.stage.width, worldScreen.stage.height)
addListener(object : ActorGestureListener() {
var lastScale = 1f
internal var lastInitialDistance = 0f
override fun zoom(event: InputEvent?, initialDistance: Float, distance: Float) {
if (lastInitialDistance != initialDistance) {
lastInitialDistance = initialDistance
lastScale = scaleX
}
val scale = Math.sqrt((distance / initialDistance).toDouble()).toFloat() * lastScale
if (scale < 1) return
setScale(scale)
}
})
}
internal fun updateTiles() {
for (WG in worldScreen.tileGroups.linqValues()) WG.update(worldScreen)
if (unitTile != null)
return // While we're in "unit move" mode, no tiles but the tiles the unit can move to will be "visible"
// YES A TRIPLE FOR, GOT PROBLEMS WITH THAT?
// Seriously though, there is probably a more efficient way of doing this, probably?
// The original implementation caused serious lag on android, so efficiency is key, here
for (WG in worldScreen.tileGroups.linqValues()) WG.setIsViewable(false)
val veiwableVectorStrings = HashSet<String>()
// tiles adjacent to city tiles
for (tileInfo in tileMap.values)
if (civInfo.civName == tileInfo.owner)
for (adjacentLocation in HexMath.GetAdjacentVectors(tileInfo.position))
veiwableVectorStrings.add(adjacentLocation.toString())
// Tiles within 2 tiles of units
for (tile in tileMap.values
.where { arg0 -> arg0.unit != null })
for (tileInfo in tileMap.getViewableTiles(tile.position, 2))
veiwableVectorStrings.add(tileInfo.position.toString())
for (string in veiwableVectorStrings)
if (worldScreen.tileGroups.containsKey(string))
worldScreen.tileGroups[string]!!.setIsViewable(true)
}
fun setCenterPosition(vector: Vector2) {
val TG = worldScreen.tileGroups.linqValues().first { arg0 -> arg0.tileInfo.position == vector }
layout() // Fit the scroll pane to the contents - otherwise, setScroll won't work!
// We want to center on the middle of TG (TG.getX()+TG.getWidth()/2)
// and so the scroll position (== where the screen starts) needs to be half a screen away
scrollX = TG!!.x + TG.width / 2 - worldScreen.stage.width / 2
// Here it's the same, only the Y axis is inverted - when at 0 we're at the top, not bottom - so we invert it back.
scrollY = maxY - (TG.y + TG.width / 2 - worldScreen.stage.height / 2)
updateVisualScroll()
}
}

View file

@ -1,156 +0,0 @@
package com.unciv.ui.worldscreen;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.unciv.logic.civilization.CivilizationInfo;
import com.unciv.models.linq.Linq;
import com.unciv.models.linq.LinqHashMap;
import com.unciv.ui.GameInfo;
import com.unciv.ui.pickerscreens.PolicyPickerScreen;
import com.unciv.ui.pickerscreens.TechPickerScreen;
import com.unciv.ui.tilegroups.WorldTileGroup;
import com.unciv.ui.utils.CameraStageBaseScreen;
import com.unciv.ui.utils.GameSaver;
public class WorldScreen extends CameraStageBaseScreen {
final CivilizationInfo civInfo;
final public TileMapHolder tileMapHolder;
float buttonScale = game.settings.buttonScale;
final TileInfoTable tileInfoTable;
final CivStatsTable civTable = new CivStatsTable();
final TextButton techButton = new TextButton("", skin);
final public LinqHashMap<String, WorldTileGroup> tileGroups = new LinqHashMap<String, WorldTileGroup>();
final WorldScreenOptionsTable optionsTable;
final NotificationsScroll notificationsScroll;
final IdleUnitButton idleUnitButton = new IdleUnitButton(this);
public WorldScreen() {
GameInfo gameInfo = game.gameInfo;
this.civInfo = gameInfo.getPlayerCivilization();
tileMapHolder = new TileMapHolder(this, gameInfo.tileMap, civInfo);
tileInfoTable = new TileInfoTable(this, civInfo);
notificationsScroll = new NotificationsScroll(gameInfo.notifications, this);
optionsTable = new WorldScreenOptionsTable(this, civInfo);
new Label("", skin).getStyle().font.getData().setScale(game.settings.labelScale);
tileMapHolder.addTiles();
stage.addActor(tileMapHolder);
stage.addActor(tileInfoTable);
stage.addActor(civTable);
stage.addActor(techButton);
stage.addActor(notificationsScroll);
stage.addActor(idleUnitButton);
update();
tileMapHolder.setCenterPosition(Vector2.Zero);
createNextTurnButton(); // needs civ table to be positioned
stage.addActor(optionsTable);
Linq<String> beginningTutorial = new Linq<String>();
beginningTutorial.add("Hello, and welcome to Unciv!" +
"\r\nCivilization games can be complex, so we'll" +
"\r\n be guiding you along your first journey." +
"\r\nBefore we begin, let's review some basic game concepts.");
beginningTutorial.add("This is the world map, which is made up of multiple tiles." +
"\r\nEach tile can contain units, as well as resources" +
"\r\n and improvements, which we'll get to later");
beginningTutorial.add("You start out with two units -" +
"\r\n a Settler - who can found a city," +
"\r\n and a scout, for exploring the area." +
"\r\n Click on a tile to assign orders the unit!");
displayTutorials("NewGame",beginningTutorial);
}
public void update() {
if(game.gameInfo.tutorial.contains("CityEntered")){
Linq<String> tutorial = new Linq<String>();
tutorial.add("Once you've done everything you can, " +
"\r\nclick the next turn button on the top right to continue.");
tutorial.add("Each turn, science, culture and gold are added" +
"\r\n to your civilization, your cities' construction" +
"\r\n continues, and they may grow in population or area.");
displayTutorials("NextTurn",tutorial);
}
updateTechButton();
if(tileMapHolder.selectedTile!=null) tileInfoTable.updateTileTable(tileMapHolder.selectedTile);
tileMapHolder.updateTiles();
civTable.update(this);
notificationsScroll.update();
idleUnitButton.update();
if (civInfo.tech.freeTechs != 0) {
game.setScreen(new TechPickerScreen(true, civInfo));
}
else if(civInfo.policies.shouldOpenPolicyPicker){
game.setScreen(new PolicyPickerScreen(civInfo));
civInfo.policies.shouldOpenPolicyPicker=false;
}
}
private void updateTechButton() {
techButton.setVisible(civInfo.cities.size() != 0);
techButton.clearListeners();
techButton.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
game.setScreen(new TechPickerScreen(civInfo));
}
});
if (civInfo.tech.currentTechnology() == null) techButton.setText("Choose a tech!");
else techButton.setText(civInfo.tech.currentTechnology() + "\r\n"
+ civInfo.turnsToTech(civInfo.tech.currentTechnology()) + " turns");
techButton.setSize(techButton.getPrefWidth(), techButton.getPrefHeight());
techButton.setPosition(10, civTable.getY() - techButton.getHeight() - 5);
}
private void createNextTurnButton() {
TextButton nextTurnButton = new TextButton("Next turn", skin);
nextTurnButton.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
if (civInfo.tech.currentTechnology() == null
&& civInfo.cities.size() != 0) {
game.setScreen(new TechPickerScreen(civInfo));
return;
}
game.gameInfo.nextTurn();
tileMapHolder.unitTile = null;
GameSaver.SaveGame(game, "Autosave");
update();
Linq<String> tutorial = new Linq<String>();
tutorial.add("In your first couple of turns," +
"\r\n you will have very little options," +
"\r\n but as your civilization grows, so do the " +
"\r\n number of things requiring your attention");
displayTutorials("NextTurn",tutorial);
}
});
nextTurnButton.setPosition(stage.getWidth() - nextTurnButton.getWidth() - 10,
civTable.getY() - nextTurnButton.getHeight() - 10);
stage.addActor(nextTurnButton);
}
@Override
public void resize(int width, int height) {
if(stage.getViewport().getScreenWidth()!=width || stage.getViewport().getScreenHeight()!=height) {
super.resize(width, height);
game.worldScreen = new WorldScreen(); // start over.
game.setWorldScreen();
}
}
}

View file

@ -0,0 +1,145 @@
package com.unciv.ui.worldscreen
import com.badlogic.gdx.math.Vector2
import com.badlogic.gdx.scenes.scene2d.ui.Label
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.models.linq.Linq
import com.unciv.models.linq.LinqHashMap
import com.unciv.ui.cityscreen.addClickListener
import com.unciv.ui.pickerscreens.PolicyPickerScreen
import com.unciv.ui.pickerscreens.TechPickerScreen
import com.unciv.ui.tilegroups.WorldTileGroup
import com.unciv.ui.utils.CameraStageBaseScreen
import com.unciv.ui.utils.GameSaver
class WorldScreen : CameraStageBaseScreen() {
internal val civInfo: CivilizationInfo
val tileMapHolder: TileMapHolder
internal var buttonScale = game.settings.buttonScale
private val tileInfoTable: TileInfoTable
private val civTable = CivStatsTable()
private val techButton = TextButton("", CameraStageBaseScreen.skin)
val tileGroups = LinqHashMap<String, WorldTileGroup>()
internal val optionsTable: WorldScreenOptionsTable
private val notificationsScroll: NotificationsScroll
internal val idleUnitButton = IdleUnitButton(this)
init {
val gameInfo = game.gameInfo
this.civInfo = gameInfo.getPlayerCivilization()
tileMapHolder = TileMapHolder(this, gameInfo.tileMap, civInfo)
tileInfoTable = TileInfoTable(this, civInfo)
notificationsScroll = NotificationsScroll(gameInfo.notifications, this)
optionsTable = WorldScreenOptionsTable(this, civInfo)
Label("", CameraStageBaseScreen.skin).style.font.data.setScale(game.settings.labelScale)
tileMapHolder.addTiles()
stage.addActor(tileMapHolder)
stage.addActor(tileInfoTable)
stage.addActor(civTable)
stage.addActor(techButton)
stage.addActor(notificationsScroll)
stage.addActor(idleUnitButton)
update()
tileMapHolder.setCenterPosition(Vector2.Zero)
createNextTurnButton() // needs civ table to be positioned
stage.addActor(optionsTable)
val beginningTutorial = Linq<String>()
beginningTutorial.add("Hello, and welcome to Unciv!" +
"\r\nCivilization games can be complex, so we'll" +
"\r\n be guiding you along your first journey." +
"\r\nBefore we begin, let's review some basic game concepts.")
beginningTutorial.add("This is the world map, which is made up of multiple tiles." +
"\r\nEach tile can contain units, as well as resources" +
"\r\n and improvements, which we'll get to later")
beginningTutorial.add("You start out with two units -" +
"\r\n a Settler - who can found a city," +
"\r\n and a scout, for exploring the area." +
"\r\n Click on a tile to assign orders the unit!")
displayTutorials("NewGame", beginningTutorial)
}
fun update() {
if (game.gameInfo.tutorial.contains("CityEntered")) {
val tutorial = Linq<String>()
tutorial.add("Once you've done everything you can, " + "\r\nclick the next turn button on the top right to continue.")
tutorial.add("Each turn, science, culture and gold are added" +
"\r\n to your civilization, your cities' construction" +
"\r\n continues, and they may grow in population or area.")
displayTutorials("NextTurn", tutorial)
}
updateTechButton()
if (tileMapHolder.selectedTile != null) tileInfoTable.updateTileTable(tileMapHolder.selectedTile!!)
tileMapHolder.updateTiles()
civTable.update(this)
notificationsScroll.update()
idleUnitButton.update()
if (civInfo.tech.freeTechs != 0) {
game.screen = TechPickerScreen(true, civInfo)
} else if (civInfo.policies.shouldOpenPolicyPicker) {
game.screen = PolicyPickerScreen(civInfo)
civInfo.policies.shouldOpenPolicyPicker = false
}
}
private fun updateTechButton() {
techButton.isVisible = civInfo.cities.size != 0
techButton.clearListeners()
techButton.addClickListener {
game.screen = TechPickerScreen(civInfo)
}
if (civInfo.tech.currentTechnology() == null)
techButton.setText("Choose a tech!")
else
techButton.setText(civInfo.tech.currentTechnology() + "\r\n"
+ civInfo.turnsToTech(civInfo.tech.currentTechnology()!!) + " turns")
techButton.setSize(techButton.prefWidth, techButton.prefHeight)
techButton.setPosition(10f, civTable.y - techButton.height - 5f)
}
private fun createNextTurnButton() {
val nextTurnButton = TextButton("Next turn", CameraStageBaseScreen.skin)
nextTurnButton.addClickListener {
if (civInfo.tech.currentTechnology() == null && civInfo.cities.size != 0) {
game.screen = TechPickerScreen(civInfo)
return@addClickListener
}
game.gameInfo.nextTurn()
tileMapHolder.unitTile = null
GameSaver.SaveGame(game, "Autosave")
update()
val tutorial = Linq<String>()
tutorial.add("In your first couple of turns," +
"\r\n you will have very little options," +
"\r\n but as your civilization grows, so do the " +
"\r\n number of things requiring your attention")
displayTutorials("NextTurn", tutorial)
}
nextTurnButton.setPosition(stage.width - nextTurnButton.width - 10f,
civTable.y - nextTurnButton.height - 10f)
stage.addActor(nextTurnButton)
}
override fun resize(width: Int, height: Int) {
if (stage.viewport.screenWidth != width || stage.viewport.screenHeight != height) {
super.resize(width, height)
game.worldScreen = WorldScreen() // start over.
game.setWorldScreen()
}
}
}

View file

@ -1,82 +0,0 @@
package com.unciv.ui.worldscreen;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;
import com.badlogic.gdx.scenes.scene2d.utils.Drawable;
import com.unciv.logic.civilization.CivilizationInfo;
import com.unciv.ui.CivilopediaScreen;
import com.unciv.ui.ScienceVictoryScreen;
import com.unciv.ui.pickerscreens.PolicyPickerScreen;
import com.unciv.ui.utils.CameraStageBaseScreen;
import com.unciv.ui.utils.ImageGetter;
public class WorldScreenOptionsTable extends Table {
private final CivilizationInfo civInfo;
WorldScreenOptionsTable(final WorldScreen worldScreen, CivilizationInfo civInfo) {
this.civInfo = civInfo;
Drawable tileTableBackground = ImageGetter.getDrawable("skin/tileTableBackground.png")
.tint(new Color(0x004085bf));
setBackground(tileTableBackground);
setVisible(false);
TextButton OpenCivilopediaButton = new TextButton("Civilopedia", CameraStageBaseScreen.skin);
OpenCivilopediaButton.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
worldScreen.game.setScreen(new CivilopediaScreen());
setVisible(false);
}
});
add(OpenCivilopediaButton).pad(10);
row();
TextButton StartNewGameButton = new TextButton("Start new game", CameraStageBaseScreen.skin);
StartNewGameButton.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
worldScreen.game.startNewGame();
}
});
add(StartNewGameButton).pad(10);
row();
TextButton OpenScienceVictoryScreen = new TextButton("Science victory status", CameraStageBaseScreen.skin);
OpenScienceVictoryScreen.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
worldScreen.game.setScreen(new ScienceVictoryScreen(WorldScreenOptionsTable.this.civInfo));
}
});
add(OpenScienceVictoryScreen).pad(10);
row();
TextButton OpenPolicyPickerScreen = new TextButton("Social Policies", CameraStageBaseScreen.skin);
OpenPolicyPickerScreen.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
worldScreen.game.setScreen(new PolicyPickerScreen(WorldScreenOptionsTable.this.civInfo));
}
});
add(OpenPolicyPickerScreen).pad(10);
row();
TextButton closeButton = new TextButton("Close", CameraStageBaseScreen.skin);
closeButton.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
setVisible(false);
}
});
add(closeButton).pad(10);
pack(); // Needed to show the background.
setPosition(worldScreen.stage.getWidth() / 2 - getWidth() / 2,
worldScreen.stage.getHeight() / 2 - getHeight() / 2);
}
}

View file

@ -0,0 +1,58 @@
package com.unciv.ui.worldscreen
import com.badlogic.gdx.graphics.Color
import com.badlogic.gdx.scenes.scene2d.ui.Table
import com.badlogic.gdx.scenes.scene2d.ui.TextButton
import com.unciv.logic.civilization.CivilizationInfo
import com.unciv.ui.CivilopediaScreen
import com.unciv.ui.ScienceVictoryScreen
import com.unciv.ui.cityscreen.addClickListener
import com.unciv.ui.pickerscreens.PolicyPickerScreen
import com.unciv.ui.utils.CameraStageBaseScreen
import com.unciv.ui.utils.ImageGetter
class WorldScreenOptionsTable internal constructor(worldScreen: WorldScreen, private val civInfo: CivilizationInfo) : Table() {
init {
val tileTableBackground = ImageGetter.getDrawable("skin/tileTableBackground.png")
.tint(Color(0x004085bf))
background = tileTableBackground
isVisible = false
val OpenCivilopediaButton = TextButton("Civilopedia", CameraStageBaseScreen.skin)
OpenCivilopediaButton.addClickListener {
worldScreen.game.screen = CivilopediaScreen()
isVisible = false
}
add(OpenCivilopediaButton).pad(10f)
row()
val StartNewGameButton = TextButton("Start new game", CameraStageBaseScreen.skin)
StartNewGameButton.addClickListener { worldScreen.game.startNewGame() }
add(StartNewGameButton).pad(10f)
row()
val OpenScienceVictoryScreen = TextButton("Science victory status", CameraStageBaseScreen.skin)
OpenScienceVictoryScreen.addClickListener {
worldScreen.game.screen = ScienceVictoryScreen(this@WorldScreenOptionsTable.civInfo)
}
add(OpenScienceVictoryScreen).pad(10f)
row()
val OpenPolicyPickerScreen = TextButton("Social Policies", CameraStageBaseScreen.skin)
OpenPolicyPickerScreen.addClickListener {
worldScreen.game.screen = PolicyPickerScreen(this@WorldScreenOptionsTable.civInfo)
}
add(OpenPolicyPickerScreen).pad(10f)
row()
val closeButton = TextButton("Close", CameraStageBaseScreen.skin)
closeButton.addClickListener { isVisible = false }
add(closeButton).pad(10f)
pack() // Needed to show the background.
setPosition(worldScreen.stage.width / 2 - width / 2,
worldScreen.stage.height / 2 - height / 2)
}
}