This commit is contained in:
YueR 2019-09-25 10:31:34 +08:00
commit 2a63d53f7e
98 changed files with 2143 additions and 1960 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 834 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 937 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 831 B

After

Width:  |  Height:  |  Size: 509 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 852 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 590 B

After

Width:  |  Height:  |  Size: 473 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 716 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 936 B

After

Width:  |  Height:  |  Size: 731 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1,010 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 675 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 878 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 853 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 542 B

After

Width:  |  Height:  |  Size: 414 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 722 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3 KiB

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 922 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3 KiB

After

Width:  |  Height:  |  Size: 961 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 937 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 891 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1,007 KiB

After

Width:  |  Height:  |  Size: 1,015 KiB

View file

@ -28,12 +28,12 @@
{
name:"Stone Works",
happiness:1,
production:1
requiredNearbyImprovedResources:["Marble","Stone"]
production:1,
requiredNearbyImprovedResources:["Marble","Stone"],
resourceBonusStats:{production:1},
maintenance:1,
hurryCostModifier:25,
uniques:["Must not be on plains"]
uniques:["Must not be on plains"],
requiredTech:"Calendar"
},
{
@ -41,7 +41,7 @@
culture:6,
isWonder:true,
greatPersonPoints:{production:1},
requiredTech:"Calendar"
requiredTech:"Calendar",
quote:"'Time crumbles things; everything grows old and is forgotten under the power of time' - Aristotle"
},
{
@ -73,11 +73,24 @@
},
{
name:"Circus",
requiredNearbyImprovedResources:["Ivory","Horses"]
requiredNearbyImprovedResources:["Ivory","Horses"],
happiness:2,
hurryCostModifier:25,
requiredTech:"Trapping"
},
/*
{
name:"Temple of Artemis",
culture:1,
isWonder:true,
greatPersonPoints:{production:1},
uniques:["+10% Growth in all Cities.","+15% Production towards Ranged Units."],
requiredTech:"Archery"
quote:"'It is not so much for its beauty that the forest makes a claim upon men's hearts, as for that subtle something, that quality of air, that emanation from old trees, that so wonderfully changes and renews a weary spirit.' - Robert Louis Stevenson"
},
*/
{
name:"Walls",
cityStrength:5,
@ -124,13 +137,32 @@
{
name:"Krepost",
replaces:"Barracks",
uniqueTo:"Russia"
uniqueTo:"Russia",
xpForNewUnits:15,
hurryCostModifier:25,
maintenance:1,
uniques:["Culture and Gold costs of acquiring new tiles reduced by 25% in this city"]
uniques:["Culture and Gold costs of acquiring new tiles reduced by 25% in this city"],
requiredTech:"Bronze Working"
},
/*
{
name:"Statue of Zeus",
culture:1,
isWonder:true,
uniques:["+15% Combat Strenght when attacking Cities."],
requiredTech:"Bronze Working"
quote:"'He spoke, the son of Kronos, and nodded his head with the dark brows, and the immortally anointed hair of the great god swept from his divine head, and all Olympos was shaken' - The Iliad"
},
{
name:"Mausoleum of Halicarnassus",
culture:1,
greatPersonPoints:{gold:1},
isWonder:true,
uniques:["Gain 100 Gold when you use a Great Person.","+2 Gold from every source of Marble and Stone"],
requiredTech:"Masonry"
quote:"'The whole earth is the tomb of heroic men and their story is not given only on stone over their clay but abides everywhere without visible symbol woven into the stuff of other men's lives.' - Pericles"
},
*/
// Classical Era
@ -139,7 +171,7 @@
hurryCostModifier:25,
maintenance:1,
resourceBonusStats:{food:1},
uniques:["Can only be built in coastal cities","+1 food from Ocean and Coast tiles"]
uniques:["Can only be built in coastal cities","+1 food from Ocean and Coast tiles"],
requiredTech:"Optics"
},
{
@ -148,14 +180,14 @@
greatPersonPoints:{gold:1},
isWonder:true,
providesFreeBuilding: "Lighthouse",
uniques:["Can only be built in coastal cities", "All military naval units receive +1 movement and +1 sight"]
uniques:["Can only be built in coastal cities", "All military naval units receive +1 movement and +1 sight"],
requiredTech:"Optics",
quote:"'They that go down to the sea in ships, that do business in great waters; these see the works of the Lord, and his wonders in the deep.' - The Bible, Psalms 107:23-24"
},
{
name:"Stable",
maintenance:1,
requiredNearbyImprovedResources:["Horses","Sheep","Cattle"]
requiredNearbyImprovedResources:["Horses","Sheep","Cattle"],
resourceBonusStats:{production:1},
hurryCostModifier:25,
uniques:["+15% Production when building Mounted Units in this city"]
@ -269,6 +301,18 @@
hurryCostModifier:25,
requiredTech:"Currency"
},
/*
{ //Must be built in or near Desert
name:"Petra",
culture:1,
isWonder:true,
greatPersonPoints:{production:1},
uniques:["+1 Food and +1 Production from all worked Desert tiles in the City (except Flood plains).","+6 Culture when discovering Archeology."],
requiredTech:"Currency"
quote:"'...who drinks the water I shall give him, says the Lord, will have a spring inside him welling up for eternal life. Let them bring me to your holy mountain in the place where you dwell. Across the desert and through the mountain to the Canyon of the Crescent Moon...' - Indiana Jones"
},
*/
{
name:"Aqueduct",
maintenance:1,

View file

@ -2,96 +2,160 @@
{
name:"Settler",
baseHappiness:15,
extraHappinessPerLuxury:1,
researchCostModifier:0.9,
unitCostModifier:0.5,
buildingCostModifier:0.5,
policyCostModifier:0.5,
unhappinessModifier:0.4,
aiCityGrowthModifier:1.6, // that is to say it'll take them 1.6 times as long to grow the city
aiUnitCostModifier:1.75,
aiBuildingCostModifier:1.6,
aiWonderCostModifier:1.6,
aiBuildingMaintenanceModifier:1,
aiUnitMaintenanceModifier:1,
aiYieldModifier:0.6, // Replaces "Construction rate" and "Create rate" in original config
aiFreeTechs:[],
aiFreeUnits:[],
aiUnhappinessModifier:1,
aisExchangeTechs:false
},
{
name:"Chieftain",
baseHappiness:12,
extraHappinessPerLuxury:1,
researchCostModifier:0.95,
unitCostModifier:0.67,
buildingCostModifier:0.67,
policyCostModifier:0.67,
unhappinessModifier:0.6,
aiCityGrowthModifier:1.3,
aiUnitCostModifier:1.3,
aiBuildingCostModifier:1.3,
aiWonderCostModifier:1.3,
aiBuildingMaintenanceModifier:1,
aiUnitMaintenanceModifier:1,
aiYieldModifier:0.75,
aiFreeTechs:[],
aiFreeUnits:[],
aiUnhappinessModifier:1,
aisExchangeTechs:false
},
{
name:"Warlord",
baseHappiness:12,
extraHappinessPerLuxury:0,
researchCostModifier:1,
unitCostModifier:0.85,
buildingCostModifier:0.85,
policyCostModifier:0.85,
unhappinessModifier:0.75,
aiCityGrowthModifier:1.1,
aiUnitCostModifier:1.1,
aiBuildingCostModifier:1.1,
aiWonderCostModifier:1.1,
aiBuildingMaintenanceModifier:1,
aiUnitMaintenanceModifier:1,
aiYieldModifier:0.9,
aiFreeTechs:[],
aiFreeUnits:[],
aiUnhappinessModifier:1,
aisExchangeTechs:false
},
{
name:"Prince",
baseHappiness:9,
extraHappinessPerLuxury:0,
researchCostModifier:1,
unitCostModifier:1,
buildingCostModifier:1,
policyCostModifier:1,
unhappinessModifier:1,
aiCityGrowthModifier:1,
aiUnitCostModifier:1,
aiBuildingCostModifier:1,
aiWonderCostModifier:1,
aiBuildingMaintenanceModifier:1,
aiUnitMaintenanceModifier:0.85,
aiYieldModifier:1,
aiFreeTechs:[],
aiFreeUnits:[],
aiUnhappinessModifier:1,
aisExchangeTechs:true
},
{
name:"King",
baseHappiness:9,
researchCostModifier:1.1,
extraHappinessPerLuxury:0,
researchCostModifier:1,
unitCostModifier:1,
buildingCostModifier:1,
policyCostModifier:1,
unhappinessModifier:1,
aiCityGrowthModifier:0.9,
aiUnitCostModifier:0.85,
aiBuildingCostModifier:0.85,
aiWonderCostModifier:1,
aiBuildingMaintenanceModifier:0.85,
aiUnitMaintenanceModifier:0.8,
aiYieldModifier:1.15,
aiFreeTechs:["Pottery"],
aiFreeUnits:["Warrior"],
aiUnhappinessModifier:0.9,
aisExchangeTechs:true
},
{
name:"Emperor",
baseHappiness:9,
researchCostModifier:1.2,
extraHappinessPerLuxury:0,
researchCostModifier:1,
unitCostModifier:1,
buildingCostModifier:1,
policyCostModifier:1,
unhappinessModifier:1,
aiCityGrowthModifier:0.85,
aiUnitCostModifier:0.8,
aiBuildingCostModifier:0.8,
aiWonderCostModifier:1,
aiBuildingMaintenanceModifier:0.8,
aiUnitMaintenanceModifier:0.75,
aiYieldModifier:1.25,
aiFreeTechs:["Pottery","Animal Husbandry"],
aiFreeUnits:["Warrior", "Scout"],
aiUnhappinessModifier:0.85,
aisExchangeTechs:true
},
{
name:"Immortal",
baseHappiness:9,
researchCostModifier:1.3,
extraHappinessPerLuxury:0,
researchCostModifier:1,
unitCostModifier:1,
buildingCostModifier:1,
policyCostModifier:1,
unhappinessModifier:1,
aiCityGrowthModifier:0.75,
aiUnitCostModifier:0.65,
aiBuildingCostModifier:0.65,
aiWonderCostModifier:1,
aiBuildingMaintenanceModifier:0.65,
aiUnitMaintenanceModifier:0.65,
aiYieldModifier:1.5,
aiFreeTechs:["Pottery","Animal Husbandry","Mining"],
aiFreeUnits:["Warrior", "Warrior", "Worker", "Scout"],
aiUnhappinessModifier:0.75,
aisExchangeTechs:true
},
{
name:"Deity",
baseHappiness:9,
researchCostModifier:1.5,
extraHappinessPerLuxury:0,
researchCostModifier:1,
unitCostModifier:1,
buildingCostModifier:1,
policyCostModifier:1,
unhappinessModifier:1,
aiCityGrowthModifier:0.6,
aiUnitCostModifier:0.5,
aiBuildingCostModifier:0.5,
aiWonderCostModifier:1,
aiBuildingMaintenanceModifier:0.5,
aiUnitMaintenanceModifier:0.5,
aiYieldModifier:2,
aiFreeTechs:["Pottery","Animal Husbandry","Mining","The Wheel"],
aiFreeUnits:["Settler", "Warrior", "Warrior", "Worker", "Worker", "Scout"],
aiUnhappinessModifier:0.6,
aisExchangeTechs:true
}

View file

@ -551,7 +551,7 @@
declaringWar:"Sei una peste per Madre Terra! Preparati a combattere!"
attacked:"Creatura maligna! I miei prodi ti massacreranno!"
defeated:"Ci avrai anche sconfitti... ma i nostri spiriti sono immortali! Tra cento, mille anni torneremo!"
defeated:"Ci avrai anche sconfitti, e io accetto il mio destino... ma i nostri spiriti sono immortali! Tra cento, mille anni, noi torneremo!"
introduction:"Saluti, straniero. Sono Hiawatha, e parlo per il popolo degli Irochesi. Cerchiamo la pace con tutti, ma siamo anche abili guerrieri."
neutralHello:"Buongiorno."
@ -586,23 +586,23 @@
startIntroPart1: "La benedizione del cielo scenda su di te, oh amato re Dario di Persia! Tu sei a capo di un popolo forte e saggio. All'alba del mondo, il grande capo persiano Ciro si rivoltò contro l'impero dei Medi, che nel 550 a.C. scomparve del tutto. Grazie alla sua astuta diplomazia e alla sua prodezza militare, il grande Ciro conquistò la florida Lidia e la potente Babilonia, mentre qualche anno più tardi suo figlio Cambise s'impadronì anche dell'orgoglioso Egitto. Col tempo i persiani si espansero fino alla lontana Macedonia, bussando alla porta delle giovani città-stato greche. A lungo avrebbe prosperato la Persia, fino all'arrivo di quello zotico Alessandro di Macedonia, venuto su dal nulla, che distrusse il nostro glorioso impero con un'unica campagna militare senza precedenti."
startIntroPart2: "Dario, il tuo popolo si rivolge a te per tornare ai giorni della grande e potente Persia! L'impero dei tuoi antenati deve rivivere per trionfare sui suoi nemici e riportare la pace e l'ordine nel mondo. Oh re, risponderai alla chiamata? Riuscirai a plasmare una civiltà in grado di superare la prova del tempo?"
declaringWar:"La tua contiuna esistenza rappresenta un imbarazzo per tutti i leader del mondo! Farò loro un favore distruggendoti!"
declaringWar:"La tua continua esistenza rappresenta un imbarazzo per tutti i leader del mondo! Farò loro un favore distruggendoti!"
attacked:"Non hai forse udito le storie sulla potenza e sulla grandezza delle mie armate? Forse, se le vedrai, ci penserai due volte prima di affrontarmi!"
defeated:"Canaglia! Che tu sia maledetto! Il mondo ricorderà a lungo l'errore che hai commesso!"
defeated:"Canaglia! Che Ahura Mazda ti maledica! Il mondo ricorderà a lungo l'errore che hai commesso!"
introduction:"Che la pace scenda su di te! Io sono Dario, il grande re dei re della Persia... ma sono certo che tu già lo sappia."
neutralHello:"Good day to you!"
neutralLetsHearIt:["Go on.","You said?"]
neutralNo:["You are not serious!","Not good enough."]
neutralYes:["Good!","Certainly.","Agreed!"]
neutralHello:"Buona giornata!"
neutralLetsHearIt:["Va' avanti.","Parla."]
neutralNo:["È uno scherzo?","Non basta."]
neutralYes:["Va bene!","Certamente!","D'accordo!"]
hateHello:"Ahh... you..."
hateLetsHearIt:["I'm listening.","Go on!"]
hateNo:["Io dico... no!","Certo che no!"]
hateHello:"Ahh... sei tu..."
hateLetsHearIt:["Sono tutto orecchi.","Vai avanti!"]
hateNo:["Io dico di no!","Certo che no!"]
hateYes:["Va bene!","D'accordo."]
afterPeace:"Sembra che mi convenga finirla qui..."
tradeRequest:"Nella mia infinita misericordia, ti faccio questa offerta. Di certo, sarai d'accordo?"
afterPeace:"Sembra che mi convenga finirla qui... Mettiamoci una pietra sopra."
tradeRequest:"Nella mia infinita misericordia, ti faccio questa offerta. Di certo, accetterai?"
outerColor:[255,0,0],
innerColor:[255,255,0],

View file

@ -83,6 +83,26 @@
Italian:"'Il tempo sgretola le cose; davanti al suo potere tutto invecchia e viene dimenticato.' - Aristotele"
}
/*
"Temple of Artemis":{
Italian:"Tempio di Artemide"
}
"'It is not so much for its beauty that the forest makes a claim upon men's hearts, as for that subtle something, that quality of air, that emanation from old trees, that so wonderfully changes and renews a weary spirit.' - Robert Louis Stevenson":{
Italian:"'Non è tanto con la sua bellezza che la foresta tocca il cuore degli uomini, ma con un'indefinibile sottigliezza, una certa qualità dell'aria, con l'emanazione degli antichi alberi, che così meravigliosamente muta e rinnova uno spirito fiaccato.' - Robert Louis Stevenson"
}
"+10% Growth in all Cities":{
Italian:"+10% Crescita in tutte le Città"
}
"+15% Production towards Ranged Units":{
Italian:"+15% Produzione per le unità a distanza"
}
*/
"Library":{
Italian:"Biblioteca"
Russian:"Библиотека"
@ -180,7 +200,7 @@
}
"'O, let not the pains of death which come upon thee enter into my body. I am the god Tem, and I am the foremost part of the sky, and the power which protecteth me is that which is with all the gods forever.' - The Book of the Dead, translated by Sir Ernest Alfred Wallis Budge":{
Italian:"''Oh, non lasciare che i dolori della morte che piombano su di te entrino nel mio corpo. Io sono il dio Tem, e risiedo nella parte più importante del cielo, e il potere che mi protegge è quello che si accompagna per sempre a tutti gli dèi.' - Il Libro dei Morti, traduzione di Sir Ernest Alfred Wallis Budge"
Italian:"'Oh, non lasciare che i dolori della morte che piombano su di te entrino nel mio corpo. Io sono il dio Tem, e risiedo nella parte più importante del cielo, e il potere che mi protegge è quello che si accompagna per sempre a tutti gli dèi.' - Il Libro dei Morti, traduzione di Sir Ernest Alfred Wallis Budge"
}
"Worker construction increased 25%":{ //typo? Removed one instance of "Worker construction increased"
@ -233,7 +253,7 @@
}
"Culture and Gold costs of acquiring new tiles reduced by 25% in this city":{
Italian:"-25% costi in Cultura e Oro nell'acquisto di nuove celle nella città"
Italian:"-25% costi in Cultura e Oro nell'acquisto di nuove celle nella Città"
Romanian:"Costurile în Cultură și Aur pentru cumpărarea noilor celule în acest oraș sunt reduse cu 25%"
Spanish:"El coste de comprar terrenos en esta ciudad se reduce un 25%"
Simplified_Chinese:"所在城市扩展新地块所需文化和金钱花费-25%"
@ -454,7 +474,7 @@
}
"+15% Production when building Mounted Units in this city":{
Italian:"+15% Produzione nella città nel reclutare unità a cavallo"
Italian:"+15% Produzione per le unità a cavallo"
German:"+15% Produktion beim Ausbilden von berittenen Einheiten in dieser Stadt"
French:"+15% Production lorsqu'une unité montée est produite dans cette ville"
Simplified_Chinese:"组建骑乘单位时产能积累速率+15%"
@ -506,6 +526,10 @@
Polish:"+15% siły bojowej do ataku na miasta"
}
"'He spoke, the son of Kronos, and nodded his head with the dark brows, and the immortally anointed hair of the great god swept from his divine head, and all Olympos was shaken' - The Iliad":{
Italian:"'Così parlò, il figlio di Crono, e con le nere sopracciglia accennò; le chiome immortali del sire si scompigliarono sul capo divino: scosse tutto l'Olimpo.' - L'Iliade"
}
//New Wonder: Mausoleum of Halicarnassus! Suggested by Smashfanful
"Mausoleum of Halicarnassus":{
Italian:"Mausoleo di Alicarnasso"
@ -520,6 +544,30 @@
Simplified_Chinese:"所在城市开发的每处大理石或花岗石资源额外+2金钱"
Polish:"+2 do złota z każdego złoża marmuru i kamienia"
}
"Gain 100 Gold when you use a Great Person.":{
Italian:"Guadagni 100 Oro ogni volta che consumi un Grande Personaggio"
}
"'The whole earth is the tomb of heroic men and their story is not given only on stone over their clay but abides everywhere without visible symbol woven into the stuff of other men's lives.' - Pericles":{
Italian:"'Tutta la terra è tomba di uomini eroici; la loro storia non resta solo sulla pietra sopra la loro creta, ma si ritrova ovunque, invisibile, intessuta nella vita degli altri.' - Pericle"
}
"Petra":{
Italian:"Petra"
}
"+1 Food and +1 Production from all worked Desert tiles in the City (except Flood plains)":{
Italian:"+1 Cibo e +1 Produzione da tutte le caselle desertiche sfruttate dalla città (eccetto Terreni allagati)"
}
"+6 Culture when discovering Archeology":{
Italian:"+6 Cultura quando scopri l'Archeologia"
}
"'...who drinks the water I shall give him, says the Lord, will have a spring inside him welling up for eternal life. Let them bring me to your holy mountain in the place where you dwell. Across the desert and through the mountain to the Canyon of the Crescent Moon...' - Indiana Jones":{
Italian:"'...colui che beve l'acqua che io gli darò, dice il Signore, avrà dentro di sé una sorgente inesauribile dalla quale sgorgherà la vita eterna. Lasciate che mi conducano alla tua montagna sacra nel luogo dove dimori, attraverso il deserto e oltre la montagna, nella Gola della Luna Crecente...' - Indiana Jones"
}
*/
"Colosseum":{

View file

@ -217,7 +217,7 @@
}
"An enemy [unit] has attacked our [ourUnit]":{
Italian:"Un'unità nemica [unit] ha attaccato [ourUnit]"
Italian:"L'unità nemica [unit] ha attaccato [ourUnit]"
Russian:"Наш [ourUnit] был атакован вражеским [unit]"
French:"Un(e) [unit] ennemi(e) a attaqué [ourUnit]" // Gender sensitive
Romanian:"Un [unit] inamic ne-a atacat un [ourUnit]"
@ -230,7 +230,7 @@
}
"Enemy city [cityName] has attacked our [ourUnit]":{
Italian:"La città nemica [cityName] ha attaccato [ourUnit]"
Italian:"La città nemica di [cityName] ha attaccato [ourUnit]"
French:"La cité ennemie [cityName] a attaqué notre [ourUnit]"
Russian:"Наш [ourUnit] был атакован вражеским городом [cityName]"
Simplified_Chinese:"敌方城市[cityName]攻击了我们的[ourUnit]"
@ -276,7 +276,7 @@
}
"Enemy city [cityName] has destroyed our [ourUnit]":{
Italian:"La città nemica [cityName] ha distrutto [ourUnit]"
Italian:"La città nemica di [cityName] ha distrutto [ourUnit]"
French:"La cité ennemie [cityName] a détruit notre [ourUnit]"
Russian:"Наш [ourUnit] был уничтожен вражеским городом [cityName]"
Simplified_Chinese:"敌方城市[cityName]杀死了我们的[ourUnit]"

View file

@ -21,8 +21,8 @@ android {
applicationId "com.unciv.app"
minSdkVersion 14
targetSdkVersion 29
versionCode 300
versionName "3.0.7"
versionCode 301
versionName "3.1.0"
}
// Had to add this crap for Travis to build, it wanted to sign the app

View file

@ -12,6 +12,7 @@ class Constants{
const val hill = "Hill"
const val coast = "Coast"
const val plains = "Plains"
const val lakes = "Lakes"
const val barbarianEncampment = "Barbarian encampment"
const val ancientRuins = "Ancient ruins"

View file

@ -76,6 +76,12 @@ class GameStarter{
civ.placeUnitNearTile(startingLocation.position, Constants.settler)
civ.placeUnitNearTile(startingLocation.position, "Warrior")
civ.placeUnitNearTile(startingLocation.position, "Scout")
if (!civ.isPlayerCivilization()) {
for (unit in gameInfo.getDifficulty().aiFreeUnits) {
civ.placeUnitNearTile(startingLocation.position, unit)
}
}
}
return gameInfo

View file

@ -162,12 +162,18 @@ class UnitAutomation{
}
fun containsAttackableEnemy(tile: TileInfo, combatant: ICombatant): Boolean {
if(combatant is MapUnitCombatant){
if(combatant is MapUnitCombatant) {
if (combatant.unit.isEmbarked()) {
if (tile.isWater) return false // can't attack water units while embarked, only land
if (combatant.isRanged()) return false
}
if (tile.isLand && combatant.unit.hasUnique("Can only attack water")) return false
if (combatant.unit.hasUnique("Can only attack water")) {
if (tile.isLand) return false
// trying to attack lake-to-coast or vice versa
if ((tile.baseTerrain == Constants.lakes) != (combatant.getTile().baseTerrain == Constants.lakes))
return false
}
}
val tileCombatant = Battle(combatant.getCivInfo().gameInfo).getMapCombatantOfTile(tile)
@ -388,7 +394,7 @@ class UnitAutomation{
val cityTilesToAttack = attackableEnemies.filter { it.tileToAttack.isCityCenter() }
val nonCityTilesToAttack = attackableEnemies.filter { !it.tileToAttack.isCityCenter() }
// todo add filter undefended tile if is air unit
// todo For air units, prefer to attack tiles with lower intercept chance
var enemyTileToAttack: AttackableTile? = null
val capturableCity = cityTilesToAttack.firstOrNull{it.tileToAttack.getCity()!!.health == 1}

View file

@ -33,7 +33,7 @@ class Battle(val gameInfo:GameInfo) {
val attackedTile = defender.getTile()
if(attacker is MapUnitCombatant && attacker.getUnitType().isAirUnit()){
intercept(attacker,defender)
tryInterceptAirAttack(attacker,defender)
if(attacker.isDefeated()) return
}
@ -65,9 +65,9 @@ class Battle(val gameInfo:GameInfo) {
postBattleAction(attacker,defender,attackedTile)
}
private fun postBattleAction(attacker: ICombatant, defender: ICombatant, attackedTile:TileInfo){
private fun postBattleAction(attacker: ICombatant, defender: ICombatant, attackedTile:TileInfo) {
if(attacker.getCivInfo()!=defender.getCivInfo()) { // If what happened was that a civilian unit was captures, that's dealt with in the CaptureCilvilianUnit function
if (attacker.getCivInfo() != defender.getCivInfo()) { // If what happened was that a civilian unit was captures, that's dealt with in the CaptureCilvilianUnit function
val whatHappenedString =
if (attacker !is CityCombatant && attacker.isDefeated()) " {was destroyed while attacking}"
else " has " + (if (defender.isDefeated()) "destroyed" else "attacked")
@ -75,20 +75,20 @@ class Battle(val gameInfo:GameInfo) {
if (attacker.getUnitType() == UnitType.City) "Enemy city [" + attacker.getName() + "]"
else "An enemy [" + attacker.getName() + "]"
val defenderString =
if (defender.getUnitType() == UnitType.City) " [" + defender.getName()+"]"
else " our [" + defender.getName()+"]"
if (defender.getUnitType() == UnitType.City) " [" + defender.getName() + "]"
else " our [" + defender.getName() + "]"
val notificationString = attackerString + whatHappenedString + defenderString
defender.getCivInfo().addNotification(notificationString, attackedTile.position, Color.RED)
}
// Units that heal when killing
if(defender.isDefeated()
if (defender.isDefeated()
&& defender is MapUnitCombatant
&& attacker is MapUnitCombatant){
&& attacker is MapUnitCombatant) {
val regex = Regex("""Heals \[(\d*)\] damage if it kills a unit"""")
for(unique in attacker.unit.getUniques()){
for (unique in attacker.unit.getUniques()) {
val match = regex.matchEntire(unique)
if(match==null) continue
if (match == null) continue
val amountToHeal = match.groups[1]!!.value.toInt()
attacker.unit.healBy(amountToHeal)
}
@ -96,74 +96,84 @@ class Battle(val gameInfo:GameInfo) {
// German unique - needs to be checked before we try to move to the enemy tile, since the encampment disappears after we move in
if(defender.isDefeated() && defender.getCivInfo().isBarbarian()
&& attackedTile.improvement==Constants.barbarianEncampment
&& attacker.getCivInfo().nation.unique== "67% chance to earn 25 Gold and recruit a Barbarian unit from a conquered encampment, -25% land units maintenance."
&& Random().nextDouble() > 0.67){
if (defender.isDefeated() && defender.getCivInfo().isBarbarian()
&& attackedTile.improvement == Constants.barbarianEncampment
&& attacker.getCivInfo().nation.unique == "67% chance to earn 25 Gold and recruit a Barbarian unit from a conquered encampment, -25% land units maintenance."
&& Random().nextDouble() > 0.67) {
attacker.getCivInfo().placeUnitNearTile(attackedTile.position, defender.getName())
attacker.getCivInfo().gold += 25
attacker.getCivInfo().addNotification("A barbarian [${defender.getName()}] has joined us!",attackedTile.position, Color.RED)
attacker.getCivInfo().addNotification("A barbarian [${defender.getName()}] has joined us!", attackedTile.position, Color.RED)
}
// Similarly, Ottoman unique
if(defender.isDefeated() && defender.getUnitType().isWaterUnit() && attacker.isMelee() && attacker.getUnitType().isWaterUnit()
&& attacker.getCivInfo().nation.unique== "Pay only one third the usual cost for naval unit maintenance. Melee naval units have a 1/3 chance to capture defeated naval units."
&& Random().nextDouble() > 0.33){
if (defender.isDefeated() && defender.getUnitType().isWaterUnit() && attacker.isMelee() && attacker.getUnitType().isWaterUnit()
&& attacker.getCivInfo().nation.unique == "Pay only one third the usual cost for naval unit maintenance. Melee naval units have a 1/3 chance to capture defeated naval units."
&& Random().nextDouble() > 0.33) {
attacker.getCivInfo().placeUnitNearTile(attackedTile.position, defender.getName())
}
// we're a melee unit and we destroyed\captured an enemy unit
else if (attacker.isMelee()
&& (defender.isDefeated() || defender.getCivInfo()==attacker.getCivInfo())
&& (defender.isDefeated() || defender.getCivInfo() == attacker.getCivInfo())
// This is so that if we attack e.g. a barbarian in enemy territory that we can't enter, we won't enter it
&& (attacker as MapUnitCombatant).unit.movement.canMoveTo(attackedTile)) {
// we destroyed an enemy military unit and there was a civilian unit in the same tile as well
if(attackedTile.civilianUnit!=null && attackedTile.civilianUnit!!.civInfo != attacker.getCivInfo())
captureCivilianUnit(attacker,MapUnitCombatant(attackedTile.civilianUnit!!))
if (attackedTile.civilianUnit != null && attackedTile.civilianUnit!!.civInfo != attacker.getCivInfo())
captureCivilianUnit(attacker, MapUnitCombatant(attackedTile.civilianUnit!!))
attacker.unit.movement.moveToTile(attackedTile)
}
if(attacker is MapUnitCombatant) {
if (attacker is MapUnitCombatant) {
val unit = attacker.unit
if (unit.hasUnique("Can move after attacking")
|| (unit.hasUnique("1 additional attack per turn") && unit.attacksThisTurn==0)){
|| (unit.hasUnique("1 additional attack per turn") && unit.attacksThisTurn == 0)) {
// if it was a melee attack and we won, then the unit ALREADY got movement points deducted,
// for the movement to the enemy's tile!
// and if it's an air unit, it only has 1 movement anyway, so...
if(!attacker.getUnitType().isAirUnit() && !(attacker.getUnitType().isMelee() && defender.isDefeated()))
if (!attacker.getUnitType().isAirUnit() && !(attacker.getUnitType().isMelee() && defender.isDefeated()))
unit.useMovementPoints(1f)
}
else unit.currentMovement = 0f
unit.attacksThisTurn+=1
if(unit.isFortified() || unit.action == Constants.unitActionSleep)
attacker.unit.action=null // but not, for instance, if it's Set Up - then it should definitely keep the action!
} else unit.currentMovement = 0f
unit.attacksThisTurn += 1
if (unit.isFortified() || unit.action == Constants.unitActionSleep)
attacker.unit.action = null // but not, for instance, if it's Set Up - then it should definitely keep the action!
} else if (attacker is CityCombatant) {
attacker.city.attackedThisTurn = true
}
if(defender.isDefeated()
if (defender.isDefeated()
&& defender is CityCombatant
&& attacker.isMelee())
conquerCity(defender.city, attacker)
if(attacker.isMelee()){
if(!defender.getUnitType().isCivilian()) // unit was not captured but actually attacked
if (attacker.isMelee()) {
if (!defender.getUnitType().isCivilian()) // unit was not captured but actually attacked
{
addXp(attacker,5,defender)
addXp(defender,4,attacker)
addXp(attacker, 5, defender)
addXp(defender, 4, attacker)
}
}
else{ // ranged attack
addXp(attacker,2,defender)
addXp(defender,2,attacker)
} else { // ranged attack
addXp(attacker, 2, defender)
addXp(defender, 2, attacker)
}
// Add culture when defeating a barbarian when Honor policy is adopted (can be either attacker or defender!)
fun tryGetCultureFromHonor(civUnit:ICombatant, barbarianUnit:ICombatant){
tryGetCultureFromHonor(attacker, defender)
tryGetCultureFromHonor(defender, attacker)
if (defender.isDefeated() && defender is MapUnitCombatant && !defender.getUnitType().isCivilian()
&& attacker.getCivInfo().policies.isAdopted("Honor Complete"))
attacker.getCivInfo().gold += defender.unit.baseUnit.getProductionCost(attacker.getCivInfo()) / 10
if (attacker is MapUnitCombatant && attacker.unit.action != null
&& attacker.unit.action!!.startsWith("moveTo"))
attacker.unit.action = null
}
private fun tryGetCultureFromHonor(civUnit:ICombatant, barbarianUnit:ICombatant){
if(barbarianUnit.isDefeated() && barbarianUnit is MapUnitCombatant
&& barbarianUnit.getCivInfo().isBarbarian()
&& civUnit.getCivInfo().policies.isAdopted("Honor"))
@ -171,19 +181,8 @@ class Battle(val gameInfo:GameInfo) {
max(barbarianUnit.unit.baseUnit.strength,barbarianUnit.unit.baseUnit.rangedStrength)
}
tryGetCultureFromHonor(attacker,defender)
tryGetCultureFromHonor(defender,attacker)
if(defender.isDefeated() && defender is MapUnitCombatant && !defender.getUnitType().isCivilian()
&& attacker.getCivInfo().policies.isAdopted("Honor Complete"))
attacker.getCivInfo().gold += defender.unit.baseUnit.getProductionCost(attacker.getCivInfo()) / 10
if(attacker is MapUnitCombatant && attacker.unit.action!=null && attacker.unit.action!!.startsWith("moveTo"))
attacker.unit.action=null
}
// XP!
fun addXp(thisCombatant:ICombatant, amount:Int, otherCombatant:ICombatant){
private fun addXp(thisCombatant:ICombatant, amount:Int, otherCombatant:ICombatant){
if(thisCombatant !is MapUnitCombatant) return
if(thisCombatant.unit.promotions.totalXpProduced() >= 30 && otherCombatant.getCivInfo().isBarbarian())
return
@ -211,12 +210,9 @@ class Battle(val gameInfo:GameInfo) {
for(airUnit in airUnits.toList()) airUnit.destroy()
}
if (attacker.getCivInfo().isPlayerCivilization()) {
if (attacker.getCivInfo().isPlayerCivilization())
attackerCiv.popupAlerts.add(PopupAlert(AlertType.CityConquered, city.name))
} else {
city.annexCity(attacker.getCivInfo())
}
else city.puppetCity(attacker.getCivInfo())
}
fun getMapCombatantOfTile(tile:TileInfo): ICombatant? {
@ -226,12 +222,13 @@ class Battle(val gameInfo:GameInfo) {
return null
}
fun captureCivilianUnit(attacker: ICombatant, defender: ICombatant){
private fun captureCivilianUnit(attacker: ICombatant, defender: ICombatant){
// barbarians don't capture civilians, City-states don't capture settlers
if(attacker.getCivInfo().isBarbarian()
|| (attacker.getCivInfo().isCityState() && defender.getName()==Constants.settler)){
defender.takeDamage(100)
return
} // barbarians don't capture civilians!
}
if (defender.getCivInfo().isDefeated()) {//Last settler captured
defender.getCivInfo().destroy()
@ -247,14 +244,14 @@ class Battle(val gameInfo:GameInfo) {
capturedUnit.updateViewableTiles()
}
fun intercept(attacker:MapUnitCombatant, defender: ICombatant){
private fun tryInterceptAirAttack(attacker:MapUnitCombatant, defender: ICombatant) {
val attackedTile = defender.getTile()
for(interceptor in defender.getCivInfo().getCivUnits().filter { it.canIntercept(attackedTile) }){
if(Random().nextFloat() > 100f/interceptor.interceptChance()) continue
for (interceptor in defender.getCivInfo().getCivUnits().filter { it.canIntercept(attackedTile) }) {
if (Random().nextFloat() > 100f / interceptor.interceptChance()) continue
var damage = BattleDamage().calculateDamageToDefender(MapUnitCombatant(interceptor),attacker)
damage += damage*interceptor.interceptDamagePercentBonus()/100
if(attacker.unit.hasUnique("Reduces damage taken from interception by 50%")) damage/=2
var damage = BattleDamage().calculateDamageToDefender(MapUnitCombatant(interceptor), attacker)
damage += damage * interceptor.interceptDamagePercentBonus() / 100
if (attacker.unit.hasUnique("Reduces damage taken from interception by 50%")) damage /= 2
attacker.takeDamage(damage)
interceptor.attacksThisTurn++
@ -262,16 +259,19 @@ class Battle(val gameInfo:GameInfo) {
val attackerName = attacker.getName()
val interceptorName = interceptor.name
if(attacker.isDefeated()){
attacker.getCivInfo().addNotification("Our [$attackerName] was destroyed by an intercepting [$interceptorName]",
if (attacker.isDefeated()) {
attacker.getCivInfo()
.addNotification("Our [$attackerName] was destroyed by an intercepting [$interceptorName]",
Color.RED)
defender.getCivInfo().addNotification("Our [$interceptorName] intercepted and destroyed an enemy [$attackerName]",
defender.getCivInfo()
.addNotification("Our [$interceptorName] intercepted and destroyed an enemy [$attackerName]",
interceptor.currentTile.position, Color.RED)
}
else{
attacker.getCivInfo().addNotification("Our [$attackerName] was attacked by an intercepting [$interceptorName]",
} else {
attacker.getCivInfo()
.addNotification("Our [$attackerName] was attacked by an intercepting [$interceptorName]",
Color.RED)
defender.getCivInfo().addNotification("Our [$interceptorName] intercepted and attacked an enemy [$attackerName]",
defender.getCivInfo()
.addNotification("Our [$interceptorName] intercepted and attacked an enemy [$attackerName]",
interceptor.currentTile.position, Color.RED)
}
return

View file

@ -59,9 +59,10 @@ class CityConstructions {
fun getCityProductionTextForCityButton(): String {
val currentConstructionSnapshot = currentConstruction // See below
var result = currentConstructionSnapshot .tr()
var result = currentConstructionSnapshot.tr()
if (currentConstructionSnapshot!=""
&& SpecialConstruction.getSpecialConstructions().none { it.name==currentConstructionSnapshot })
result += ("\r\nCost " + getConstruction(currentConstruction).getProductionCost(cityInfo.civInfo).toString()).tr()
result += "\r\n" + turnsToConstruction(currentConstructionSnapshot ) + " {turns}".tr()
return result
}

View file

@ -442,7 +442,7 @@ class CityInfo {
But if they don't keep their promise they get a -20 that will only fully disappear in 160 turns.
There's a lot of triggering going on here.
*/
fun triggerCitiesSettledNearOtherCiv(){
private fun triggerCitiesSettledNearOtherCiv(){
val citiesWithin6Tiles = civInfo.gameInfo.civilizations.filter { it.isMajorCiv() && it!=civInfo }
.flatMap { it.cities }
.filter { it.getCenterTile().arialDistanceTo(getCenterTile()) <= 6 }

View file

@ -107,22 +107,6 @@ class CityStats {
return stats
}
private fun getStatPercentBonusesFromDifficulty(): Stats {
val stats = Stats()
val civ = cityInfo.civInfo
if (!civ.isPlayerCivilization()) {
val modifier = civ.gameInfo.getCurrentPlayerCivilization().getDifficulty().aiYieldModifier
stats.production += modifier
stats.science += modifier
stats.food += modifier
stats.gold += modifier
stats.culture += modifier
}
return stats
}
private fun getStatsFromNationUnique(): Stats {
val stats = Stats()
@ -392,7 +376,6 @@ class CityStats {
newStatPercentBonusList["Railroad"]=getStatPercentBonusesFromRailroad()
newStatPercentBonusList["Marble"]=getStatPercentBonusesFromMarble()
newStatPercentBonusList["Computers"]=getStatPercentBonusesFromComputers()
newStatPercentBonusList["Difficulty"]=getStatPercentBonusesFromDifficulty()
newStatPercentBonusList["National ability"]=getStatPercentBonusesFromNationUnique()
newStatPercentBonusList["Puppet City"]=getStatPercentBonusesFromPuppetCity()
@ -470,8 +453,11 @@ class CityStats {
newFinalStatList["Policies"]!!.food += foodFromGrowthBonuses
// Same here - will have a different UI display.
val buildingsMaintenance = cityInfo.cityConstructions.getMaintenanceCosts() // this is AFTER the bonus calculation!
newFinalStatList["Maintenance"] = Stats().apply { gold -= buildingsMaintenance }
var buildingsMaintenance = cityInfo.cityConstructions.getMaintenanceCosts().toFloat() // this is AFTER the bonus calculation!
if (!cityInfo.civInfo.isPlayerCivilization()) {
buildingsMaintenance *= cityInfo.civInfo.gameInfo.getDifficulty().aiBuildingMaintenanceModifier
}
newFinalStatList["Maintenance"] = Stats().apply { gold -= buildingsMaintenance.toInt() }
if (cityInfo.resistanceCounter > 0)
newFinalStatList.clear() // NOPE

View file

@ -101,7 +101,7 @@ class CivInfoStats(val civInfo: CivilizationInfo){
val statMap = HashMap<String, Float>()
statMap["Base happiness"] = civInfo.getDifficulty().baseHappiness.toFloat()
var happinessPerUniqueLuxury = 5f
var happinessPerUniqueLuxury = 5f + civInfo.getDifficulty().extraHappinessPerLuxury
if (civInfo.policies.isAdopted("Protectionism")) happinessPerUniqueLuxury += 1
statMap["Luxury resources"]= civInfo.getCivResources().map { it.resource }
.count { it.resourceType === ResourceType.Luxury } * happinessPerUniqueLuxury

View file

@ -31,6 +31,8 @@ class PolicyManager {
if (isAdopted("Piety Complete")) policyCultureCost *= 0.9
if (civInfo.containsBuildingUnique("Culture cost of adopting new Policies reduced by 10%"))
policyCultureCost *= 0.9
if (civInfo.isPlayerCivilization())
policyCultureCost *= civInfo.getDifficulty().policyCostModifier
policyCultureCost *= civInfo.gameInfo.gameParameters.gameSpeed.getModifier()
val cost: Int = (policyCultureCost * (1 + cityModifier)).roundToInt()
return cost - (cost % 5)

View file

@ -42,6 +42,7 @@ class TechManager {
fun costOfTech(techName: String): Int {
var techCost = GameBasics.Technologies[techName]!!.cost.toFloat()
if (civInfo.isPlayerCivilization())
techCost *= civInfo.getDifficulty().researchCostModifier
techCost *= civInfo.gameInfo.gameParameters.gameSpeed.getModifier()
techCost *= 1 + (civInfo.cities.size -1 ) * 0.02f // each city increases tech cost by 2%, as per https://civilization.fandom.com/wiki/Science_(Civ5)

View file

@ -2,8 +2,6 @@ package com.unciv.logic.map
import com.badlogic.gdx.math.Vector2
import com.unciv.Constants
import com.unciv.Constants.Companion.mountain
import com.unciv.Constants.Companion.ocean
import com.unciv.logic.HexMath
import com.unciv.models.gamebasics.GameBasics
import com.unciv.models.gamebasics.tile.ResourceType
@ -123,7 +121,7 @@ class CelluarAutomataRandomMapGenerator(): SeedRandomMapGenerator() {
val tile=TileInfo()
tile.position=vector
if (type == TerrainType.Land) tile.baseTerrain = ""
else tile.baseTerrain = ocean
else tile.baseTerrain = Constants.ocean
return tile
}
@ -152,7 +150,7 @@ class CelluarAutomataRandomMapGenerator(): SeedRandomMapGenerator() {
if (tilesInArea.size <= 10) {
for (vector in tilesInArea) {
val tile = map[vector.toString()]!!
tile.baseTerrain = "Lakes"
tile.baseTerrain = Constants.lakes
tile.setTransients()
}
}
@ -160,7 +158,7 @@ class CelluarAutomataRandomMapGenerator(): SeedRandomMapGenerator() {
}
//Coasts
for (tile in map.values.filter { it.baseTerrain == ocean }) {
for (tile in map.values.filter { it.baseTerrain == Constants.ocean }) {
if (HexMath().getVectorsInDistance(tile.position,2).any { hasLandTile(map,it) }) {
tile.baseTerrain = Constants.coast
tile.setTransients()
@ -170,7 +168,7 @@ class CelluarAutomataRandomMapGenerator(): SeedRandomMapGenerator() {
override fun randomizeTile(tileInfo: TileInfo, map: HashMap<String, TileInfo>){
if(tileInfo.getBaseTerrain().type==TerrainType.Land && Math.random()<0.05f){
tileInfo.baseTerrain = mountain
tileInfo.baseTerrain = Constants.mountain
tileInfo.setTransients()
}
addRandomTerrainFeature(tileInfo)
@ -185,8 +183,8 @@ class CelluarAutomataRandomMapGenerator(): SeedRandomMapGenerator() {
fun divideIntoAreas2(averageTilesPerArea: Int, waterPercent: Float, distance: Int, map: HashMap<Vector2, TileInfo>) {
val areas = ArrayList<Area>()
val terrains = GameBasics.Terrains.values.filter { it.type === TerrainType.Land && it.name != "Lakes"
&& it.name != mountain}
val terrains = GameBasics.Terrains.values.filter { it.type === TerrainType.Land && it.name != Constants.lakes
&& it.name != Constants.mountain}
while(map.values.any { it.baseTerrain=="" }) // the world could be split into lots off tiny islands, and every island deserves land types
{
@ -196,7 +194,7 @@ class CelluarAutomataRandomMapGenerator(): SeedRandomMapGenerator() {
for (i in 0 until numberOfSeeds) {
var terrain = if (Math.random() > waterPercent) terrains.random().name
else ocean
else Constants.ocean
val tile = emptyTiles.random()
//change grassland to desert or tundra based on y
@ -204,7 +202,7 @@ class CelluarAutomataRandomMapGenerator(): SeedRandomMapGenerator() {
if (terrain == "Grassland" || terrain == "Tundra")
terrain = "Desert"
} else if (abs(getLatitude(tile.position)) > maxLatitude * 0.7) {
if (terrain == "Grassland" || terrain == Constants.plains || terrain == "Desert" || terrain == ocean) {
if (terrain == "Grassland" || terrain == Constants.plains || terrain == "Desert" || terrain == Constants.ocean) {
terrain = "Tundra"
}
} else {
@ -263,9 +261,9 @@ class PerlinNoiseRandomMapGenerator:SeedRandomMapGenerator(){
+ Perlin.noise(vector.x*ratio*2,vector.y*ratio*2,mapRandomSeed)/2
+ Perlin.noise(vector.x*ratio*4,vector.y*ratio*4,mapRandomSeed)/4
when {
height>0.8 -> tile.baseTerrain = mountain
height>0.8 -> tile.baseTerrain = Constants.mountain
height>0 -> tile.baseTerrain = "" // we'll leave this to the area division
else -> tile.baseTerrain = ocean
else -> tile.baseTerrain = Constants.ocean
}
return tile
}
@ -297,12 +295,12 @@ class AlexanderRandomMapGenerator:RandomMapGenerator(){
if(map[currentSpark]!!.baseTerrain==grassland){
for(tile in emptyTilesAroundSpark){
if(Math.random()<landExpansionChance) map[tile]=TileInfo().apply { baseTerrain=grassland }
else map[tile]=TileInfo().apply { baseTerrain=ocean }
else map[tile]=TileInfo().apply { baseTerrain=Constants.ocean }
}
}
else{
for(tile in emptyTilesAroundSpark)
map[tile]=TileInfo().apply { baseTerrain=ocean }
map[tile]=TileInfo().apply { baseTerrain=Constants.ocean }
}
sparkList.remove(currentSpark)
sparkList.addAll(emptyTilesAroundSpark)
@ -311,7 +309,7 @@ class AlexanderRandomMapGenerator:RandomMapGenerator(){
val newmap = HashMap<String,TileInfo>()
for(entry in map){
entry.value!!.position = entry.key
if(entry.value!!.baseTerrain==ocean
if(entry.value!!.baseTerrain==Constants.ocean
&& HexMath().getAdjacentVectors(entry.key).all { !map.containsKey(it) || map[it]!!.baseTerrain==grassland })
entry.value!!.baseTerrain=grassland
@ -364,7 +362,8 @@ open class SeedRandomMapGenerator : RandomMapGenerator() {
open fun divideIntoAreas(averageTilesPerArea: Int, waterPercent: Float, map: HashMap<Vector2, TileInfo>) {
val areas = ArrayList<Area>()
val terrains = GameBasics.Terrains.values.filter { it.type === TerrainType.Land && it.name != "Lakes" && it.name != mountain }
val terrains = GameBasics.Terrains.values
.filter { it.type === TerrainType.Land && it.name != Constants.lakes && it.name != Constants.mountain }
while(map.values.any { it.baseTerrain=="" }) // the world could be split into lots off tiny islands, and every island deserves land types
{
@ -373,7 +372,7 @@ open class SeedRandomMapGenerator : RandomMapGenerator() {
for (i in 0 until numberOfSeeds) {
val terrain = if (Math.random() > waterPercent) terrains.random().name
else ocean
else Constants.ocean
val area = Area(terrain)
val tile = emptyTiles.random()
emptyTiles -= tile
@ -386,10 +385,10 @@ open class SeedRandomMapGenerator : RandomMapGenerator() {
}
for (area in areas.filter { it.terrain == ocean && it.locations.size <= 10 }) {
for (area in areas.filter { it.terrain == Constants.ocean && it.locations.size <= 10 }) {
// areas with 10 or less tiles are lakes.
for (location in area.locations)
map[location]!!.baseTerrain = "Lakes"
map[location]!!.baseTerrain = Constants.lakes
}
}
@ -439,7 +438,7 @@ open class RandomMapGenerator {
tileInfo.position = position
val terrains = GameBasics.Terrains.values
val baseTerrain = terrains.filter { it.type === TerrainType.Land && it.name != "Lakes" }.random()
val baseTerrain = terrains.filter { it.type === TerrainType.Land }.random()
tileInfo.baseTerrain = baseTerrain.name
addRandomTerrainFeature(tileInfo)
@ -498,7 +497,7 @@ open class RandomMapGenerator {
}
open fun setWaterTiles(map: HashMap<String, TileInfo>) {
for (tile in map.values.filter { it.baseTerrain == ocean }) {
for (tile in map.values.filter { it.baseTerrain == Constants.ocean }) {
if (HexMath().getVectorsInDistance(tile.position,2).any { hasLandTile(map,it) }) {
tile.baseTerrain = Constants.coast
tile.setTransients()
@ -508,12 +507,12 @@ open class RandomMapGenerator {
open fun randomizeTile(tileInfo: TileInfo, map: HashMap<String, TileInfo>){
if(tileInfo.getBaseTerrain().type==TerrainType.Land && Math.random()<0.05f){
tileInfo.baseTerrain = mountain
tileInfo.baseTerrain = Constants.mountain
tileInfo.setTransients()
}
if(tileInfo.getBaseTerrain().type==TerrainType.Land && Math.random()<0.05f
&& HexMath().getVectorsInDistance(tileInfo.position,1).all { hasLandTile(map,it) }){
tileInfo.baseTerrain = "Lakes"
tileInfo.baseTerrain = Constants.lakes
tileInfo.setTransients()
}
addRandomTerrainFeature(tileInfo)

View file

@ -192,6 +192,17 @@ class Building : NamedStats(), IConstruction{
var productionCost = cost.toFloat()
if (!isWonder && culture != 0f && civInfo.policies.isAdopted("Piety"))
productionCost *= 0.85f
if (civInfo.isPlayerCivilization()) {
if(!isWonder) {
productionCost *= civInfo.getDifficulty().buildingCostModifier
}
} else {
if(isWonder) {
productionCost *= civInfo.gameInfo.getDifficulty().aiWonderCostModifier
} else {
productionCost *= civInfo.gameInfo.getDifficulty().aiBuildingCostModifier
}
}
productionCost *= civInfo.gameInfo.gameParameters.gameSpeed.getModifier()
return productionCost.toInt()
}

View file

@ -6,12 +6,20 @@ import java.util.*
class Difficulty: INamed {
override lateinit var name: String
var baseHappiness: Int = 0
var extraHappinessPerLuxury: Float = 0f
var researchCostModifier:Float = 1f
var unhappinessModifier = 1f
var aiCityGrowthModifier = 1f
var unitCostModifier:Float = 1f
var buildingCostModifier:Float = 1f
var policyCostModifier:Float = 1f
var unhappinessModifier:Float = 1f
var aiCityGrowthModifier:Float = 1f
var aiUnitCostModifier:Float = 1f
var aiBuildingCostModifier:Float = 1f
var aiWonderCostModifier:Float = 1f
var aiBuildingMaintenanceModifier:Float = 1f
var aiUnitMaintenanceModifier = 1f
var aiYieldModifier = 1f
var aiFreeTechs = ArrayList<String>()
var aiFreeUnits = ArrayList<String>()
var aiUnhappinessModifier = 1f
var aisExchangeTechs = false
}

View file

@ -99,6 +99,10 @@ class BaseUnit : INamed, IConstruction, ICivilopedia {
override fun getProductionCost(civInfo: CivilizationInfo): Int {
var productionCost = cost.toFloat()
if (civInfo.isPlayerCivilization())
productionCost *= civInfo.getDifficulty().unitCostModifier
else
productionCost *= civInfo.gameInfo.getDifficulty().aiUnitCostModifier
productionCost *= civInfo.gameInfo.gameParameters.gameSpeed.getModifier()
return productionCost.toInt()
}

View file

@ -185,18 +185,20 @@ object ImageGetter {
}
fun getTechIconGroup(techName: String): Group {
var TechIconColor = Color.WHITE
when(GameBasics.Technologies[techName]!!.era().name){
"Ancient"-> TechIconColor = Color.FIREBRICK
"Classical"-> TechIconColor = Color.VIOLET
"Medieval"-> TechIconColor = Color.TAN
"Renaissance"-> TechIconColor = Color.BROWN
"Industrial"-> TechIconColor = Color.CHARTREUSE
"Modern"-> TechIconColor = Color.GOLD
"Information"-> TechIconColor = Color.CORAL
"Future"-> TechIconColor = Color.CYAN
var techIconColor = Color.WHITE
when (GameBasics.Technologies[techName]!!.era().name) {
"Ancient" -> techIconColor = colorFromRGB(255, 87, 35)
"Classical" -> techIconColor = colorFromRGB(233, 31, 99)
"Medieval" -> techIconColor = colorFromRGB(157, 39, 176)
"Renaissance" -> techIconColor = colorFromRGB(104, 58, 183)
"Industrial" -> techIconColor = colorFromRGB(63, 81, 182)
"Modern" -> techIconColor = colorFromRGB(33, 150, 243)
"Information" -> techIconColor = colorFromRGB(0, 150, 136)
"Future" -> techIconColor = colorFromRGB(76,176,81)
}
return getImage("TechIcons/$techName").surroundWithCircle(60f).apply{ this.circle.color = TechIconColor }
return getImage("TechIcons/$techName").apply { color = techIconColor.lerp(Color.BLACK,0.6f) }
.surroundWithCircle(60f)
//.apply { this.circle.color = techIconColor.lerp(Color.WHITE, 0.5f) }
}
fun getProgressBarVertical(width:Float,height:Float,percentComplete:Float,progressColor:Color,backgroundColor:Color): Table {