All coe converted to Kotlin!
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
59
core/src/com/unciv/logic/GameInfo.kt
Normal 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()
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
153
core/src/com/unciv/logic/city/CityConstructions.kt
Normal 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
|
|
@ -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;
|
||||
}
|
||||
}
|
46
core/src/com/unciv/logic/city/CityExpansionManager.kt
Normal 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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
138
core/src/com/unciv/logic/city/CityInfo.kt
Normal 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
|
||||
}
|
||||
}
|
|
@ -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; }
|
||||
|
||||
}
|
257
core/src/com/unciv/logic/city/CityStats.kt
Normal 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
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
72
core/src/com/unciv/logic/city/PopulationManager.kt
Normal 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
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
147
core/src/com/unciv/logic/civilization/CivilizationInfo.kt
Normal 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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
36
core/src/com/unciv/logic/civilization/GoldenAgeManager.kt
Normal 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++
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
29
core/src/com/unciv/logic/civilization/GreatPersonManager.kt
Normal 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)
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
71
core/src/com/unciv/logic/civilization/PolicyManager.kt
Normal 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
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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+")";
|
||||
}
|
||||
|
||||
}
|
74
core/src/com/unciv/logic/civilization/TechManager.kt
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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)
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) }
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
)
|
||||
}
|
||||
|
||||
}
|
|
@ -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 {
|
||||
|
|
77
core/src/com/unciv/models/stats/Stats.kt
Normal 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]!!
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
96
core/src/com/unciv/ui/CivilopediaScreen.kt
Normal 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
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
11
core/src/com/unciv/ui/GameSettings.kt
Normal 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
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
54
core/src/com/unciv/ui/ScienceVictoryScreen.kt
Normal 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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
115
core/src/com/unciv/ui/UnCivGame.kt
Normal 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
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
30
core/src/com/unciv/ui/VictoryScreen.kt
Normal 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)
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
113
core/src/com/unciv/ui/cityscreen/BuildingsTable.kt
Normal 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()
|
||||
}
|
||||
} )
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
301
core/src/com/unciv/ui/cityscreen/CityScreen.kt
Normal 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)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
45
core/src/com/unciv/ui/cityscreen/CityTileGroup.kt
Normal 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)
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
45
core/src/com/unciv/ui/cityscreen/YieldGroup.kt
Normal 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
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
66
core/src/com/unciv/ui/pickerscreens/PickerScreen.kt
Normal 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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
126
core/src/com/unciv/ui/pickerscreens/PolicyPickerScreen.kt
Normal 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
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
166
core/src/com/unciv/ui/pickerscreens/TechPickerScreen.kt
Normal 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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
142
core/src/com/unciv/ui/tilegroups/TileGroup.kt
Normal 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
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
}
|
77
core/src/com/unciv/ui/tilegroups/WorldTileGroup.kt
Normal 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
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
99
core/src/com/unciv/ui/utils/CameraStageBaseScreen.kt
Normal 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()
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
24
core/src/com/unciv/ui/utils/GameSaver.kt
Normal 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()
|
||||
}
|
||||
}
|
|
@ -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++;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
86
core/src/com/unciv/ui/utils/HexMath.kt
Normal 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++
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
|
||||
}
|
48
core/src/com/unciv/ui/utils/ImageGetter.kt
Normal 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")
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
67
core/src/com/unciv/ui/worldscreen/CivStatsTable.kt
Normal 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
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
39
core/src/com/unciv/ui/worldscreen/IdleUnitButton.kt
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
47
core/src/com/unciv/ui/worldscreen/NotificationsScroll.kt
Normal 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))
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
216
core/src/com/unciv/ui/worldscreen/TileInfoTable.kt
Normal 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)
|
||||
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
}
|
142
core/src/com/unciv/ui/worldscreen/TileMapHolder.kt
Normal 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()
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
145
core/src/com/unciv/ui/worldscreen/WorldScreen.kt
Normal 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
58
core/src/com/unciv/ui/worldscreen/WorldScreenOptionsTable.kt
Normal 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)
|
||||
}
|
||||
}
|