Initial commit

This commit is contained in:
Yair Morgenstern
2017-11-22 00:09:35 +02:00
parent 45b4131c0b
commit 0319602092
234 changed files with 12155 additions and 0 deletions

5
core/src/CivCity.gwt.xml Normal file
View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit trunk//EN" "http://google-web-toolkit.googlecode.com/svn/trunk/distro-source/core/src/gwt-module.dtd">
<module>
<source path="com/unciv/game" />
</module>

View File

@ -0,0 +1,152 @@
package com.unciv.civinfo;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Predicate;
import com.unciv.game.UnCivGame;
import com.unciv.models.gamebasics.Building;
import com.unciv.models.gamebasics.GameBasics;
import com.unciv.models.stats.FullStats;
import java.util.ArrayList;
import java.util.HashMap;
public class CityBuildings
{
static final String Worker="Worker";
static final String Settler="Settler";
public Vector2 cityLocation;
public CityBuildings(){} // for json parsing, we need to have a default constructor
public CityBuildings(CityInfo cityInfo)
{
cityLocation = cityInfo.cityLocation;
}
public ArrayList<String> BuiltBuildings = new ArrayList<String>();
public HashMap<String, Integer> InProgressBuildings = new HashMap<String, Integer>();
public String CurrentBuilding = Worker; // default starting building!
public CityInfo GetCity(){return UnCivGame.Current.civInfo.tileMap.get(cityLocation).GetCity(); }
public boolean IsBuilt(String buildingName) { return BuiltBuildings.contains(buildingName); }
public boolean IsBuilding(String buildingName) { return CurrentBuilding.equals(buildingName); }
Building GetGameBuilding(String buildingName) { return GameBasics.Buildings.get(buildingName); }
public void NextTurn(int ProductionProduced)
{
if (CurrentBuilding == null) return;
if (!InProgressBuildings.containsKey(CurrentBuilding)) InProgressBuildings.put(CurrentBuilding, 0);
InProgressBuildings.put(CurrentBuilding, InProgressBuildings.get(CurrentBuilding) + ProductionProduced);
if (InProgressBuildings.get(CurrentBuilding) >= GetGameBuilding(CurrentBuilding).Cost)
{
if (CurrentBuilding.equals(Worker) || CurrentBuilding.equals(Settler))
UnCivGame.Current.civInfo.tileMap.get(cityLocation).Unit = new Unit(CurrentBuilding,2);
else
{
BuiltBuildings.add(CurrentBuilding);
Building gameBuilding = GetGameBuilding(CurrentBuilding);
if (gameBuilding.ProvidesFreeBuilding != null && !BuiltBuildings.contains(gameBuilding.ProvidesFreeBuilding))
BuiltBuildings.add(gameBuilding.ProvidesFreeBuilding);
if (gameBuilding.FreeTechs != 0) UnCivGame.Current.civInfo.Tech.FreeTechs += gameBuilding.FreeTechs;
}
InProgressBuildings.remove(CurrentBuilding);
// Choose next building to build
CurrentBuilding = GetBuildableBuildings().first(new Predicate<String>() {
@Override
public boolean evaluate(String arg0) {
if(arg0.equals(Settler) || arg0.equals(Worker)) return false;
return !BuiltBuildings.contains(arg0);
}
});
if (CurrentBuilding == null) CurrentBuilding = Worker;
}
}
public boolean CanBuild(final Building building)
{
CivilizationInfo civInfo = UnCivGame.Current.civInfo;
if(IsBuilt(building.Name)) return false;
// if (building.Name.equals("Worker") || building.Name.equals("Settler")) return false;
if(building.ResourceRequired) {
boolean containsResourceWithImprovement = GetCity().GetCityTiles()
.any(new Predicate<TileInfo>() {
@Override
public boolean evaluate(TileInfo tile) {
return tile.Resource != null
&& building.Name.equals(tile.GetTileResource().Building)
&& tile.GetTileResource().Improvement.equals(tile.Improvement);
}
});
if(!containsResourceWithImprovement) return false;
}
if (building.RequiredTech != null && !civInfo.Tech.IsResearched(building.RequiredTech)) return false;
if (building.IsWonder && civInfo.Cities
.any(new Predicate<CityInfo>() {
@Override
public boolean evaluate(CityInfo arg0) {
CityBuildings CB = arg0.cityBuildings;
return CB.IsBuilt(building.Name) || CB.IsBuilt(building.Name);
}
}) ) return false;
if (building.RequiredBuilding != null && !IsBuilt(building.RequiredBuilding)) return false;
if (building.RequiredBuildingInAllCities != null ||
civInfo.Cities.any(new Predicate<CityInfo>() {
@Override
public boolean evaluate(CityInfo arg0) {
return arg0.cityBuildings.IsBuilt(building.RequiredBuildingInAllCities);
}
}) ) return false;
return true;
}
public com.unciv.models.LinqCollection<String> GetBuildableBuildings()
{
return new com.unciv.models.LinqCollection<Building>(GameBasics.Buildings.values())
.where(new Predicate<Building>() {
@Override
public boolean evaluate(Building arg0) { return CanBuild(arg0); }
})
.select(new com.unciv.models.LinqCollection.Func<Building, String>() {
@Override
public String GetBy(Building arg0) {
return arg0.Name;
}
});
}
public FullStats GetStats()
{
FullStats stats = new FullStats();
for (String building : BuiltBuildings)
{
Building gameBuilding = GetGameBuilding(building);
stats.add(gameBuilding);
//if (gameBuilding.GetFlatBonusStats != null) stats.add(gameBuilding.GetFlatBonusStats(cityInfo));
stats.Gold -= gameBuilding.Maintainance;
}
return stats;
}
public int TurnsToBuilding(String buildingName)
{
int workDone = 0;
if (InProgressBuildings.containsKey(buildingName)) workDone = InProgressBuildings.get(buildingName);
float workLeft = GetGameBuilding(buildingName).Cost - workDone; // needs to be float so that we get the cieling properly ;)
FullStats cityStats = GetCity().getCityStats();
int production = cityStats.Production;
if (buildingName.equals(Settler)) production += cityStats.Food;
return (int) Math.ceil(workLeft / production);
}
}

View File

@ -0,0 +1,132 @@
package com.unciv.civinfo;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Predicate;
import com.unciv.game.HexMath;
import com.unciv.game.UnCivGame;
import com.unciv.models.LinqCollection;
import com.unciv.models.stats.FullStats;
import java.util.ArrayList;
public class CityInfo {
public final Vector2 cityLocation;
public String Name;
public CityBuildings cityBuildings;
public CityPopulation cityPopulation;
public LinqCollection<Vector2> CityTileLocations = new LinqCollection<Vector2>();
public LinqCollection<TileInfo> GetCityTiles(){
return CityTileLocations.select(new com.unciv.models.LinqCollection.Func<Vector2, TileInfo>() {
@Override
public TileInfo GetBy(Vector2 arg0) {
return UnCivGame.Current.civInfo.tileMap.get(arg0);
}
});
}
String[] CityNames = new String[]{"Assur", "Ninveh", "Nimrud", "Kar-Tukuli-Ninurta", "Dur-Sharrukin"};
public CityInfo(){
cityLocation = Vector2.Zero;
} // for json parsing, we need to have a default constructor
public CityInfo(CivilizationInfo civInfo, Vector2 cityLocation) {
Name = CityNames[civInfo.Cities.size()];
this.cityLocation = cityLocation;
cityBuildings = new CityBuildings(this);
cityPopulation = new CityPopulation();
for(Vector2 vector : HexMath.GetVectorsInDistance(cityLocation,2))
{
if(civInfo.tileMap.get(vector).GetCity() == null)
CityTileLocations.add(vector);
}
AutoAssignWorker();
civInfo.Cities.add(this);
}
public ArrayList<String> GetLuxuryResources() {
ArrayList<String> LuxuryResources = new ArrayList<String>();
for (TileInfo tileInfo : GetCityTiles()) {
com.unciv.models.gamebasics.TileResource resource = tileInfo.GetTileResource();
if (resource != null && resource.ResourceType.equals("Luxury") && resource.Improvement.equals(tileInfo.Improvement))
LuxuryResources.add(tileInfo.Resource);
}
return LuxuryResources;
}
public int GetWorkingPopulation() {
return GetCityTiles().count(new Predicate<TileInfo>() {
@Override
public boolean evaluate(TileInfo arg0) {
return arg0.IsWorked;
}
});
}
public int GetFreePopulation() {
return cityPopulation.Population - GetWorkingPopulation();
}
public boolean HasNonWorkingPopulation() {
return GetFreePopulation() > 0;
}
public FullStats getCityStats() {
FullStats stats = new FullStats() {{
Happiness = -3 - cityPopulation.Population; // -3 happiness per city and -3 per population
}};
stats.Science += cityPopulation.Population;
// Working ppl
for (TileInfo cell : GetCityTiles()) {
if (cell.IsWorked || cell.IsCityCenter()) stats.add(cell.GetTileStats());
}
//idle ppl
stats.Production += GetFreePopulation();
stats.Food -= cityPopulation.Population * 2;
stats.add(cityBuildings.GetStats());
return stats;
}
public void NextTurn() {
FullStats stats = getCityStats();
if (cityBuildings.CurrentBuilding.equals(cityBuildings.Settler) && stats.Food > 0) {
stats.Production += stats.Food;
stats.Food = 0;
}
if (cityPopulation.NextTurn(stats.Food)) AutoAssignWorker();
cityBuildings.NextTurn(stats.Production);
for (TileInfo tileInfo : GetCityTiles()) {
tileInfo.NextTurn();
}
}
public void AutoAssignWorker() {
double maxValue = 0;
TileInfo toWork = null;
for (TileInfo tileInfo : GetCityTiles()) {
if (tileInfo.IsWorked || tileInfo.IsCityCenter()) continue;
FullStats stats = tileInfo.GetTileStats();
double value = stats.Food + stats.Production * 0.5;
if (value > maxValue) {
maxValue = value;
toWork = tileInfo;
}
}
toWork.IsWorked = true;
}
}

View File

@ -0,0 +1,34 @@
package com.unciv.civinfo;
public class CityPopulation
{
public int Population = 1;
public int FoodStored = 0;
public int FoodToNextPopulation()
{
// civ v math,civilization.wikia
return 15 + 6 * (Population - 1) + (int)Math.floor(Math.pow(Population - 1, 1.8f));
}
/**
* @param FoodProduced
* @return whether a growth occured
*/
public boolean NextTurn(int FoodProduced)
{
FoodStored += FoodProduced;
if (FoodStored < 0) // starvation!
{
Population--;
FoodStored = 0;
}
if (FoodStored >= FoodToNextPopulation()) // growth!
{
FoodStored -= FoodToNextPopulation();
Population++;
return true;
}
return false;
}
}

View File

@ -0,0 +1,71 @@
package com.unciv.civinfo;
import com.badlogic.gdx.math.Vector2;
import com.unciv.game.pickerscreens.GameSaver;
import com.unciv.models.LinqCollection;
import com.unciv.models.gamebasics.GameBasics;
import com.unciv.models.stats.CivStats;
import java.util.HashSet;
/**
* Created by LENOVO on 10/18/2017.
*/
public class CivilizationInfo {
public CivStats civStats = new CivStats();
public int baseHappiness = 15;
public CivilizationTech Tech = new CivilizationTech();
public int turns = 1;
public LinqCollection<CityInfo> Cities = new LinqCollection<CityInfo>();
public TileMap tileMap = new TileMap(20);
public int CurrentCity=0; //index!
public CivilizationInfo(){
}
public CityInfo GetCurrentCity() { return Cities.get(CurrentCity); }
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 city = new CityInfo(this,location);
if(Cities.size()==1) city.cityBuildings.BuiltBuildings.add("Palace");
}
public void NextTurn()//out boolean displayTech)
{
CivStats nextTurnStats = GetStatsForNextTurn();
civStats.add(nextTurnStats);
if(Cities.size() > 0) Tech.NextTurn(nextTurnStats.Science);
for (CityInfo city : Cities.as(CityInfo.class)) city.NextTurn();
for(TileInfo tile : tileMap.values()) if(tile.Unit!=null) tile.Unit.CurrentMovement = tile.Unit.MaxMovement;
turns += 1;
}
public CivStats GetStatsForNextTurn() {
CivStats statsForTurn = new CivStats() {{
Happiness = baseHappiness;
}};
HashSet<String> LuxuryResources = new HashSet<String>();
for (CityInfo city : Cities) {
statsForTurn.add(city.getCityStats());
LuxuryResources.addAll(city.GetLuxuryResources());
}
statsForTurn.Happiness += LuxuryResources.size() * 5; // 5 happiness for each unique luxury in civ
return statsForTurn;
}
}

View File

@ -0,0 +1,55 @@
package com.unciv.civinfo;
import com.unciv.models.gamebasics.GameBasics;
import com.unciv.models.gamebasics.Technology;
import java.util.ArrayList;
import java.util.HashMap;
public class CivilizationTech{
public int FreeTechs = 0;
public ArrayList<String> TechsResearched = new ArrayList<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){
String CurrentTechnology = CurrentTechnology();
if (!TechsInProgress.containsKey(CurrentTechnology))
TechsInProgress.put(CurrentTechnology, 0);
TechsInProgress.put(CurrentTechnology, TechsInProgress.get(CurrentTechnology) + scienceForNewTurn);
if (TechsInProgress.get(CurrentTechnology) >= GetCurrentTechnology().Cost) // We finished it!
{
TechsInProgress.remove(CurrentTechnology);
TechsResearched.add(CurrentTechnology);
TechsToResearch.remove(CurrentTechnology);
}
}
}

View File

@ -0,0 +1,134 @@
package com.unciv.civinfo;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Predicate;
import com.unciv.game.UnCivGame;
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;
public class TileInfo
{
public Unit Unit;
public Vector2 Position;
public String BaseTerrain;
public String TerrainFeature;
public String Resource;
public boolean IsWorked = false;
public String Improvement;
public String ImprovementInProgress;
public int TurnsToImprovement;
public Terrain GetBaseTerrain(){return GameBasics.Terrains.get(BaseTerrain);}
public CityInfo GetCity(){return UnCivGame.Current.civInfo.Cities.first(new Predicate<CityInfo>() {
@Override
public boolean evaluate(CityInfo arg0) {
return arg0.CityTileLocations.contains(Position);
}
});}
public Terrain GetTerrainFeature(){return TerrainFeature==null ? null : GameBasics.Terrains.get(TerrainFeature);}
public Terrain GetLastTerrain() {
return TerrainFeature == null ? GetBaseTerrain() : GetTerrainFeature();
}
public TileResource GetTileResource(){return Resource==null ? null : GameBasics.TileResources.get(Resource);}
public boolean IsCityCenter(){return GetCity()!=null && Position.equals(GetCity().cityLocation);}
public TileImprovement GetTileImprovement(){return Improvement==null ? null : GameBasics.TileImprovements.get(Improvement);}
private boolean IsResearched(String techName) { return UnCivGame.Current.civInfo.Tech.IsResearched(techName); }
public FullStats GetTileStats()
{
FullStats stats = new FullStats(GetBaseTerrain());
if(TerrainFeature!=null){
Terrain terrainFeature = GetTerrainFeature();
if(terrainFeature.OverrideStats) stats = new FullStats(terrainFeature);
else stats.add(terrainFeature);
}
TileResource resource = GetTileResource();
CityInfo City = GetCity();
if (HasViewableResource())
{
stats.add(resource);
if(resource.Building!=null && City!=null && City.cityBuildings.IsBuilt(resource.Building))
{
stats.add(resource.GetBuilding().ResourceBonusStats);
}
}
TileImprovement improvement = GetTileImprovement();
if (improvement != null)
{
if (resource != null && resource.Improvement.equals(improvement.Name))
stats.add(resource.ImprovementStats);
else stats.add(improvement);
if (IsResearched(improvement.ImprovingTech)) stats.add(improvement.ImprovingTechStats);
}
if (City != null && City.cityLocation.equals(Position)) {
if (stats.Food < 2) stats.Food = 2;
if (stats.Production < 1) stats.Production = 1;
}
if (stats.Production < 0) stats.Production = 0;
return stats;
}
public boolean CanBuildImprovement(TileImprovement improvement)
{
Terrain topTerrain = TerrainFeature==null ? GetBaseTerrain() : GetTerrainFeature();
if (improvement.TechRequired != null && !IsResearched(improvement.TechRequired)) return false;
if (improvement.TerrainsCanBeBuiltOn.contains(topTerrain.Name)) return true;
if (topTerrain.Unbuildable) return false;
return Resource != null && GetTileResource().Improvement.equals(improvement.Name);
}
public void StartWorkingOnImprovement(TileImprovement improvement)
{
ImprovementInProgress = improvement.Name;
TurnsToImprovement = improvement.TurnsToBuild;
}
public void StopWorkingOnImprovement()
{
ImprovementInProgress = null;
}
public void NextTurn()
{
if (ImprovementInProgress == null || Unit==null || !Unit.Name.equals("Worker")) return;
TurnsToImprovement -= 1;
if(TurnsToImprovement == 0)
{
if (ImprovementInProgress.startsWith("Remove")) TerrainFeature = null;
else Improvement = ImprovementInProgress;
ImprovementInProgress = null;
}
}
public String toString() {
StringBuilder SB = new StringBuilder(this.BaseTerrain);
if (TerrainFeature != null) SB.append(",\r\n" + TerrainFeature);
if (HasViewableResource()) SB.append(",\r\n" + Resource);
if (Improvement != null) SB.append(",\r\n" + Improvement);
if (ImprovementInProgress != null) SB.append(",\r\n" + ImprovementInProgress+" in "+this.TurnsToImprovement+" turns");
if(Unit!=null) SB.append(",\r\n" + Unit.Name+ "("+Unit.CurrentMovement+"/"+Unit.MaxMovement+")");
return SB.toString();
}
public boolean HasViewableResource() {
return Resource != null && (GetTileResource().RevealedBy==null || IsResearched(GetTileResource().RevealedBy));
}
}

View File

@ -0,0 +1,89 @@
package com.unciv.civinfo;
import com.badlogic.gdx.math.Vector;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Predicate;
import com.unciv.game.HexMath;
import com.unciv.models.LinqCollection;
import com.unciv.models.LinqHashMap;
import com.unciv.models.gamebasics.GameBasics;
import com.unciv.models.gamebasics.Terrain;
import com.unciv.models.gamebasics.TileResource;
public class TileMap{
private LinqHashMap<String, TileInfo> tiles = new LinqHashMap<String, TileInfo>();
public TileMap(){} // for json parsing, we need to have a default constructor
public TileMap(int distance) {
for(Vector2 vector : HexMath.GetVectorsInDistance(Vector2.Zero,distance)) addRandomTile(vector);
}
private void addRandomTile(Vector2 position) {
final TileInfo tileInfo = new TileInfo();
tileInfo.Position = position;
LinqCollection<Terrain> Terrains = GameBasics.Terrains.linqValues();
final Terrain baseTerrain = Terrains.where(new Predicate<Terrain>() {
@Override
public boolean evaluate(Terrain arg0) {
return arg0.Type.equals("BaseTerrain") && !arg0.Name.equals("Lakes");
}
}).getRandom();
tileInfo.BaseTerrain = baseTerrain.Name;
if (baseTerrain.CanHaveOverlay) {
if (Math.random() > 0.7f) {
Terrain SecondaryTerrain = Terrains.where(new Predicate<Terrain>() {
@Override
public boolean evaluate(Terrain arg0) {
return arg0.Type.equals("TerrainFeature") && arg0.OccursOn.contains(baseTerrain.Name);
}
}).getRandom();
if (SecondaryTerrain != null) tileInfo.TerrainFeature = SecondaryTerrain.Name;
}
}
LinqCollection<TileResource> TileResources = GameBasics.TileResources.linqValues();
// Resources are placed according to TerrainFeature, if exists, otherwise according to BaseLayer.
TileResources = TileResources.where(new Predicate<TileResource>() {
@Override
public boolean evaluate(TileResource arg0) {
return arg0.TerrainsCanBeFoundOn.contains(tileInfo.GetLastTerrain().Name);
}
});
TileResource resource = null;
if (Math.random() < 1 / 5f) {
resource = GetRandomResource(TileResources, "Bonus");
} else if (Math.random() < 1 / 7f) {
resource = GetRandomResource(TileResources, "Strategic");
} else if (Math.random() < 1 / 10f) {
resource = GetRandomResource(TileResources, "Luxury");
}
if (resource != null) tileInfo.Resource = resource.Name;
// tileInfo.City = this;
// GetCityTiles.put(vector2, tileInfo);
tiles.put(position.toString(),tileInfo);
}
public boolean contains(Vector2 vector){ return tiles.containsKey(vector.toString());}
public TileInfo get(Vector2 vector){return tiles.get(vector.toString());}
public LinqCollection<TileInfo> values(){return tiles.linqValues();}
public TileResource GetRandomResource(LinqCollection<TileResource> resources, final String resourceType) {
return resources.where(new Predicate<TileResource>() {
@Override
public boolean evaluate(TileResource arg0) {
return arg0.ResourceType.equals(resourceType);
}
}).getRandom();
}
}

View File

@ -0,0 +1,15 @@
package com.unciv.civinfo;
public class Unit{
public String Name;
public int MaxMovement;
public int CurrentMovement;
public Unit(){} // for json parsing, we need to have a default constructor
public Unit(String name, int maxMovement) {
Name = name;
MaxMovement = maxMovement;
CurrentMovement = maxMovement;
}
}

View File

@ -0,0 +1,72 @@
package com.unciv.game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.utils.viewport.FitViewport;
import java.util.HashMap;
public class CameraStageBaseScreen implements Screen {
protected UnCivGame game;
protected Stage stage;
protected Skin skin = new Skin(Gdx.files.internal("skin/flat-earth-ui.json"));
static Batch batch = new SpriteBatch();
public CameraStageBaseScreen(UnCivGame game) {
this.game = game;
stage = new Stage(new FitViewport(1000,600),batch);
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() {
}
}

View File

@ -0,0 +1,299 @@
package com.unciv.game;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Pixmap.Blending;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
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.Image;
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.scenes.scene2d.utils.TextureRegionDrawable;
import com.badlogic.gdx.utils.Align;
import com.unciv.civinfo.CityInfo;
import com.unciv.civinfo.TileInfo;
import com.unciv.game.pickerscreens.BuildingPickerScreen;
import com.unciv.models.stats.FullStats;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
public class CityScreen extends CameraStageBaseScreen {
TileInfo selectedTile = null;
float buttonScale = game.settings.buttonScale;
Table TileTable = new Table();
Table CityStatsTable = new Table();
Table CityPickerTable = new Table();
TextButton TechButton = new TextButton("Exit city",skin);
public ArrayList<TileGroup> tileGroups = new ArrayList<TileGroup>();
public CityScreen(final UnCivGame game) {
super(game);
new Label("",skin).getStyle().font.getData().setScale(game.settings.labelScale);
addTiles();
stage.addActor(TileTable);
Drawable tileTableBackground = new TextureRegionDrawable(new TextureRegion(new Texture("skin/tileTableBackground.png")))
.tint(new Color(0x0040804f));
tileTableBackground.setMinHeight(0);
tileTableBackground.setMinWidth(0);
TileTable.setBackground(tileTableBackground);
CityStatsTable.setBackground(tileTableBackground);
updateCityTable();
stage.addActor(CityStatsTable);
updateGoToWorldButton();
stage.addActor(TechButton);
updateCityPickerTable();
stage.addActor(CityPickerTable);
}
private void updateCityPickerTable() {
CityPickerTable.clear();
CityPickerTable.row().pad(20);
if(game.civInfo.Cities.size()>1) {
TextButton prevCityButton = new TextButton("<", skin);
prevCityButton.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
com.unciv.civinfo.CivilizationInfo ci = game.civInfo;
if (ci.CurrentCity == 0) ci.CurrentCity = ci.Cities.size()-1;
else ci.CurrentCity--;
game.setScreen(new CityScreen(game));
dispose();
}
});
CityPickerTable.add(prevCityButton);
}
Label currentCityLabel = new Label(game.civInfo.GetCurrentCity().Name, skin);
currentCityLabel.setFontScale(2);
CityPickerTable.add(currentCityLabel);
if(game.civInfo.Cities.size()>1) {
TextButton nextCityButton = new TextButton(">", skin);
nextCityButton.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
com.unciv.civinfo.CivilizationInfo ci = game.civInfo;
if (ci.CurrentCity == ci.Cities.size()-1) ci.CurrentCity = 0;
else ci.CurrentCity++;
game.setScreen(new CityScreen(game));
dispose();
}
});
CityPickerTable.add(nextCityButton);
}
CityPickerTable.pack();
CityPickerTable.setPosition(stage.getWidth()/2-CityPickerTable.getWidth()/2,0);
stage.addActor(CityPickerTable);
}
private void updateGoToWorldButton() {
TechButton.clearListeners();
TechButton.addListener(new ClickListener(){
@Override
public void clicked(InputEvent event, float x, float y) {
game.setWorldScreen();
game.worldScreen.setCenterPosition(game.civInfo.GetCurrentCity().cityLocation);
dispose();
}
});
TechButton.setSize(TechButton.getPrefWidth(), TechButton.getPrefHeight());
TechButton.setPosition(10, stage.getHeight() - TechButton.getHeight()-5);
}
private void addTiles() {
final CityInfo cityInfo = game.civInfo.GetCurrentCity();
Group allTiles = new Group();
for(Vector2 vector : HexMath.GetVectorsInDistance(cityInfo.cityLocation,5)){
final TileInfo tileInfo = game.civInfo.tileMap.get(vector);
TileGroup group = new TileGroup(tileInfo);
group.addListener(new ClickListener(){
@Override
public void clicked(InputEvent event, float x, float y) {
selectedTile = tileInfo;
updateTileTable();
}
});
if(!cityInfo.GetCityTiles().contains(tileInfo)) group.setColor(0,0,0,0.3f);
else if(!tileInfo.IsCityCenter()) {
group.addPopulationIcon();
group.populationImage.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
if (cityInfo.GetFreePopulation() > 0 || tileInfo.IsWorked)
tileInfo.IsWorked = !tileInfo.IsWorked;
updateCityTable();
}
});
}
Vector2 positionalVector = HexMath.Hex2WorldCoords(vector.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.setScale(game.settings.tilesZoom);
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);
game.settings.tilesZoom=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() {
CityInfo cityInfo = game.civInfo.GetCurrentCity();
FullStats stats = cityInfo.getCityStats();
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",stats.Production+"");
CityStatsValues.put("Food",stats.Food+" ("+cityInfo.cityPopulation.FoodStored+"/"+cityInfo.cityPopulation.FoodToNextPopulation()+")");
CityStatsValues.put("Gold",stats.Gold+"");
CityStatsValues.put("Science",stats.Science+"");
CityStatsValues.put("Culture",stats.Culture+"");
CityStatsValues.put("Population",cityInfo.GetFreePopulation()+"/"+cityInfo.cityPopulation.Population);
for(String key : CityStatsValues.keySet()){
CityStatsTable.add(ImageGetter.getStatIcon(key)).align(Align.right);
CityStatsTable.add(new Label(CityStatsValues.get(key),skin)).align(Align.left);
CityStatsTable.row();
}
String CurrentBuilding = game.civInfo.GetCurrentCity().cityBuildings.CurrentBuilding;
String BuildingText = "Pick building";
if(CurrentBuilding != null) BuildingText = CurrentBuilding+"\r\n"
+cityInfo.cityBuildings.TurnsToBuilding(CurrentBuilding)+" turns";
TextButton buildingPickButton = new TextButton(BuildingText,skin);
buildingPickButton.addListener(new ClickListener(){
@Override
public void clicked(InputEvent event, float x, float y) {
game.setScreen(new BuildingPickerScreen(game));
dispose();
}
});
buildingPickButton.getLabel().setFontScale(buttonScale);
CityStatsTable.add(buildingPickButton).colspan(2).pad(10)
.size(buildingPickButton.getWidth()*buttonScale,buildingPickButton.getHeight()*buttonScale);
CityStatsTable.setPosition(10,10);
CityStatsTable.pack();
}
private void updateTileTable() {
if(selectedTile == null) return;
TileTable.clearChildren();
CityInfo City =game.civInfo.GetCurrentCity();
FullStats stats = selectedTile.GetTileStats();
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,String> TileStatsValues = new HashMap<String, String>();
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).equals("0")) continue; // this tile gives nothing of this stat, so why even display it?
TileTable.add(ImageGetter.getStatIcon(key)).align(Align.right);
TileTable.add(new Label(TileStatsValues.get(key),skin)).align(Align.left);
TileTable.row();
}
TileTable.pack();
TileTable.setPosition(stage.getWidth()-10- TileTable.getWidth(), 10);
}
@Override
public void render(float delta) {
for(TileGroup HG : tileGroups) {
HG.update();
}
super.render(delta);
}
public static Pixmap getPixmapRoundedRectangle(int width, int height, int radius, int color) {
Pixmap pixmap = new Pixmap(width, height, Pixmap.Format.RGBA8888);
pixmap.setBlending(Blending.None);
pixmap.setColor(color);
pixmap.fillRectangle(0, radius, pixmap.getWidth(), pixmap.getHeight()-2*radius);
pixmap.fillRectangle(radius, 0, pixmap.getWidth() - 2*radius, pixmap.getHeight());
pixmap.fillCircle(radius, radius, radius);
pixmap.fillCircle(radius, pixmap.getHeight()-radius, radius);
pixmap.fillCircle(pixmap.getWidth()-radius, radius, radius);
pixmap.fillCircle(pixmap.getWidth()-radius, pixmap.getHeight()-radius, radius);
return pixmap;
}
}

View File

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

View File

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

View File

@ -0,0 +1,86 @@
package com.unciv.game;
import com.badlogic.gdx.math.Vector2;
import com.unciv.models.LinqCollection;
import java.util.ArrayList;
import java.util.HashSet;
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 LinqCollection<Vector2> GetVectorsInDistance(Vector2 origin, int distance){
HashSet<Vector2> hexesToReturn = new HashSet<Vector2>();
HashSet<Vector2> oldHexes;
HashSet<Vector2> newHexes = new HashSet<Vector2>();
hexesToReturn.add(origin);
newHexes.add(origin);
for (int i = 0; i < distance; i++) {
oldHexes = newHexes;
newHexes = new HashSet<Vector2>();
for (Vector2 vector : oldHexes) {
for (Vector2 adjacentVector : GetAdjacentVectors(vector)){
if(hexesToReturn.contains(adjacentVector)) continue;
hexesToReturn.add(adjacentVector);
newHexes.add(adjacentVector);
}
}
}
return new LinqCollection<Vector2>(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(GetVectorsInDistance(origin,distance).contains(destination)) return distance;
distance++;
}
}
// public static boolean IsWithinDistance(Vector2 a, Vector2 b, int distance){
// return GetVectorsInDistance(a,distance).contains(b);
// Vector2 distanceVector = a.sub(b);
// if(distanceVector.x<0) distanceVector = new Vector2(-distanceVector.x,-distanceVector.y);
//
// int distance = (int) Math.abs(distanceVector.x);
// distanceVector = distanceVector.sub(distanceVector.x,distanceVector.x); // Zero X f distance, then we'll calculate Y
// distance += Math.abs(distanceVector.y);
// return distance;
// }
}

View File

@ -0,0 +1,22 @@
package com.unciv.game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import java.util.HashMap;
public class ImageGetter {
static HashMap<String, TextureRegion> textureRegionByFileName = new HashMap<String, TextureRegion>();
public static Image getImageByFilename(String fileName) {
if (!textureRegionByFileName.containsKey(fileName))
textureRegionByFileName.put(fileName, new TextureRegion(new Texture(Gdx.files.internal(fileName))));
return new Image(textureRegionByFileName.get(fileName));
}
public static Image getStatIcon(String name) {
return getImageByFilename("StatIcons/20x" + name + "5.png");
}
}

View File

@ -0,0 +1,79 @@
package com.unciv.game;
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.badlogic.gdx.utils.Align;
import com.unciv.civinfo.TileInfo;
public class TileGroup extends Group {
Image terrainImage;
Image resourceImage;
Image unitImage;
Image improvementImage;
Image populationImage;
Image hexagon;
Container<TextButton> cityButton;
TileInfo tileInfo;
TileGroup(TileInfo tileInfo){
this.tileInfo = tileInfo;
String terrainFileName = "TerrainIcons/" + tileInfo.GetLastTerrain().Name + "_(Civ5).png";
terrainImage = ImageGetter.getImageByFilename(terrainFileName);
terrainImage.setSize(50,50);
addActor(terrainImage);
}
void addPopulationIcon(){
populationImage = ImageGetter.getStatIcon("Population");
populationImage.setAlign(Align.bottomRight);
populationImage.setX(terrainImage.getWidth()-populationImage.getWidth());
addActor(populationImage);
}
void removePopulationIcon(){
populationImage.remove();
populationImage = null;
}
void update() {
if (tileInfo.HasViewableResource() && resourceImage == null) { // Need to add the resource image!
String fileName = "ResourceIcons/" + tileInfo.Resource + "_(Civ5).png";
Image image = ImageGetter.getImageByFilename(fileName);
image.setScale(0.5f);
image.setOrigin(Align.topRight);
resourceImage = image;
addActor(image);
}
if (tileInfo.Unit != null && unitImage == null) {
unitImage = ImageGetter.getImageByFilename("StatIcons/" + tileInfo.Unit.Name + "_(Civ5).png");
addActor(unitImage);
unitImage.setSize(20, 20);
}
if (tileInfo.Unit == null && unitImage != null) {
unitImage.remove();
unitImage = null;
}
if (tileInfo.Improvement != null && improvementImage == null) {
improvementImage = ImageGetter.getImageByFilename("ImprovementIcons/" + tileInfo.Improvement.replace(' ','_') + "_(Civ5).png");
addActor(improvementImage);
improvementImage.setSize(20, 20);
improvementImage.moveBy(0, terrainImage.getHeight() - improvementImage.getHeight());
}
if(populationImage!=null){
if(tileInfo.IsWorked) populationImage.setColor(Color.WHITE);
else populationImage.setColor(Color.GRAY);
}
}
}

View File

@ -0,0 +1,83 @@
package com.unciv.game;
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.civinfo.CivilizationInfo;
import com.unciv.civinfo.Unit;
import com.unciv.game.pickerscreens.GameSaver;
import com.unciv.models.gamebasics.BasicHelp;
import com.unciv.models.gamebasics.GameBasics;
import com.unciv.models.gamebasics.Technology;
import com.unciv.models.LinqHashMap;
import com.unciv.models.gamebasics.TechColumn;
import com.unciv.models.gamebasics.TileImprovement;
public class UnCivGame extends Game {
public static UnCivGame Current;
public CivilizationInfo civInfo;
public GameSettings settings = new GameSettings();
public WorldScreen worldScreen;
public void create() {
SetupGameBasics();
Current = this;
if(GameSaver.GetSave("Autosave").exists()) GameSaver.LoadGame(this,"Autosave");
else startNewGame();
worldScreen = new WorldScreen(this);
setWorldScreen();
}
public void startNewGame(){
civInfo = new CivilizationInfo();
civInfo.tileMap.get(Vector2.Zero).Unit = new Unit("Settler",2);
worldScreen = new WorldScreen(this);
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 com.unciv.models.stats.NamedStats> 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(com.unciv.models.gamebasics.Building.class,GetFromJson(com.unciv.models.gamebasics.Building[].class,"Buildings"));
GameBasics.Terrains = CreateHashmap(com.unciv.models.gamebasics.Terrain.class,GetFromJson(com.unciv.models.gamebasics.Terrain[].class,"Terrains"));
GameBasics.TileResources = CreateHashmap(com.unciv.models.gamebasics.TileResource.class,GetFromJson(com.unciv.models.gamebasics.TileResource[].class,"TileResources"));
GameBasics.TileImprovements = CreateHashmap(TileImprovement.class,GetFromJson(TileImprovement[].class,"TileImprovements"));
GameBasics.Helps = CreateHashmap(BasicHelp.class,GetFromJson(BasicHelp[].class,"BasicHelp"));
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(com.unciv.models.gamebasics.Building building : GameBasics.Buildings.values()){
if(building.RequiredTech == null) continue;
TechColumn column = building.GetRequiredTech().Column;
building.Cost = building.IsWonder ? column.WonderCost : column.BuildingCost;
}
}
}

View File

@ -0,0 +1,457 @@
package com.unciv.game;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
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.scenes.scene2d.utils.TextureRegionDrawable;
import com.badlogic.gdx.utils.Align;
import com.badlogic.gdx.utils.Predicate;
import com.unciv.civinfo.CityInfo;
import com.unciv.civinfo.TileInfo;
import com.unciv.game.pickerscreens.GameSaver;
import com.unciv.game.pickerscreens.ImprovementPickerScreen;
import com.unciv.game.pickerscreens.TechPickerScreen;
import com.unciv.models.LinqHashMap;
import com.unciv.models.gamebasics.GameBasics;
import com.unciv.models.gamebasics.TileImprovement;
import com.unciv.models.stats.CivStats;
import com.unciv.models.stats.FullStats;
import java.util.HashMap;
import java.util.HashSet;
public class WorldScreen extends CameraStageBaseScreen {
TileInfo selectedTile = null;
TileInfo unitTile = null;
ScrollPane scrollPane;
float buttonScale = game.settings.buttonScale;
Table TileTable = new Table();
Table CivTable = new Table();
TextButton TechButton = new TextButton("",skin);
public LinqHashMap<String,WorldTileGroup> tileGroups = new LinqHashMap<String, WorldTileGroup>();
Table OptionsTable = new Table();
public WorldScreen(final UnCivGame game) {
super(game);
new Label("",skin).getStyle().font.getData().setScale(game.settings.labelScale);
addTiles();
stage.addActor(TileTable);
Drawable tileTableBackground = new TextureRegionDrawable(new TextureRegion(new Texture("skin/tileTableBackground.png")))
.tint(new Color(0x0040804f));
tileTableBackground.setMinHeight(0);
tileTableBackground.setMinWidth(0);
TileTable.setBackground(tileTableBackground);
OptionsTable.setBackground(tileTableBackground);
TextureRegionDrawable civBackground = new TextureRegionDrawable(new TextureRegion(new Texture("skin/civTableBackground.png")));
// civBackground.tint(new Color(0x0040804f));
CivTable.setBackground(civBackground.tint(new Color(0x0040804f)));
stage.addActor(CivTable);
stage.addActor(TechButton);
setCenterPosition(Vector2.Zero);
update();
createNextTurnButton(); // needs civ table to be positioned
addOptionsTable();
}
public void update(){
updateTechButton();
updateTileTable();
updateTiles();
updateCivTable();
}
void addOptionsTable(){
OptionsTable.setVisible(false);
TextButton OpenCivilopediaButton = new TextButton("Civilopedia",skin);
OpenCivilopediaButton.addListener(new ClickListener(){
@Override
public void clicked(InputEvent event, float x, float y) {
game.setScreen(new CivilopediaScreen(game));
OptionsTable.setVisible(false);
}
});
OptionsTable.add(OpenCivilopediaButton).pad(10);
OptionsTable.row();
TextButton StartNewGameButton = new TextButton("Start new game",skin);
StartNewGameButton.addListener(new ClickListener(){
@Override
public void clicked(InputEvent event, float x, float y) {
game.startNewGame();
}
});
OptionsTable.add(StartNewGameButton).pad(10);
OptionsTable.row();
TextButton closeButton = new TextButton("Close",skin);
closeButton.addListener(new ClickListener(){
@Override
public void clicked(InputEvent event, float x, float y) {
OptionsTable.setVisible(false);
}
});
OptionsTable.add(closeButton).pad(10);
OptionsTable.setPosition(stage.getWidth()/2-OptionsTable.getWidth()/2,
stage.getHeight()/2-OptionsTable.getHeight()/2);
stage.addActor(OptionsTable);
}
private void updateTechButton() {
TechButton.setVisible(game.civInfo.Cities.size()!=0);
TechButton.clearListeners();
TechButton.addListener(new ClickListener(){
@Override
public void clicked(InputEvent event, float x, float y) {
game.setScreen(new TechPickerScreen(game));
dispose();
}
});
if (game.civInfo.Tech.CurrentTechnology() == null) TechButton.setText("Choose a tech!");
else TechButton.setText(game.civInfo.Tech.CurrentTechnology() + "\r\n"
+ game.civInfo.TurnsToTech(game.civInfo.Tech.CurrentTechnology()) + " turns");
TechButton.setSize(TechButton.getPrefWidth(), TechButton.getPrefHeight());
TechButton.setPosition(10, CivTable.getY() - TechButton.getHeight()-5);
}
private void updateCivTable() {
CivTable.clear();
CivTable.row().pad(20);
CivStats currentStats = game.civInfo.civStats;
TextButton CivilopediaButton = new TextButton("Menu",skin);
CivilopediaButton.addListener(new ClickListener(){
@Override
public void clicked(InputEvent event, float x, float y) {
OptionsTable.setVisible(true);
dispose();
}
});
CivilopediaButton.getLabel().setFontScale(buttonScale);
CivTable.add(CivilopediaButton)
.size(CivilopediaButton.getWidth() * buttonScale, CivilopediaButton.getHeight() * buttonScale);
CivTable.add(new Label("Turns: " + game.civInfo.turns+"/400", skin));
CivStats nextTurnStats = game.civInfo.GetStatsForNextTurn();
CivTable.add(new Label("Gold: " + currentStats.Gold + "(" +(nextTurnStats.Gold>0?"+":"") + nextTurnStats.Gold+")", skin));
CivTable.add(new Label("Science: +" + nextTurnStats.Science, skin));
CivTable.add(new Label("Happiness: " + nextTurnStats.Happiness, skin));
CivTable.add(new Label("Culture: " + currentStats.Culture + "(+" + nextTurnStats.Culture+")", skin));
CivTable.pack();
CivTable.setPosition(10, stage.getHeight() - 10 - CivTable.getHeight());
CivTable.setWidth(stage.getWidth() - 20);
}
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 (game.civInfo.Tech.CurrentTechnology() == null
&& game.civInfo.Cities.size()!=0) {
game.setScreen(new TechPickerScreen(game));
dispose();
return;
}
game.civInfo.NextTurn();
GameSaver.SaveGame(game,"Autosave");
update();
}
});
nextTurnButton.setPosition(stage.getWidth() - nextTurnButton.getWidth() - 10,
CivTable.getY() - nextTurnButton.getHeight() - 10);
stage.addActor(nextTurnButton);
}
private void addTiles() {
final Group allTiles = new Group();
float topX = 0;
float topY = 0;
float bottomX = 0;
float bottomY = 0;
for (final TileInfo tileInfo : game.civInfo.tileMap.values()) {
final WorldTileGroup group = new WorldTileGroup(tileInfo);
group.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
selectedTile = tileInfo;
if(unitTile != null && group.tileInfo.Unit == null ) {
int distance = HexMath.GetDistance(unitTile.Position, group.tileInfo.Position);
if (distance <= unitTile.Unit.CurrentMovement) {
unitTile.Unit.CurrentMovement -= distance;
group.tileInfo.Unit = unitTile.Unit;
unitTile.Unit = null;
unitTile = null;
selectedTile = group.tileInfo;
}
}
update();
}
});
Vector2 positionalVector = HexMath.Hex2WorldCoords(tileInfo.Position);
int groupSize = 50;
group.setPosition(stage.getWidth() / 2 + positionalVector.x * 0.8f * groupSize,
stage.getHeight() / 2 + positionalVector.y * 0.8f * groupSize);
group.setSize(groupSize, groupSize);
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 : tileGroups.linqValues()) {
group.moveBy(-bottomX, -bottomY);
}
// allTiles.setPosition(-bottomX,-bottomY); // 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(topX - bottomX, topY - bottomY);
scrollPane = new ScrollPane(allTiles);
scrollPane.setFillParent(true);
scrollPane.setOrigin(stage.getWidth() / 2, stage.getHeight() / 2);
scrollPane.setScale(game.settings.tilesZoom);
scrollPane.setSize(stage.getWidth(), stage.getHeight());
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);
game.settings.tilesZoom = scale;
}
});
stage.addActor(scrollPane);
}
private void updateTileTable() {
if(selectedTile == null) return;
TileTable.clearChildren();
FullStats stats = selectedTile.GetTileStats();
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,String> TileStatsValues = new HashMap<String, String>();
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).equals("0")) continue; // this tile gives nothing of this stat, so why even display it?
TileTable.add(ImageGetter.getStatIcon(key)).align(Align.right);
TileTable.add(new Label(TileStatsValues.get(key),skin)).align(Align.left);
TileTable.row();
}
if(selectedTile.Unit!=null){
TextButton moveUnitButton = new TextButton("Move to", skin);
if(unitTile == selectedTile) moveUnitButton = new TextButton("Stop movement",skin);
moveUnitButton.getLabel().setFontScale(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(unitTile!=null) {
unitTile = null;
update();
return;
}
unitTile = selectedTile;
// Set all tiles transparent except those in unit range
for(TileGroup TG : tileGroups.linqValues()) TG.setColor(0,0,0,0.3f);
for(Vector2 vector : HexMath.GetVectorsInDistance(unitTile.Position, unitTile.Unit.CurrentMovement)){
if(tileGroups.containsKey(vector.toString()))
tileGroups.get(vector.toString()).setColor(Color.WHITE);
}
update();
}
});
TileTable.add(moveUnitButton).colspan(2)
.size(moveUnitButton.getWidth() * buttonScale, moveUnitButton.getHeight() * buttonScale);
if(selectedTile.Unit.Name.equals("Settler")){
TextButton foundCityButton = new TextButton("Found City", skin);
foundCityButton.getLabel().setFontScale(buttonScale);
foundCityButton.addListener(new ClickListener(){
@Override
public void clicked(InputEvent event, float x, float y) {
game.civInfo.addCity(selectedTile.Position);
selectedTile.Unit = null; // Remove settler!
update();
}
});
if(HexMath.GetVectorsInDistance(selectedTile.Position,2).any(new Predicate<Vector2>() {
@Override
public boolean evaluate(Vector2 arg0) {
return tileGroups.containsKey(arg0.toString()) &&
tileGroups.get(arg0.toString()).tileInfo.IsCityCenter();
}
})){
foundCityButton.setDisabled(true);
foundCityButton.setColor(Color.GRAY);
}
TileTable.row();
TileTable.add(foundCityButton).colspan(2)
.size(foundCityButton.getWidth() * buttonScale, foundCityButton.getHeight() * buttonScale);
}
if(selectedTile.Unit.Name.equals("Worker")) {
String improvementButtonText = selectedTile.ImprovementInProgress == null ?
"Construct\r\nimprovement" : selectedTile.ImprovementInProgress+"\r\nin progress";
TextButton improvementButton = new TextButton(improvementButtonText, skin);
improvementButton.getLabel().setFontScale(buttonScale);
improvementButton.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
game.setScreen(new ImprovementPickerScreen(game, selectedTile));
dispose();
}
});
if(!GameBasics.TileImprovements.linqValues().any(new Predicate<TileImprovement>() {
@Override
public boolean evaluate(TileImprovement arg0) {
return selectedTile.CanBuildImprovement(arg0);
}
})){
improvementButton.setColor(Color.GRAY);
improvementButton.setTouchable(Touchable.disabled);
}
TileTable.row();
TileTable.add(improvementButton).colspan(2)
.size(improvementButton.getWidth() * buttonScale, improvementButton.getHeight() * buttonScale);
}
}
TileTable.pack();
// TileTable.setBackground(getTableBackground(TileTable.getWidth(),TileTable.getHeight()));
TileTable.setPosition(stage.getWidth()-10- TileTable.getWidth(), 10);
}
private void updateTiles() {
for (WorldTileGroup WG : tileGroups.linqValues()) WG.update(this);
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 : tileGroups.linqValues()) WG.setIsViewable(false);
HashSet<String> ViewableVectorStrings = new HashSet<String>();
// tiles adjacent to city tiles
for(CityInfo city : game.civInfo.Cities)
for(Vector2 tileLocation : city.CityTileLocations)
for(Vector2 adjacentLocation : HexMath.GetAdjacentVectors(tileLocation))
ViewableVectorStrings.add(adjacentLocation.toString());
// Tiles within 2 tiles of units
for(TileInfo tile : game.civInfo.tileMap.values()
.where(new Predicate<TileInfo>() {
@Override
public boolean evaluate(TileInfo arg0) {
return arg0.Unit!=null;
}
}))
for(Vector2 vector : HexMath.GetVectorsInDistance(tile.Position,2))
ViewableVectorStrings.add(vector.toString());
for(String string : ViewableVectorStrings)
if(tileGroups.containsKey(string))
tileGroups.get(string).setIsViewable(true);
}
void setCenterPosition(final Vector2 vector){
TileGroup TG = tileGroups.linqValues().first(new Predicate<WorldTileGroup>() {
@Override
public boolean evaluate(WorldTileGroup arg0) {
return arg0.tileInfo.Position.equals(vector) ;
}
});
float x = TG.getX()-stage.getWidth()/2;
float y = TG.getY()-stage.getHeight()/2;
scrollPane.layout();
scrollPane.setScrollX(x);
scrollPane.setScrollY(y);
scrollPane.updateVisualScroll();
}
}

View File

@ -0,0 +1,79 @@
package com.unciv.game;
import com.badlogic.gdx.math.Vector2;
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.badlogic.gdx.utils.Predicate;
import com.unciv.civinfo.CityInfo;
import com.unciv.civinfo.CivilizationInfo;
import com.unciv.civinfo.TileInfo;
public class WorldTileGroup extends TileGroup {
WorldTileGroup(TileInfo tileInfo) {
super(tileInfo);
}
void setIsViewable(boolean isViewable) {
if (isViewable) setColor(1, 1, 0, 1); // Only alpha really changes anything
else setColor(0, 0, 0, 0.3f);
}
void update(WorldScreen worldScreen) {
super.update();
if(tileInfo.IsWorked && populationImage==null) addPopulationIcon();
if(!tileInfo.IsWorked && populationImage!=null) removePopulationIcon();
if (tileInfo.GetCity() != null && hexagon == null) {
hexagon = ImageGetter.getImageByFilename("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()) {
if (cityButton == null) {
cityButton = new Container<TextButton>();
cityButton.setActor(new TextButton("", worldScreen.skin));
cityButton.getActor().getLabel().setFontScale(0.7f);
final UnCivGame game = worldScreen.game;
cityButton.getActor().addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
game.civInfo.CurrentCity = game.civInfo.Cities.indexOf(city);
game.setScreen(new CityScreen(game));
}
});
addActor(cityButton);
setZIndex(getParent().getChildren().size);
}
String cityButtonText = city.Name+" ("+city.cityPopulation.Population+")"
+ "\r\n" + city.cityBuildings.CurrentBuilding + " in "
+ city.cityBuildings.TurnsToBuilding(city.cityBuildings.CurrentBuilding);
TextButton button = cityButton.getActor();
button.setText(cityButtonText);
button.setSize(button.getPrefWidth(), button.getPrefHeight());
cityButton.setPosition((getWidth() - cityButton.getWidth()) / 2,
getHeight() * 0.9f);
}
}
}

View File

@ -0,0 +1,59 @@
package com.unciv.game.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.civinfo.CityBuildings;
import com.unciv.game.CityScreen;
import com.unciv.game.UnCivGame;
import com.unciv.models.gamebasics.Building;
import com.unciv.models.gamebasics.GameBasics;
public class BuildingPickerScreen extends PickerScreen {
Building selectedBuilding;
public BuildingPickerScreen(final UnCivGame game) {
super(game);
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(game));
dispose();
}
});
rightSideButton.setText("Pick building");
rightSideButton.addListener(new ClickListener(){
@Override
public void clicked(InputEvent event, float x, float y) {
game.civInfo.GetCurrentCity().cityBuildings.CurrentBuilding = selectedBuilding.Name;
game.setScreen(new CityScreen(game));
dispose();
}
});
rightSideButton.setTouchable(Touchable.disabled);
rightSideButton.setColor(Color.GRAY);
CityBuildings cityBuildings = game.civInfo.GetCurrentCity().cityBuildings;
for(final Building building : GameBasics.Buildings.values()) {
if(!cityBuildings.CanBuild(building)) continue;
TextButton TB = new TextButton(building.Name+"\r\n"+cityBuildings.TurnsToBuilding(building.Name)+" turns", skin);
TB.addListener(new ClickListener(){
@Override
public void clicked(InputEvent event, float x, float y) {
selectedBuilding = building;
rightSideButton.setTouchable(Touchable.enabled);
rightSideButton.setText("Build "+building.Name);
rightSideButton.setColor(Color.WHITE);
descriptionLabel.setText(building.GetDescription());
}
});
topTable.add(TB).pad(10);
topTable.row();
}
}
}

View File

@ -0,0 +1,23 @@
package com.unciv.game.pickerscreens;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.utils.Json;
import com.unciv.civinfo.CivilizationInfo;
import com.unciv.game.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.civInfo), false);
}
public static void LoadGame(UnCivGame game, String GameName) {
game.civInfo = new Json().fromJson(CivilizationInfo.class, GetSave(GameName).readString());
}
}

View File

@ -0,0 +1,79 @@
package com.unciv.game.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.unciv.game.CameraStageBaseScreen;
import com.unciv.game.UnCivGame;
import com.unciv.models.gamebasics.GameBasics;
import com.unciv.models.gamebasics.TileImprovement;
public class ImprovementPickerScreen extends CameraStageBaseScreen {
TileImprovement SelectedImprovement;
public ImprovementPickerScreen(final UnCivGame game, final com.unciv.civinfo.TileInfo tileInfo) {
super(game);
Table buttonTable = new Table();
TextButton closeButton =new TextButton("Close", skin);
closeButton.addListener(new ClickListener(){
@Override
public void clicked(InputEvent event, float x, float y) {
game.setScreen(new com.unciv.game.CityScreen(game));
dispose();
}
});
// closeButton.getLabel().setFontScale(0.7f);
buttonTable.add(closeButton).width(stage.getWidth()/4);
final Label improvementDescription = new Label("",skin);
buttonTable.add(improvementDescription).width(stage.getWidth()/2).pad(5);
improvementDescription.setFontScale(game.settings.labelScale);
final TextButton pickImprovementButton = new TextButton("Pick improvement",skin);
pickImprovementButton.addListener(new ClickListener(){
@Override
public void clicked(InputEvent event, float x, float y) {
tileInfo.StartWorkingOnImprovement(SelectedImprovement);
game.setWorldScreen();
dispose();
}
});
// pickImprovementButton.getLabel().setFontScale(0.7f);
pickImprovementButton.setTouchable(Touchable.disabled);
pickImprovementButton.setColor(Color.GRAY);
buttonTable.add(pickImprovementButton).width(stage.getWidth()/4);
Table buildingsTable = new Table();
for(final TileImprovement improvement : GameBasics.TileImprovements.values()) {
if(!tileInfo.CanBuildImprovement(improvement)) continue;
TextButton TB = new TextButton(improvement.Name+"\r\n"+improvement.TurnsToBuild+" turns", skin);
TB.addListener(new ClickListener(){
@Override
public void clicked(InputEvent event, float x, float y) {
SelectedImprovement = improvement;
pickImprovementButton.setTouchable(Touchable.enabled);
pickImprovementButton.setText("Construct "+improvement.Name);
pickImprovementButton.setColor(Color.WHITE);
improvementDescription.setText(improvement.GetDescription());
}
});
buildingsTable.add(TB).pad(10);
buildingsTable.row();
}
ScrollPane scrollPane = new ScrollPane(buildingsTable);
scrollPane.setSize(stage.getWidth(),stage.getHeight()*0.9f);
SplitPane splitPane = new SplitPane(scrollPane, buttonTable, true, skin);
splitPane.setSplitAmount(0.9f);
splitPane.setFillParent(true);
stage.addActor(splitPane);
}
}

View File

@ -0,0 +1,60 @@
package com.unciv.game.pickerscreens;
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.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.game.CameraStageBaseScreen;
import com.unciv.game.UnCivGame;
public class PickerScreen extends CameraStageBaseScreen {
TextButton closeButton;
Label descriptionLabel;
TextButton rightSideButton;
float screenSplit = 0.85f;
Table topTable;
SplitPane splitPane;
public PickerScreen(final UnCivGame game) {
super(game);
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);
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);
}
}

View File

@ -0,0 +1,139 @@
package com.unciv.game.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.game.UnCivGame;
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>();
Technology SelectedTech;
com.unciv.civinfo.CivilizationTech civTech = game.civInfo.Tech;
ArrayList<String> TechsToResearch = new ArrayList<String>(civTech.TechsToResearch);
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);
else if (civTech.CanBeResearched(techName)) TB.setColor(Color.WHITE);
else TB.setColor(Color.GRAY);
TB.setChecked(false);
TB.setText(techName);
if (SelectedTech != null) {
Technology thisTech = GameBasics.Technologies.get(techName);
if (techName.equals(SelectedTech.Name)) {
TB.setChecked(true);
TB.setColor(TB.getColor().lerp(Color.LIGHT_GRAY, 0.5f));
}
if (thisTech.Prerequisites.contains(SelectedTech.Name)) TB.setText("*" + techName);
else if (SelectedTech.Prerequisites.contains(techName)) TB.setText(techName + "*");
}
if (TechsToResearch.contains(techName)) {
TB.setText(TB.getText() + " (" + TechsToResearch.indexOf(techName) + ")");
}
TB.setText(TB.getText() + "\r\n" + game.civInfo.TurnsToTech(techName) + " turns");
}
}
public void selectTechnology(Technology tech) {
SelectedTech = tech;
descriptionLabel.setText(tech.Description);
if (civTech.IsResearched(tech.Name)) {
rightSideButton.setText("Research");
rightSideButton.setTouchable(Touchable.disabled);
rightSideButton.setColor(Color.GRAY);
SetButtonsInfo();
return;
}
rightSideButton.setTouchable(Touchable.enabled);
rightSideButton.setColor(Color.WHITE);
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))
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());
}
rightSideButton.setText("Research \r\n" + TechsToResearch.get(0));
SetButtonsInfo();
}
public TechPickerScreen(final UnCivGame game) {
super(game);
Technology[][] techMatrix = new Technology[10][5]; // Divided into columns, then rows
for (int i = 0; i < techMatrix.length; i++) {
techMatrix[i] = new Technology[10];
}
for (Technology technology : GameBasics.Technologies.linqValues()) {
techMatrix[technology.Column.ColumnNumber][technology.Row - 1] = technology;
}
// Table topTable = new Table();
for (int i = 0; i < 10; i++) {
topTable.row().pad(5);
for (int j = 0; j < 6; 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("Research");
rightSideButton.setTouchable(Touchable.disabled);
rightSideButton.setColor(Color.GRAY);
rightSideButton.addListener(new ClickListener() {
@Override
public void clicked(InputEvent event, float x, float y) {
civTech.TechsToResearch = TechsToResearch;
game.setWorldScreen();
dispose();
}
});
}
}

View File

@ -0,0 +1,62 @@
package com.unciv.models;
import com.badlogic.gdx.utils.Predicate;
import java.util.ArrayList;
import java.util.Collection;
/**
* Created by LENOVO on 10/20/2017.
*/
public class LinqCollection <T> extends ArrayList<T> {
public LinqCollection() {
}
public LinqCollection(Collection<? extends T> objects) {
this.addAll(objects);
}
public LinqCollection<T> where(Predicate<T> p) {
LinqCollection<T> newCollection = new LinqCollection<T>();
for (T t : this) if (p.evaluate(t)) newCollection.add(t);
return newCollection;
}
public T first(Predicate<T> p) {
for (T t : this) if (p.evaluate(t)) return t;
return null;
}
public boolean any(Predicate<T> p){ return first(p) != null;}
public int count(Predicate<T> p) {
return where(p).size();
}
public <T2> LinqCollection<T2> select(Func<T, T2> selector) {
LinqCollection<T2> newCollection = new LinqCollection<T2>();
for (T t : this) newCollection.add(selector.GetBy(t));
return newCollection;
}
public T getRandom(){
if(size()==0) return null;
return get((int) (Math.random() * (size() - 1)));
}
public interface Func<T1, T2> {
public T2 GetBy(T1 arg0);
}
public <T2> LinqCollection<T2> as(Class<T2> t2Class){
LinqCollection<T2> newCollection = new LinqCollection<T2>();
for (T t:this) newCollection.add((T2)t);
return newCollection;
}
}

View File

@ -0,0 +1,9 @@
package com.unciv.models;
import java.util.LinkedHashMap;
public class LinqHashMap <K,V> extends LinkedHashMap<K,V> {
public LinqCollection<V> linqValues() {
return new LinqCollection<V>(super.values());
}
}

View File

@ -0,0 +1,12 @@
package com.unciv.models.gamebasics;
import com.unciv.models.stats.NamedStats;
public class BasicHelp extends NamedStats implements ICivilopedia {
public String Description;
@Override
public String GetDescription() {
return Description;
}
}

View File

@ -0,0 +1,35 @@
package com.unciv.models.gamebasics;
import com.unciv.models.stats.NamedStats;
public class Building extends NamedStats implements ICivilopedia {
public String Description;
public String RequiredTech;
public Technology GetRequiredTech(){return GameBasics.Technologies.get(RequiredTech);}
public int Cost;
public int Maintainance = 0;
public com.unciv.models.stats.FullStats PercentStatBonus = new com.unciv.models.stats.FullStats();
//public Func<CityInfo,FullStats> GetFlatBonusStats;
public boolean IsWonder = false;
public boolean ResourceRequired = false;
public String RequiredBuilding;
public String RequiredBuildingInAllCities;
// Uniques
public String ProvidesFreeBuilding;
public int FreeTechs;
/** The bonus stats that a resource gets when this building is built */
public com.unciv.models.stats.FullStats ResourceBonusStats;
public String GetDescription() {
com.unciv.models.stats.FullStats stats = new com.unciv.models.stats.FullStats(this);
StringBuilder stringBuilder = new StringBuilder();
if(IsWonder) stringBuilder.append("Wonder\r\n");
stringBuilder.append(Description + "\r\n" + stats);
return stringBuilder.toString();
}
}

View File

@ -0,0 +1,12 @@
package com.unciv.models.gamebasics;
import com.unciv.models.LinqHashMap;
public class GameBasics{
public static LinqHashMap<String,Building> Buildings;
public static LinqHashMap<String,Terrain> Terrains;
public static LinqHashMap<String,TileResource> TileResources;
public static LinqHashMap<String,TileImprovement> TileImprovements;
public static LinqHashMap<String, Technology> Technologies;
public static LinqHashMap<String, BasicHelp> Helps;
}

View File

@ -0,0 +1,9 @@
package com.unciv.models.gamebasics;
/**
* Created by LENOVO on 10/18/2017.
*/
public interface ICivilopedia {
public String GetDescription();
}

View File

@ -0,0 +1,14 @@
package com.unciv.models.gamebasics;
import java.util.Collection;
public class StringUtils {
public static String join(String delimiter, Collection<String> collection) {
StringBuilder stringBuilder = new StringBuilder();
for (String str : collection) {
if (stringBuilder.length() != 0) stringBuilder.append(delimiter);
stringBuilder.append(str);
}
return stringBuilder.toString();
}
}

View File

@ -0,0 +1,13 @@
package com.unciv.models.gamebasics;
import java.util.ArrayList;
public class TechColumn
{
public int ColumnNumber;
public GameBasics gameBasics;
public ArrayList<Technology> Techs = new ArrayList<Technology>();
public int TechCost;
public int BuildingCost;
public int WonderCost;
}

View File

@ -0,0 +1,15 @@
package com.unciv.models.gamebasics;
import java.util.ArrayList;
public class Technology
{
public String Name;
public String Description;
public int Cost;
public ArrayList<String> Prerequisites = new ArrayList<String>();
public TechColumn Column; // The column that this tech is in the tech tree
public int Row;
}

View File

@ -0,0 +1,55 @@
package com.unciv.models.gamebasics;
import com.unciv.models.stats.FullStats;
import com.unciv.models.stats.NamedStats;
import java.util.Collection;
public class Terrain extends NamedStats implements ICivilopedia {
public String Type; // BaseTerrain or TerrainFeature
/// <summary>
/// For base terrain - comma-delimited 256 RGB values, e.g. "116,88,62"
/// </summary>
public String RGB;
//
//public Color Color
// {
// get
// {
// var rgbStringValues = RGB.Split(',');
// var rgbs = rgbStringValues.Select(x => int.Parse(x)).ToArray();
// return Extensions.ColorFrom256RGB(rgbs[0], rgbs[1], rgbs[2]);
// }
// }
public boolean OverrideStats = false;
/// <summary>
/// If true, other terrain layers can come over this one. For mountains, lakes etc. this is false
/// </summary>
public boolean CanHaveOverlay = true;
/// <summary>
/// If true, nothing can be built here - not even resource improvements
/// </summary>
public boolean Unbuildable = false;
/// <summary>
/// For terrain features
/// </summary>
public Collection<String> OccursOn;
/// <summary>
/// For terrain features - which technology alllows removal of this feature
/// </summary>
public String RemovalTech;
@Override
public String GetDescription() {
return ""+new FullStats(this);
}
}

View File

@ -0,0 +1,41 @@
package com.unciv.models.gamebasics;
import com.unciv.models.stats.FullStats;
import com.unciv.models.stats.NamedStats;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
public class TileImprovement extends NamedStats implements ICivilopedia {
public Collection<String> TerrainsCanBeBuiltOn = new ArrayList<String>();
public String TechRequired;
public String ImprovingTech;
public FullStats ImprovingTechStats;
public int TurnsToBuild;
@Override
public String GetDescription() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(new FullStats(this)+"\r\n");
if(!TerrainsCanBeBuiltOn.isEmpty()) stringBuilder.append("Can be built on " + com.unciv.models.gamebasics.StringUtils.join(", ", TerrainsCanBeBuiltOn));
HashMap<String,ArrayList<String>> statsToResourceNames = new HashMap<String, ArrayList<String>>();
for(com.unciv.models.gamebasics.TileResource tr : GameBasics.TileResources.values()){
if(!tr.Improvement.equals(Name)) continue;
String statsString = tr.ImprovementStats.toString();
if(!statsToResourceNames.containsKey(statsString))
statsToResourceNames.put(statsString,new ArrayList<String>());
statsToResourceNames.get(statsString).add(tr.Name);
}
for(String statsString : statsToResourceNames.keySet()){
stringBuilder.append("\r\n"+statsString+" for "+ com.unciv.models.gamebasics.StringUtils.join(", ",statsToResourceNames.get(statsString)));
}
if(TechRequired!=null) stringBuilder.append("\r\nTech required: "+TechRequired);
return stringBuilder.toString();
}
}

View File

@ -0,0 +1,32 @@
package com.unciv.models.gamebasics;
import com.unciv.models.stats.NamedStats;
import com.unciv.models.stats.FullStats;
import java.util.Collection;
public class TileResource extends NamedStats implements ICivilopedia {
public String ResourceType;
public Collection<String> TerrainsCanBeFoundOn;
public String Improvement;
public FullStats ImprovementStats;
/// <summary>
/// The building that improves this resource, if any. E.G.: Granary for wheat, Stable for cattle.
/// </summary>
public String Building;
public com.unciv.models.gamebasics.Building GetBuilding(){return Building==null ? null : GameBasics.Buildings.get(Building);}
public String RevealedBy;
@Override
public String GetDescription() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(new FullStats(this)+"\r\n");
stringBuilder.append("Can be found on " + com.unciv.models.gamebasics.StringUtils.join(", ",TerrainsCanBeFoundOn));
stringBuilder.append("\r\n\r\nImproved by "+Improvement+"\r\n");
stringBuilder.append("\r\nBonus stats for improvement: "+ImprovementStats+"\r\n");
return stringBuilder.toString();
}
}

View File

@ -0,0 +1,15 @@
package com.unciv.models.stats;
public class CivStats {
public int Gold = 0;
public int Science = 0;
public int Culture = 0;
public int Happiness = 0;
public void add(CivStats other) {
Gold += other.Gold;
Science += other.Science;
Happiness += other.Happiness;
Culture += other.Culture;
}
}

View File

@ -0,0 +1,41 @@
package com.unciv.models.stats;
public class FullStats extends CivStats // also used for hex stats, since it's basically the same
{
public int Production = 0;
public int Food = 0;
public FullStats() {
}
public FullStats(FullStats other){
add(other);
}
public void add(FullStats other){
Gold+=other.Gold;
Science+=other.Science;
Happiness+=other.Happiness;
Culture+=other.Culture;
Food+=other.Food;
Production+=other.Production;
}
public String display(int value, String name){
return ", " + (value>0 ? "+" : "") + value + " "+name;
}
public String toString() {
StringBuilder valuableParts = new StringBuilder();
if (Production != 0) valuableParts.append(display(Production,"Production"));
if (Food != 0) valuableParts.append(display(Food,"Food"));
if (Gold != 0) valuableParts.append(display(Gold,"Gold"));
if (Science != 0) valuableParts.append(display(Science,"Science"));
if (Happiness != 0) valuableParts.append(display(Happiness,"Happpiness"));
if (Culture != 0) valuableParts.append(display(Culture,"Culture"));
if (valuableParts.length() == 0) return "";
valuableParts.delete(0,1);
return valuableParts.toString();
}
}

View File

@ -0,0 +1,13 @@
package com.unciv.models.stats;
public class NamedStats extends FullStats {
public String Name;
public String GetName() {
return Name;
}
public String toString() {
return Name;
}
}