diff --git a/Assets/Python/AIWars.py b/Assets/Python/AIWars.py
new file mode 100644
index 000000000..315664ba3
--- /dev/null
+++ b/Assets/Python/AIWars.py
@@ -0,0 +1,293 @@
+from CvPythonExtensions import *
+from Consts import INDEPENDENT_CIVS
+from Core import (
+ civilization,
+ civilizations,
+ get_data_from_upside_down_map,
+ get_scenario_start_turn,
+ is_independent_civ,
+ is_major_civ,
+ turn,
+ year,
+ plots,
+)
+from CoreTypes import Civ
+from PyUtils import rand
+from RFCUtils import (
+ getMaster,
+ getPlagueCountdown,
+ isAVassal,
+ minorCoreWars,
+ minorWars,
+ restorePeaceAI,
+ restorePeaceHuman,
+)
+from StoredData import data
+from WarMapData import WARS_MAP
+from Events import handler
+
+gc = CyGlobalContext()
+
+iMinIntervalEarly = 15
+iMaxIntervalEarly = 30
+iMinIntervalLate = 40
+iMaxIntervalLate = 60
+iThreshold = 100
+iMinValue = 30
+
+
+@handler("GameStart")
+def setup():
+ iTurn = get_scenario_start_turn() # only check from the start turn of the scenario
+ data.iNextTurnAIWar = iTurn + rand(iMaxIntervalEarly - iMinIntervalEarly)
+
+
+def getAttackingCivsArray(iCiv):
+ return data.lAttackingCivsArray[iCiv]
+
+
+def setAttackingCivsArray(iCiv, iNewValue):
+ data.lAttackingCivsArray[iCiv] = iNewValue
+
+
+@handler("BeginGameTurn")
+def checkTurn(iGameTurn):
+ if iGameTurn > 20:
+ # Absinthe: automatically turn peace on between independent cities and all the major civs
+ turn_peace_human_mapper = {
+ Civ.INDEPENDENT: 9,
+ Civ.INDEPENDENT_2: 4,
+ Civ.INDEPENDENT_3: 14,
+ Civ.INDEPENDENT_4: 19,
+ }
+ for civ, value in turn_peace_human_mapper.items():
+ if iGameTurn % 20 == value:
+ restorePeaceHuman(civ)
+
+ turn_peace_ai_mapper = {
+ Civ.INDEPENDENT: 0,
+ Civ.INDEPENDENT_2: 9,
+ Civ.INDEPENDENT_3: 18,
+ Civ.INDEPENDENT_4: 27,
+ }
+ for civ, value in turn_peace_ai_mapper.items():
+ if iGameTurn % 36 == value:
+ restorePeaceAI(civ, False)
+
+ # Absinthe: automatically turn war on between independent cities and some AI major civs
+ # runned on the 2nd turn after restorePeaceAI()
+ turn_minor_wars_mapper = {
+ Civ.INDEPENDENT: 2,
+ Civ.INDEPENDENT_2: 11,
+ Civ.INDEPENDENT_3: 20,
+ Civ.INDEPENDENT_4: 29,
+ }
+ for civ, value in turn_minor_wars_mapper.items():
+ if iGameTurn % 36 == value:
+ minorWars(civ, iGameTurn)
+
+ # Absinthe: declare war sooner / more frequently if there is an Indy city inside the core area
+ # so the AI will declare war much sooner after an indy city appeared in it's core
+ turn_minor_core_wars_mapper = {
+ Civ.INDEPENDENT: 10,
+ Civ.INDEPENDENT_2: 7,
+ Civ.INDEPENDENT_3: 4,
+ Civ.INDEPENDENT_4: 1,
+ }
+ for civ, value in turn_minor_core_wars_mapper.items():
+ if iGameTurn % 12 == value:
+ minorCoreWars(civ, iGameTurn)
+
+ # Absinthe: Venice always seeks war with an Independent Ragusa - should help AI Venice significantly
+ if iGameTurn % 9 == 2:
+ pVenice = gc.getPlayer(Civ.VENECIA)
+ if pVenice.isAlive() and not pVenice.isHuman():
+ pRagusaPlot = gc.getMap().plot(64, 28)
+ if pRagusaPlot.isCity():
+ pRagusaCity = pRagusaPlot.getPlotCity()
+ iOwner = pRagusaCity.getOwner()
+ if is_independent_civ(iOwner):
+ # Absinthe: probably better to use declareWar instead of setAtWar
+ teamVenice = gc.getTeam(pVenice.getTeam())
+ teamVenice.declareWar(iOwner, False, WarPlanTypes.WARPLAN_LIMITED)
+
+ # Absinthe: Kingdom of Hungary should try to dominate Sisak/Zagreb if it's independent
+ if iGameTurn > year(1000) and iGameTurn % 7 == 3:
+ pHungary = gc.getPlayer(Civ.HUNGARY)
+ if pHungary.isAlive() and not pHungary.isHuman():
+ pZagrebPlot = gc.getMap().plot(62, 34)
+ if pZagrebPlot.isCity():
+ pZagrebCity = pZagrebPlot.getPlotCity()
+ iOwner = pZagrebCity.getOwner()
+ if is_independent_civ(iOwner):
+ # Absinthe: probably better to use declareWar instead of setAtWar
+ teamHungary = gc.getTeam(pHungary.getTeam())
+ teamHungary.declareWar(iOwner, False, WarPlanTypes.WARPLAN_LIMITED)
+
+ if iGameTurn == data.iNextTurnAIWar:
+ iMinInterval = iMinIntervalEarly
+ iMaxInterval = iMaxIntervalEarly
+
+ # skip if already in a world war
+ iCiv, iTargetCiv = pickCivs()
+ if 0 <= iTargetCiv <= civilizations().drop(Civ.BARBARIAN).len():
+ if iTargetCiv != Civ.POPE and iCiv != Civ.POPE and iCiv != iTargetCiv:
+ initWar(iCiv, iTargetCiv, iGameTurn, iMaxInterval, iMinInterval)
+ return
+ data.iNextTurnAIWar = iGameTurn + iMinInterval + rand(iMaxInterval - iMinInterval)
+
+
+def pickCivs():
+ iCiv = chooseAttackingPlayer()
+ if iCiv != -1:
+ if is_major_civ(iCiv):
+ iTargetCiv = checkGrid(iCiv)
+ return (iCiv, iTargetCiv)
+ else:
+ return (-1, -1)
+
+
+def initWar(iCiv, iTargetCiv, iGameTurn, iMaxInterval, iMinInterval):
+ # Absinthe: don't declare if couldn't do it otherwise
+ teamAgressor = gc.getTeam(gc.getPlayer(iCiv).getTeam())
+ if teamAgressor.canDeclareWar(iTargetCiv):
+ gc.getTeam(gc.getPlayer(iCiv).getTeam()).declareWar(iTargetCiv, True, -1)
+ data.iNextTurnAIWar = iGameTurn + iMinInterval + rand(iMaxInterval - iMinInterval)
+ # Absinthe: if not, next try will come the 1/2 of this time later
+ else:
+ data.iNextTurnAIWar = iGameTurn + (iMinInterval + rand(iMaxInterval - iMinInterval) / 2)
+
+
+def chooseAttackingPlayer():
+ # finding max teams ever alive (countCivTeamsEverAlive() doesn't work as late human starting civ gets killed every turn)
+ iMaxCivs = civilizations().majors().len()
+ for i in civilizations().majors().ids():
+ j = civilizations().main().len() - i
+ if gc.getPlayer(j).isAlive():
+ iMaxCivs = j
+ break
+
+ if gc.getGame().countCivPlayersAlive() <= 2:
+ return -1
+ else:
+ iRndnum = rand(iMaxCivs)
+ iAlreadyAttacked = -100
+ iMin = 100
+ iCiv = -1
+ for i in range(iRndnum, iRndnum + iMaxCivs):
+ iLoopCiv = i % iMaxCivs
+ if gc.getPlayer(iLoopCiv).isAlive() and not gc.getPlayer(iLoopCiv).isHuman():
+ if (
+ getPlagueCountdown(iLoopCiv) >= -10 and getPlagueCountdown(iLoopCiv) <= 0
+ ): # civ is not under plague or quit recently from it
+ iAlreadyAttacked = getAttackingCivsArray(iLoopCiv)
+ if isAVassal(iLoopCiv):
+ iAlreadyAttacked += 1 # less likely to attack
+ # check if a world war is already in place:
+ iNumAlreadyWar = 0
+ tLoopCiv = gc.getTeam(gc.getPlayer(iLoopCiv).getTeam())
+ for kLoopCiv in civilizations().majors().ids():
+ if tLoopCiv.isAtWar(kLoopCiv):
+ iNumAlreadyWar += 1
+ if iNumAlreadyWar >= 4:
+ iAlreadyAttacked += 2 # much less likely to attack
+ elif iNumAlreadyWar >= 2:
+ iAlreadyAttacked += 1 # less likely to attack
+
+ if iAlreadyAttacked < iMin:
+ iMin = iAlreadyAttacked
+ iCiv = iLoopCiv
+ if iAlreadyAttacked != -100:
+ setAttackingCivsArray(iCiv, iAlreadyAttacked + 1)
+ return iCiv
+ else:
+ return -1
+
+
+def checkGrid(iCiv):
+ pCiv = gc.getPlayer(iCiv)
+ pTeam = gc.getTeam(pCiv.getTeam())
+ lTargetCivs = [0] * civilizations().drop(Civ.BARBARIAN).len()
+
+ # set alive civs to 1 to differentiate them from dead civs
+ for iLoopPlayer in civilizations().drop(Civ.BARBARIAN).ids():
+ if iLoopPlayer == iCiv:
+ continue
+ if pTeam.isAtWar(iLoopPlayer): # if already at war with iCiv then it remains 0
+ continue
+ pLoopPlayer = gc.getPlayer(iLoopPlayer)
+ iLoopTeam = pLoopPlayer.getTeam()
+ pLoopTeam = gc.getTeam(iLoopTeam)
+ if (
+ iLoopPlayer < civilizations().majors().len()
+ ): # if master or vassal of iCiv then it remains 0
+ if pLoopTeam.isVassal(iCiv) or pTeam.isVassal(iLoopPlayer):
+ continue
+ if pLoopPlayer.isAlive() and pTeam.isHasMet(iLoopTeam):
+ lTargetCivs[iLoopPlayer] = 1
+
+ for plot in plots.all().not_owner(iCiv).not_owner(Civ.BARBARIAN).entities():
+ if lTargetCivs[plot.getOwner()] > 0:
+ iValue = get_data_from_upside_down_map(WARS_MAP, iCiv, plot)
+ if plot.getOwner() in INDEPENDENT_CIVS:
+ iValue /= 3
+ lTargetCivs[plot.getOwner()] += iValue
+
+ # normalization
+ iMaxTempValue = max(lTargetCivs)
+ if iMaxTempValue > 0:
+ for civ in civilizations().drop(Civ.BARBARIAN).ids():
+ if lTargetCivs[civ] > 0:
+ lTargetCivs[civ] = lTargetCivs[civ] * 500 / iMaxTempValue
+
+ for iLoopCiv in civilizations().drop(Civ.BARBARIAN).ids():
+ if iLoopCiv == iCiv:
+ continue
+
+ if lTargetCivs[iLoopCiv] <= 0:
+ continue
+
+ # add a random value
+ if lTargetCivs[iLoopCiv] <= iThreshold:
+ lTargetCivs[iLoopCiv] += rand(100)
+ else:
+ lTargetCivs[iLoopCiv] += rand(300)
+ # balanced with attitude
+ attitude = 2 * (pCiv.AI_getAttitude(iLoopCiv) - 2)
+ if attitude > 0:
+ lTargetCivs[iLoopCiv] /= attitude
+ # exploit plague
+ if (
+ getPlagueCountdown(iLoopCiv) > 0
+ or getPlagueCountdown(iLoopCiv) < -10
+ and not turn() <= civilization(iLoopCiv).date.birth + 20
+ ):
+ lTargetCivs[iLoopCiv] *= 3
+ lTargetCivs[iLoopCiv] /= 2
+
+ # balanced with master's attitude
+ iMaster = getMaster(iCiv)
+ if iMaster != -1:
+ attitude = 2 * (gc.getPlayer(iMaster).AI_getAttitude(iLoopCiv) - 2)
+ if attitude > 0:
+ lTargetCivs[iLoopCiv] /= attitude
+
+ # if already at war
+ if not pTeam.isAtWar(iLoopCiv):
+ # consider peace counter
+ iCounter = min(7, max(1, pTeam.AI_getAtPeaceCounter(iLoopCiv)))
+ if iCounter <= 7:
+ lTargetCivs[iLoopCiv] *= 20 + 10 * iCounter
+ lTargetCivs[iLoopCiv] /= 100
+
+ # if under pact
+ if pTeam.isDefensivePact(iLoopCiv):
+ lTargetCivs[iLoopCiv] /= 4
+
+ # find max
+ iMaxValue = max(lTargetCivs)
+ iTargetCiv = lTargetCivs.index(iMaxValue)
+
+ if iMaxValue >= iMinValue:
+ return iTargetCiv
+ return -1
diff --git a/Assets/Python/BUG/BugData.py b/Assets/Python/BUG/BugData.py
index 1d225bee1..ec1cd4d0b 100644
--- a/Assets/Python/BUG/BugData.py
+++ b/Assets/Python/BUG/BugData.py
@@ -37,8 +37,11 @@
from CvPythonExtensions import CyGame
import BugUtil
import cPickle as pickle
+from StoredData import data
+STORED_DATA = "doc_stored_data"
+
## Data Access
@@ -100,9 +103,11 @@ def onGameStart(argsList):
def onGameLoad(argsList):
initGameData().load()
+ data.update(getTable(STORED_DATA).data)
def save():
+ getTable(STORED_DATA).setData(data.__dict__)
getGameData().save()
diff --git a/Assets/Python/BUG/BugEventManager.py b/Assets/Python/BUG/BugEventManager.py
index 2c4b76b7c..1c2954453 100644
--- a/Assets/Python/BUG/BugEventManager.py
+++ b/Assets/Python/BUG/BugEventManager.py
@@ -100,16 +100,13 @@
from CvPythonExtensions import *
import CvEventManager
+import BugCore
import BugData
import BugUtil
+import Modifiers
import InputUtil
import types
-import CvRFCEventHandler
-import RiseAndFall
-import Crusades
-import Religions
-import Barbs
# BUG - Mac Support - start
BugUtil.fixSets(globals())
@@ -205,30 +202,10 @@ def __init__(self, logging=None, noLogEvents=None):
self.addEvent("combatLogFlanking")
self.addEvent("playerRevolution")
- self.CustomEvents = {
- 7614: ("RiseAndFallPopupEvent", self.rnfEventApply7614, self.rnfEventBegin7614),
- 7615: ("FlipPopupEvent", self.rnfEventApply7615, self.rnfEventBegin7615),
- 7616: ("CrusadeInitVoteEvent", self.crusadeApply7616, self.crusadeBegin7616),
- 7617: ("InformForLeaderPopup", self.crusadeApply7617, self.crusadeBegin7617),
- 7618: ("HumanVotePopup", self.crusadeApply7618, self.crusadeBegin7618),
- 7619: ("HumanDeviate", self.crusadeApply7619, self.crusadeBegin7619),
- 7620: ("ChoseNewCrusadeTarget", self.crusadeApply7620, self.crusadeBegin7620),
- 7621: ("Under Attack", self.crusadeApply7621, self.crusadeBegin7621),
- 7622: ("ResurrectionEvent", self.rnfEventApply7622, self.rnfEventBegin7622),
- 7624: ("ReformationEvent", self.relEventApply7624, self.relEventBegin7624),
- 7625: ("DefensiveCrusadeEvent", self.crusadeApply7625, self.crusadeBegin7625),
- 7626: ("CounterReformationEvent", self.relEventApply7626, self.relEventBegin7626),
- 7627: ("CounterReformationEvent", self.barbEventApply7627, self.barbEventBegin7627),
- 7628: ("Religious Persecution", self.relEventApply7628, self.relEventBegin7628),
- 7629: ("Free Religious Revolution", self.relEventApply7629, self.relEventBegin7629),
- }
-
- # --> INSERT EVENT HANDLER INITIALIZATION HERE <--
- CvRFCEventHandler.CvRFCEventHandler(self)
- self.rnf = RiseAndFall.RiseAndFall()
- self.crus = Crusades.Crusades()
- self.rel = Religions.Religions()
- self.barb = Barbs.Barbs()
+ self.CustomEvents = {}
+
+ def addCustomEvent(self, iCustomEventID, eventName, applyFunction, beginFunction):
+ self.CustomEvents[iCustomEventID] = (eventName, applyFunction, beginFunction)
def setLogging(self, logging):
if logging is not None:
@@ -455,6 +432,7 @@ def _handleInitBugEvent(self, eventType, argsList):
import BugInit
BugInit.init()
+ Modifiers.setup()
self._handleDefaultEvent(eventType, argsList)
def resetActiveTurn(self, argsList=None):
@@ -595,106 +573,6 @@ def onPlayerRevolution(self, argsList):
", ".join(civics),
)
- # popup events
- def rnfEventBegin7614(self):
- pass
-
- def rnfEventApply7614(self, playerID, netUserData, popupReturn):
- self.rnf.eventApply7614(popupReturn)
-
- def rnfEventBegin7615(self):
- pass
-
- def rnfEventApply7615(self, playerID, netUserData, popupReturn): # 3Miro: flip
- self.rnf.eventApply7615(popupReturn)
-
- def crusadeBegin7616(self):
- pass
-
- def crusadeApply7616(self, playerID, netUserData, popupReturn):
- self.crus.eventApply7616(popupReturn)
-
- def crusadeBegin7617(self):
- pass
-
- def crusadeApply7617(self, playerID, netUserData, popupReturn):
- pass
-
- def crusadeBegin7618(self):
- pass
-
- def crusadeApply7618(self, playerID, netUserData, popupReturn):
- self.crus.eventApply7618(popupReturn)
-
- def crusadeBegin7619(self):
- pass
-
- def crusadeApply7619(self, playerID, netUserData, popupReturn):
- self.crus.eventApply7619(popupReturn)
-
- def crusadeBegin7620(self):
- pass
-
- def crusadeApply7620(self, playerID, netUserData, popupReturn):
- self.crus.eventApply7620(popupReturn)
-
- def crusadeBegin7621(self):
- pass
-
- def crusadeApply7621(self, playerID, netUserData, popupReturn):
- pass
-
- def rnfEventBegin7622(self):
- pass
-
- def rnfEventApply7622(self, playerID, netUserData, popupReturn): # 3Miro: rebel
- self.rnf.eventApply7622(popupReturn)
-
- ### Begin Reformation ###
- def relEventBegin7624(self):
- pass
-
- def relEventApply7624(self, playerID, netUserData, popupReturn):
- self.rel.eventApply7624(popupReturn)
-
- def relEventBegin7626(self):
- pass
-
- def relEventApply7626(self, playerID, netUserData, popupReturn):
- self.rel.eventApply7626(popupReturn)
-
- ### End Reformation ###
-
- def crusadeBegin7625(self):
- pass
-
- def crusadeApply7625(self, playerID, netUserData, popupReturn):
- self.crus.eventApply7625(popupReturn)
-
- def barbEventBegin7627(self):
- pass
-
- def barbEventApply7627(self, playerID, netUserData, popupReturn):
- self.barb.eventApply7627(popupReturn)
-
- # Absinthe: persecution popup
- def relEventBegin7628(self):
- pass
-
- def relEventApply7628(self, playerID, netUserData, popupReturn):
- self.rel.eventApply7628(popupReturn)
-
- # Absinthe: end
-
- # Absinthe: free religion change
- def relEventBegin7629(self):
- pass
-
- def relEventApply7629(self, playerID, netUserData, popupReturn):
- self.rel.eventApply7629(playerID, popupReturn)
-
- # Absinthe: end
-
EVENT_FUNCTION_MAP = {
"kbdEvent": BugEventManager._handleConsumableEvent,
diff --git a/Assets/Python/BUG/BugGameUtils.py b/Assets/Python/BUG/BugGameUtils.py
index 904cc91aa..4b1342578 100644
--- a/Assets/Python/BUG/BugGameUtils.py
+++ b/Assets/Python/BUG/BugGameUtils.py
@@ -373,9 +373,7 @@ def callListener(self, listener, argsList, result):
def __call__(self, argsList=None):
for handler in self.handlers:
if self.log:
- BugUtil.debug(
- "BugGameUtils - %s - dispatching to %s handler", self.name, handler.__module__
- )
+ BugUtil.debug("BugGameUtils - %s - dispatching to %s handler", self.name, handler.__module__)
result = self.callHandler(handler, argsList)
if result is not None and result != self.default:
break
@@ -391,15 +389,12 @@ def __call__(self, argsList=None):
if result is not None:
for listener in self.listeners:
if self.log:
- BugUtil.debug(
- "BugGameUtils - %s - calling %s listener", self.name, listener.__module__
- )
+ BugUtil.debug("BugGameUtils - %s - calling %s listener", self.name, listener.__module__)
self.callListener(listener, argsList, result)
else:
BugUtil.error("BugGameUtils - %s - no handler returned a value", self.name)
return result
-
## Config Parser Handler
diff --git a/Assets/Python/BUG/WidgetUtil.py b/Assets/Python/BUG/WidgetUtil.py
index 1fb965c63..404af57f0 100644
--- a/Assets/Python/BUG/WidgetUtil.py
+++ b/Assets/Python/BUG/WidgetUtil.py
@@ -41,6 +41,7 @@
from CvPythonExtensions import *
import BugConfig
import BugUtil
+from Core import text
gc = CyGlobalContext()
@@ -135,6 +136,15 @@ def getWidgetHelp(argsList):
if iData1 == -1:
return CyTranslator().getText("TXT_KEY_CULTURELEVEL_NONE", ())
+ elif iData1 == 666:
+ return text("TXT_KEY_CLEANSE_RELIGION_MOUSE_OVER")
+ elif iData1 == 1618:
+ return text("TXT_KEY_FAITH_SAINT")
+ elif iData1 == 1919:
+ return text("TXT_KEY_MERCENARY_HELP")
+ elif iData1 == 1920:
+ return text("TXT_KEY_BARBONLY_HELP")
+
## Platy WorldBuilder ##
elif eWidgetType == WidgetTypes.WIDGET_PYTHON:
if iData1 == 1027:
diff --git a/Assets/Python/Barbs.py b/Assets/Python/Barbs.py
new file mode 100644
index 000000000..1fce9165c
--- /dev/null
+++ b/Assets/Python/Barbs.py
@@ -0,0 +1,3656 @@
+# Rhye's and Fall of Civilization: Europe - Barbarian units and cities
+
+from CvPythonExtensions import *
+from Consts import INDEPENDENT_CIVS, MessageData
+from Core import (
+ civilizations,
+ message,
+ event_popup,
+ human,
+ location,
+ make_unit,
+ make_units,
+ text,
+ turn,
+ cities,
+ plots,
+)
+from CoreTypes import Civ, Civic, Religion, Technology, Unit, Province
+from Events import handler, popup_handler
+from PyUtils import percentage, percentage_chance, rand, random_entry, choice
+from RFCUtils import (
+ cultureManager,
+ flipCity,
+ flipUnitsInCityAfter,
+ flipUnitsInCitySecession,
+ forcedInvasion,
+ outerInvasion,
+ outerSeaSpawn,
+ squareSearch,
+)
+from TimelineData import DateTurn
+from StoredData import data
+
+
+gc = CyGlobalContext()
+
+
+# Independent and barbarians city spawns
+# Key: tCity = variations (coordinates, actual city name, chance), owner, population size, defender type, number of defenders, religion, workers
+# Notes: Indy cities start with zero-sized culture, barbs with normal culture
+# Added some initial food reserves on founding cities, so even independents won't shrink on their first turn anymore
+# Barbarian cities start with 2 additional defender units
+# Walls (and other buildings) can be added with the onCityBuilt function, in RiseAndFall.py
+# 500 AD
+tTangier = (
+ [((27, 16), "Tangier", 100)],
+ Civ.INDEPENDENT_2,
+ 1,
+ Unit.CORDOBAN_BERBER,
+ 2,
+ -1,
+ 0,
+)
+tBordeaux = ([((37, 38), "Burdigala", 100)], Civ.BARBARIAN, 2, Unit.ARCHER, 0, -1, 0)
+tAlger = (
+ [((40, 16), "Alger", 60), ((34, 13), "Tlemcen", 40)],
+ Civ.INDEPENDENT_3,
+ 1,
+ Unit.ARCHER,
+ 1,
+ Religion.CATHOLICISM,
+ 0,
+)
+tBarcelona = (
+ [((40, 28), "Barcino", 100)],
+ Civ.INDEPENDENT_2,
+ 1,
+ Unit.ARCHER,
+ 1,
+ -1,
+ 0,
+)
+tToulouse = (
+ [((41, 34), "Tolosa", 30), ((40, 34), "Tolosa", 30), ((42, 32), "Narbo", 40)],
+ Civ.BARBARIAN,
+ 1,
+ Unit.ARCHER,
+ 0,
+ -1,
+ 0,
+)
+tMarseilles = (
+ [((46, 32), "Massilia", 50), ((46, 33), "Aquae Sextiae", 50)],
+ Civ.INDEPENDENT,
+ 1,
+ Unit.ARCHER,
+ 1,
+ Religion.CATHOLICISM,
+ 0,
+)
+tNantes = (
+ [((36, 43), "Naoned", 50), ((35, 43), "Gwened", 30), ((37, 44), "Roazhon", 20)],
+ Civ.INDEPENDENT_2,
+ 1,
+ Unit.ARCHER,
+ 1,
+ -1,
+ 0,
+)
+tCaen = (
+ [((40, 47), "Caen", 100)],
+ Civ.INDEPENDENT_4,
+ 2,
+ Unit.ARCHER,
+ 1,
+ Religion.CATHOLICISM,
+ 1,
+)
+tLyon = (
+ [((46, 37), "Lyon", 100)],
+ Civ.INDEPENDENT_3,
+ 2,
+ Unit.ARCHER,
+ 2,
+ Religion.CATHOLICISM,
+ 1,
+)
+tTunis = ([((49, 17), "Tunis", 100)], Civ.INDEPENDENT_4, 2, Unit.ARCHER, 1, -1, 0)
+tYork = ([((39, 59), "Eboracum", 100)], Civ.INDEPENDENT_4, 1, Unit.ARCHER, 2, -1, 1)
+tLondon = (
+ [((41, 52), "Londinium", 100)],
+ Civ.INDEPENDENT,
+ 2,
+ Unit.ARCHER,
+ 2,
+ Religion.CATHOLICISM,
+ 0,
+)
+tMilan = (
+ [((52, 37), "Mediolanum", 100)],
+ Civ.INDEPENDENT,
+ 2,
+ Unit.ARCHER,
+ 2,
+ Religion.CATHOLICISM,
+ 0,
+)
+tFlorence = (
+ [((54, 32), "Florentia", 40), ((53, 32), "Pisae", 40), ((57, 31), "Ankon", 20)],
+ Civ.INDEPENDENT_2,
+ 2,
+ Unit.ARCHER,
+ 2,
+ Religion.CATHOLICISM,
+ 0,
+)
+tTripoli = ([((54, 8), "Tripoli", 100)], Civ.BARBARIAN, 1, Unit.ARCHER, 1, -1, 0)
+tAugsburg = (
+ [((55, 41), "Augsburg", 100)],
+ Civ.INDEPENDENT_3,
+ 1,
+ Unit.ARCHER,
+ 2,
+ -1,
+ 0,
+)
+tNapoli = (
+ [((59, 24), "Neapolis", 40), ((60, 25), "Beneventum", 40), ((62, 24), "Tarentum", 20)],
+ Civ.INDEPENDENT,
+ 2,
+ Unit.ARCHER,
+ 1,
+ -1,
+ 0,
+)
+tRagusa = (
+ [((64, 28), "Ragusa", 100)],
+ Civ.INDEPENDENT_2,
+ 1,
+ Unit.ARCHER,
+ 2,
+ Religion.CATHOLICISM,
+ 0,
+)
+tSeville = ([((27, 21), "Hispalis", 100)], Civ.INDEPENDENT_4, 1, Unit.ARCHER, 2, -1, 0)
+tPalermo = (
+ [((55, 19), "Palermo", 60), ((58, 17), "Syracuse", 40)],
+ Civ.INDEPENDENT_3,
+ 2,
+ Unit.ARCHER,
+ 1,
+ Religion.CATHOLICISM,
+ 1,
+)
+# 552 AD
+tInverness = (
+ [((37, 67), "Inbhir Nis", 50), ((37, 65), "Scaig", 50)],
+ Civ.BARBARIAN,
+ 1,
+ Unit.ARCHER,
+ 1,
+ -1,
+ 0,
+) # reduced to town on spawn of Scotland
+# 600 AD
+tRhodes = (
+ [((80, 13), "Rhodes", 100)],
+ Civ.INDEPENDENT_2,
+ 1,
+ Unit.ARCHER,
+ 1,
+ Religion.ORTHODOXY,
+ 0,
+)
+# 640 AD
+tNorwich = (
+ [((43, 55), "Norwich", 100)],
+ Civ.INDEPENDENT_3,
+ 1,
+ Unit.ARCHER,
+ 1,
+ -1,
+ 1,
+) # reduced to town on spawn of England
+# 670 AD
+tKairouan = (
+ [((48, 14), "Kairouan", 100)],
+ Civ.INDEPENDENT_2,
+ 1,
+ Unit.ARCHER,
+ 1,
+ Religion.ISLAM,
+ 0,
+)
+# 680 AD
+tToledo = (
+ [((30, 27), "Toledo", 100)],
+ Civ.BARBARIAN,
+ 1,
+ Unit.ARCHER,
+ 1,
+ Religion.CATHOLICISM,
+ 1,
+)
+tLeicester = (
+ [((39, 56), "Ligeraceaster", 100)],
+ Civ.INDEPENDENT,
+ 1,
+ Unit.ARCHER,
+ 1,
+ -1,
+ 0,
+) # reduced to town on spawn of England
+# 700 AD
+tValencia = (
+ [((36, 25), "Valencia", 100)],
+ Civ.INDEPENDENT,
+ 1,
+ Unit.ARCHER,
+ 1,
+ Religion.CATHOLICISM,
+ 1,
+)
+tPamplona = (
+ [((35, 32), "Pamplona", 70), ((34, 33), "Pamplona", 30)],
+ Civ.INDEPENDENT_4,
+ 1,
+ Unit.CROSSBOWMAN,
+ 2,
+ -1,
+ 0,
+)
+tLubeck = (
+ [((57, 54), "Liubice", 40), ((57, 53), "Liubice", 60)],
+ Civ.INDEPENDENT_2,
+ 1,
+ Unit.ARCHER,
+ 2,
+ -1,
+ 1,
+)
+tPorto = (
+ [((23, 31), "Portucale", 100)],
+ Civ.INDEPENDENT_3,
+ 1,
+ Unit.CROSSBOWMAN,
+ 2,
+ Religion.CATHOLICISM,
+ 0,
+)
+tDublin = (
+ [((32, 58), "Teamhair", 100)],
+ Civ.BARBARIAN,
+ 1,
+ Unit.SPEARMAN,
+ 1,
+ Religion.CATHOLICISM,
+ 1,
+) # Hill of Tara, later becomes Dublin
+tDownpatrick = (
+ [((33, 61), "Rath Celtair", 20), ((29, 60), "Cruiachain", 30), ((29, 56), "Caisel", 50)],
+ Civ.BARBARIAN,
+ 1,
+ Unit.ARCHER,
+ 0,
+ -1,
+ 1,
+) # Cruiachain = Rathcroghan, later becomes Sligo; Caisel = Cashel, later becomes Cork
+# 760 AD
+tTonsberg = (
+ [((57, 65), "Tonsberg", 100)],
+ Civ.INDEPENDENT_3,
+ 1,
+ Unit.ARCHER,
+ 2,
+ -1,
+ 0,
+)
+# 768 AD
+tRaska = ([((68, 28), "Ras", 100)], Civ.INDEPENDENT_2, 1, Unit.ARCHER, 2, -1, 1)
+# 780 AD
+tFez = ([((29, 12), "Fes", 100)], Civ.INDEPENDENT_4, 1, Unit.CROSSBOWMAN, 2, -1, 1)
+# 800 AD
+tMilanR = (
+ [((52, 37), "Milano", 100)],
+ Civ.INDEPENDENT,
+ 4,
+ Unit.ARCHER,
+ 2,
+ Religion.CATHOLICISM,
+ 0,
+) # respawn, in case it was razed
+# tFlorenceR = ( [ ((54, 32), "Firenze", 100) ], Civ.INDEPENDENT_2, 4, Unit.ARCHER, 2, Religion.CATHOLICISM, 0 ) #respawn, doesn't work with the multiple options in 500AD
+tPrague = (
+ [((60, 44), "Praha", 100)],
+ Civ.INDEPENDENT,
+ 1,
+ Unit.CROSSBOWMAN,
+ 2,
+ Religion.CATHOLICISM,
+ 1,
+)
+tKursk = ([((90, 48), "Kursk", 100)], Civ.INDEPENDENT_4, 1, Unit.ARCHER, 2, -1, 0)
+tCalais = (
+ [((44, 50), "Calais", 50), ((45, 50), "Dunkerque", 50)],
+ Civ.INDEPENDENT_3,
+ 1,
+ Unit.CROSSBOWMAN,
+ 2,
+ -1,
+ 0,
+)
+tNidaros = (
+ [((57, 71), "Nidaros", 100)],
+ Civ.INDEPENDENT_3,
+ 1,
+ Unit.ARCHER,
+ 1,
+ -1,
+ 1,
+) # Trondheim
+tUppsala = (
+ [((65, 66), "Uppsala", 100)],
+ Civ.INDEPENDENT_4,
+ 1,
+ Unit.ARCHER,
+ 2,
+ -1,
+ 1,
+) # reduced to town on spawn of Sweden
+tBeloozero = (
+ [((87, 65), "Beloozero", 100)],
+ Civ.INDEPENDENT_4,
+ 1,
+ Unit.CROSSBOWMAN,
+ 1,
+ -1,
+ 1,
+)
+tZagreb = (
+ [((62, 34), "Sisak", 100)],
+ Civ.INDEPENDENT,
+ 2,
+ Unit.ARCHER,
+ 2,
+ -1,
+ 0,
+) # many Slavic princes reigned from Sisak in the 9th century, great for gameplay (buffer zone between Venice and Hungary)
+# 850 AD
+tBrennabor = (
+ [((59, 50), "Brennabor", 50), ((60, 50), "Brennabor", 50)],
+ Civ.BARBARIAN,
+ 1,
+ Unit.ARCHER,
+ 2,
+ -1,
+ 0,
+) # Brandenburg or Berlin
+# 860 AD
+# tEdinburgh = ( [ ((37, 63), "Eidyn Dun", 100) ], Civ.BARBARIAN, 1, Unit.ARCHER, 1, -1, 0)
+# 880 AD
+tApulum = (
+ [((73, 35), "Belograd", 80), ((73, 37), "Napoca", 20)],
+ Civ.INDEPENDENT,
+ 1,
+ Unit.ARCHER,
+ 2,
+ -1,
+ 0,
+) # Gyulafehérvár or Kolozsvár
+# 900 AD
+tTvanksta = (
+ [((69, 53), "Tvanksta", 100)],
+ Civ.INDEPENDENT_4,
+ 1,
+ Unit.CROSSBOWMAN,
+ 2,
+ -1,
+ 0,
+) # Königsberg
+tKrakow = (
+ [((68, 44), "Krakow", 100)],
+ Civ.INDEPENDENT_3,
+ 1,
+ Unit.CROSSBOWMAN,
+ 2,
+ Religion.CATHOLICISM,
+ 0,
+)
+tRiga = (
+ [((74, 58), "Riga", 100)],
+ Civ.INDEPENDENT,
+ 2,
+ Unit.CROSSBOWMAN,
+ 2,
+ -1,
+ 1,
+) # maybe call it Duna in the early pediod (Duna is the name of a sheltered natural harbor near Riga)
+tWales = (
+ [((36, 54), "Caerdydd", 50), ((35, 57), "Aberffraw", 50)],
+ Civ.BARBARIAN,
+ 1,
+ Unit.ARCHER,
+ 1,
+ -1,
+ 1,
+) # Cardiff and Caernarfon
+tVisby = (
+ [((67, 60), "Visby", 100)],
+ Civ.INDEPENDENT_2,
+ 1,
+ Unit.CROSSBOWMAN,
+ 1,
+ -1,
+ 0,
+) # used to spawn in 1393 in the old system
+# 911 AD
+tCaenR = (
+ [((40, 47), "Caen", 100)],
+ Civ.INDEPENDENT_2,
+ 1,
+ Unit.CROSSBOWMAN,
+ 2,
+ Religion.CATHOLICISM,
+ 0,
+) # respawn, on the establishment of the Duchy of Normandy
+# 960 AD
+tMinsk = ([((79, 52), "Minsk", 100)], Civ.INDEPENDENT_3, 1, Unit.CROSSBOWMAN, 2, -1, 0)
+tSmolensk = (
+ [((84, 55), "Smolensk", 100)],
+ Civ.INDEPENDENT_4,
+ 1,
+ Unit.CROSSBOWMAN,
+ 1,
+ -1,
+ 0,
+)
+# 988 AD
+tDublinR = (
+ [((32, 58), "Dubh Linn", 100)],
+ Civ.BARBARIAN,
+ 1,
+ Unit.CROSSBOWMAN,
+ 1,
+ Religion.CATHOLICISM,
+ 1,
+) # respawn, on the traditional Irish foundation date of Dublin
+# 1010 AD
+tYaroslavl = (
+ [((92, 61), "Yaroslavl", 100)],
+ Civ.INDEPENDENT_3,
+ 1,
+ Unit.CROSSBOWMAN,
+ 1,
+ -1,
+ 0,
+)
+# 1050 AD
+tGroningen = (
+ [((52, 54), "Groningen", 100)],
+ Civ.INDEPENDENT_2,
+ 1,
+ Unit.CROSSBOWMAN,
+ 2,
+ Religion.CATHOLICISM,
+ 0,
+)
+tKalmar = (
+ [((64, 60), "Kalmar", 100)],
+ Civ.INDEPENDENT_2,
+ 2,
+ Unit.CROSSBOWMAN,
+ 1,
+ Religion.CATHOLICISM,
+ 1,
+)
+# 1060 AD
+# tMus = ( [ ((99, 21), "Mus", 100) ], Civ.BARBARIAN, 1, Unit.SELJUK_CROSSBOW, 2, -1, 0) #out of the map, not that important to represent the Seljuk/Timurid invasions this way
+# 1110 AD
+tGraz = (
+ [((61, 37), "Graz", 100)],
+ Civ.INDEPENDENT_3,
+ 2,
+ Unit.CROSSBOWMAN,
+ 2,
+ Religion.CATHOLICISM,
+ 0,
+)
+# 1124 AD
+tHalych = (
+ [((77, 41), "Halych", 100)],
+ Civ.INDEPENDENT_2,
+ 2,
+ Unit.CROSSBOWMAN,
+ 2,
+ Religion.ORTHODOXY,
+ 0,
+)
+# 1200 AD
+tRigaR = (
+ [((74, 58), "Riga", 100)],
+ Civ.INDEPENDENT,
+ 3,
+ Unit.CROSSBOWMAN,
+ 2,
+ -1,
+ 1,
+) # respawn
+# tSaraiBatu = ( [ ((99, 40), "Sarai Batu", 100) ], Civ.BARBARIAN, 1, Unit.MONGOL_KESHIK, 2, -1, 0) #out of the map, not that important to represent the Mongol invasions this way
+# 1227 AD
+tTripoliR = (
+ [((54, 8), "Tarabulus", 100)],
+ Civ.BARBARIAN,
+ 3,
+ Unit.ARBALEST,
+ 2,
+ Religion.ISLAM,
+ 1,
+) # respawn
+# 1250 AD
+tAbo = ([((71, 66), "Abo", 100)], Civ.INDEPENDENT_4, 1, Unit.CROSSBOWMAN, 1, -1, 0)
+tPerekop = (
+ [((87, 36), "Or Qapi", 100)],
+ Civ.BARBARIAN,
+ 1,
+ Unit.MONGOL_KESHIK,
+ 2,
+ -1,
+ 0,
+)
+# 1320 AD
+tNizhnyNovgorod = (
+ [((97, 58), "Nizhny Novgorod", 100)],
+ Civ.INDEPENDENT,
+ 1,
+ Unit.CROSSBOWMAN,
+ 1,
+ -1,
+ 0,
+)
+# 1392 AD
+tTanais = (
+ [((96, 38), "Tana", 100)],
+ Civ.BARBARIAN,
+ 1,
+ Unit.LONGBOWMAN,
+ 2,
+ Religion.ISLAM,
+ 0,
+)
+# 1410 AD
+tReykjavik = (
+ [((2, 70), "Reykjavik", 100)],
+ Civ.INDEPENDENT,
+ 1,
+ Unit.VIKING_BERSERKER,
+ 2,
+ -1,
+ 0,
+)
+# 1530 AD
+tValletta = (
+ [((57, 14), "Valletta", 100)],
+ Civ.INDEPENDENT_4,
+ 1,
+ Unit.KNIGHT_OF_ST_JOHNS,
+ 3,
+ Religion.CATHOLICISM,
+ 0,
+)
+
+dIndependentCities = {
+ DateTurn.i500AD: [
+ tTangier,
+ tBordeaux,
+ tAlger,
+ tBarcelona,
+ tToulouse,
+ tMarseilles,
+ tNantes,
+ tCaen,
+ tLyon,
+ tTunis,
+ tYork,
+ tLondon,
+ tMilan,
+ tFlorence,
+ tTripoli,
+ tAugsburg,
+ tNapoli,
+ tRagusa,
+ tSeville,
+ tPalermo,
+ ],
+ DateTurn.i552AD: [tInverness],
+ DateTurn.i600AD: [tRhodes],
+ DateTurn.i640AD: [tNorwich],
+ DateTurn.i670AD: [tKairouan],
+ DateTurn.i680AD: [tToledo, tLeicester],
+ DateTurn.i700AD: [tValencia, tPamplona, tLubeck, tPorto, tDublin, tDownpatrick],
+ DateTurn.i760AD: [tTonsberg],
+ DateTurn.i768AD: [tRaska],
+ DateTurn.i780AD: [tFez],
+ DateTurn.i800AD: [tMilanR, tPrague, tKursk, tCalais, tNidaros, tUppsala, tBeloozero, tZagreb],
+ DateTurn.i850AD: [tBrennabor],
+ DateTurn.i880AD: [tApulum],
+ DateTurn.i900AD: [tTvanksta, tKrakow, tRiga, tWales, tVisby],
+ DateTurn.i911AD: [tCaenR],
+ DateTurn.i960AD: [tMinsk, tSmolensk],
+ DateTurn.i988AD: [tDublinR],
+ DateTurn.i1010AD: [tYaroslavl],
+ DateTurn.i1050AD: [tGroningen, tKalmar],
+ DateTurn.i1110AD: [tGraz],
+ DateTurn.i1124AD: [tHalych],
+ DateTurn.i1200AD: [tRigaR],
+ DateTurn.i1227AD: [tTripoliR],
+ DateTurn.i1250AD: [tAbo, tPerekop],
+ DateTurn.i1320AD: [tNizhnyNovgorod],
+ DateTurn.i1393AD: [tTanais],
+ DateTurn.i1410AD: [tReykjavik],
+ DateTurn.i1530AD: [tValletta],
+}
+
+
+# Minor Nations structure: [ int Province: all cities in this province will revolt
+# list nations: a city controlled by those players will not revolt (i.e. Greece wouldn't revolt against the Byz)
+# list religions: a city owned by someone with one of those state religions will not revolt (i.e. Jerusalem doesn't revolt against Muslims)
+# list revolt dates: the dates for the revolt,
+# list revolt strength: this is subtracted from the odds to suppress the revolt (i.e. high number more likely to succeed in the revolt)
+# list units: corresponding to the revolt, if we crack down on the rebels, what barbarian units should spawn
+# list number: corresponding to the revolt, if we crack down on the rebels, how many units should spawn (note if we don't bribe the Lords, then double the number of Units will spawn)
+# list text keys: text keys for "The Nation" and "Nation Adjective"
+# Note: lists 3, 4, 5, 6 should have the same size
+# Note: you should increase the size of 'lNextMinorRevolt' in StoredData to be at least the number of minor nations
+lMinorNations = [
+ [
+ Province.SERBIA,
+ [],
+ [],
+ [DateTurn.i508AD, DateTurn.i852AD, DateTurn.i1346AD],
+ [20, 20, 20],
+ [Unit.AXEMAN, Unit.AXEMAN, Unit.LONG_SWORDSMAN],
+ [2, 1, 2],
+ ["TXT_KEY_THE_SERBS", "TXT_KEY_SERBIAN"],
+ ],
+ [
+ Province.SCOTLAND,
+ [Civ.SCOTLAND],
+ [],
+ [DateTurn.i1297AD, DateTurn.i1569AD, DateTurn.i1715AD],
+ [20, 10, 20],
+ [Unit.HIGHLANDER, Unit.MUSKETMAN, Unit.GRENADIER],
+ [2, 2, 2],
+ ["TXT_KEY_THE_SCOTS", "TXT_KEY_SCOTTISH"],
+ ],
+ [
+ Province.CATALONIA,
+ [Civ.ARAGON],
+ [],
+ [DateTurn.i1164AD + 10, DateTurn.i1640AD],
+ [20, 10],
+ [Unit.LONG_SWORDSMAN, Unit.MUSKETMAN],
+ [2, 2],
+ ["TXT_KEY_THE_CATALANS", "TXT_KEY_CATALAN"],
+ ],
+ [
+ Province.JERUSALEM,
+ [Civ.ARABIA, Civ.OTTOMAN, Civ.BYZANTIUM],
+ [Religion.ISLAM],
+ [
+ DateTurn.i1099AD + 8,
+ DateTurn.i1099AD + 16,
+ DateTurn.i1099AD + 25,
+ DateTurn.i1099AD + 33,
+ DateTurn.i1099AD + 40,
+ DateTurn.i1099AD + 47,
+ DateTurn.i1099AD + 55,
+ DateTurn.i1099AD + 65,
+ ],
+ [30, 30, 40, 40, 30, 30, 30, 30],
+ [
+ Unit.MACEMAN,
+ Unit.MACEMAN,
+ Unit.MACEMAN,
+ Unit.KNIGHT,
+ Unit.KNIGHT,
+ Unit.KNIGHT,
+ Unit.KNIGHT,
+ Unit.KNIGHT,
+ ],
+ [3, 3, 4, 3, 3, 3, 3, 3],
+ ["TXT_KEY_THE_MUSLIMS", "TXT_KEY_MUSLIM"],
+ ],
+ [
+ Province.SYRIA,
+ [Civ.ARABIA, Civ.OTTOMAN, Civ.BYZANTIUM],
+ [Religion.ISLAM],
+ [
+ DateTurn.i1099AD + 8,
+ DateTurn.i1099AD + 16,
+ DateTurn.i1099AD + 25,
+ DateTurn.i1099AD + 33,
+ DateTurn.i1099AD + 40,
+ DateTurn.i1099AD + 47,
+ DateTurn.i1099AD + 55,
+ DateTurn.i1099AD + 65,
+ ],
+ [30, 30, 40, 40, 30, 30, 30, 30],
+ [
+ Unit.MACEMAN,
+ Unit.MACEMAN,
+ Unit.MACEMAN,
+ Unit.KNIGHT,
+ Unit.KNIGHT,
+ Unit.KNIGHT,
+ Unit.KNIGHT,
+ Unit.KNIGHT,
+ ],
+ [3, 3, 4, 3, 3, 3, 3, 3],
+ ["TXT_KEY_THE_MUSLIMS", "TXT_KEY_MUSLIM"],
+ ],
+ [
+ Province.ORAN,
+ [],
+ [],
+ [DateTurn.i1236AD, DateTurn.i1346AD, DateTurn.i1359AD, DateTurn.i1542AD],
+ [40, 10, 10, 20],
+ [
+ Unit.KNIGHT,
+ Unit.HEAVY_LANCER,
+ Unit.HEAVY_LANCER,
+ Unit.MUSKETMAN,
+ ],
+ [2, 2, 2, 2],
+ ["TXT_KEY_THE_ZIYYANIDS", "TXT_KEY_ZIYYANID"],
+ ],
+ [
+ Province.FEZ,
+ [Civ.MOROCCO],
+ [],
+ [DateTurn.i1473AD],
+ [30],
+ [Unit.ARQUEBUSIER],
+ [4],
+ ["TXT_KEY_THE_WATTASIDS", "TXT_KEY_WATTASID"],
+ ],
+]
+# 3Miro: Jerusalem and Syria were added here, so the Crusaders will not be able to control it for too long
+
+
+def getRevolDates():
+ return data.lNextMinorRevolt
+
+
+def setRevolDates(lNextMinorRevolt):
+ data.lNextMinorRevolt = lNextMinorRevolt
+
+
+def getTempFlippingCity():
+ return data.iTempFlippingCity
+
+
+def setTempFlippingCity(tNewValue):
+ data.iTempFlippingCity = tNewValue
+
+
+def getNationRevoltIndex():
+ return data.lRevoltinNationRevoltIndex
+
+
+def setNationRevoltIndex(iNationIndex, iRevoltIndex):
+ data.lRevoltinNationRevoltIndex = [iNationIndex, iRevoltIndex]
+
+
+@handler("BeginGameTurn")
+def checkTurn(iGameTurn):
+ # Handicap level modifier
+ iHandicap = gc.getGame().getHandicapType() - 1
+ # gc.getGame().getHandicapType: Viceroy=0, Monarch=1, Emperor=2
+ # iHandicap: Viceroy=-1, Monarch=0, Emperor=1
+
+ # The Human player usually gets some additional barbarians
+ iHuman = human()
+
+ # Mediterranean Pirates (Light before 1500, then heavy for rest of game)
+ if DateTurn.i960AD <= iGameTurn < DateTurn.i1401AD:
+ spawnPirate(
+ Civ.BARBARIAN,
+ (9, 15),
+ (55, 33),
+ Unit.WAR_GALLEY,
+ 2,
+ 0,
+ 0,
+ iGameTurn,
+ 10,
+ 3,
+ outerSeaSpawn,
+ )
+ elif iGameTurn >= DateTurn.i1401AD:
+ spawnPirate(
+ Civ.BARBARIAN,
+ (9, 15),
+ (55, 33),
+ Unit.CORSAIR,
+ 2,
+ 0,
+ 0,
+ iGameTurn,
+ 10,
+ 3,
+ outerSeaSpawn,
+ text("TXT_KEY_BARBARIAN_NAMES_BARBARY_PIRATES"),
+ )
+ # extra Corsairs around Tunisia
+ spawnPirate(
+ Civ.BARBARIAN,
+ (42, 15),
+ (54, 23),
+ Unit.CORSAIR,
+ 1,
+ 0,
+ 0,
+ iGameTurn,
+ 5,
+ 0,
+ outerSeaSpawn,
+ text("TXT_KEY_BARBARIAN_NAMES_BARBARY_PIRATES"),
+ )
+ if DateTurn.i1200AD <= iGameTurn < DateTurn.i1500AD:
+ spawnPirate(
+ Civ.BARBARIAN,
+ (9, 15),
+ (55, 33),
+ Unit.COGGE,
+ 1,
+ Unit.SWORDSMAN,
+ 2,
+ iGameTurn,
+ 10,
+ 5,
+ outerSeaSpawn,
+ )
+ elif iGameTurn >= DateTurn.i1500AD:
+ spawnPirate(
+ Civ.BARBARIAN,
+ (9, 15),
+ (55, 33),
+ Unit.GALLEON,
+ 1,
+ Unit.MUSKETMAN,
+ 2,
+ iGameTurn,
+ 10,
+ 5,
+ outerSeaSpawn,
+ )
+
+ # Germanic Barbarians throughout Western Europe (France, Germany)
+ if iGameTurn < DateTurn.i600AD:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (43, 42),
+ (50, 50),
+ Unit.AXEMAN,
+ 1,
+ iGameTurn,
+ 11,
+ 1,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_GERMANIC_TRIBES"),
+ )
+ if Civ.FRANCE == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (42, 40),
+ (56, 48),
+ Unit.AXEMAN,
+ 1,
+ iGameTurn,
+ 9,
+ 3,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_GERMANIC_TRIBES"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (45, 45),
+ (60, 55),
+ Unit.SPEARMAN,
+ 1,
+ iGameTurn,
+ 18,
+ 7,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_GERMANIC_TRIBES"),
+ )
+ elif DateTurn.i600AD <= iGameTurn < DateTurn.i800AD:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (43, 42),
+ (50, 50),
+ Unit.AXEMAN,
+ 1,
+ iGameTurn,
+ 9,
+ 2,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_GERMANIC_TRIBES"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (42, 40),
+ (56, 48),
+ Unit.AXEMAN,
+ 1,
+ iGameTurn,
+ 11,
+ 4,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_GERMANIC_TRIBES"),
+ )
+ if Civ.FRANCE == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (43, 42),
+ (50, 50),
+ Unit.AXEMAN,
+ 1,
+ iGameTurn,
+ 9,
+ 3,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_GERMANIC_TRIBES"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (45, 45),
+ (60, 55),
+ Unit.SPEARMAN,
+ 1 + iHandicap,
+ iGameTurn,
+ 11,
+ 4,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_GERMANIC_TRIBES"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (46, 48),
+ (62, 55),
+ Unit.AXEMAN,
+ 1 + iHandicap,
+ iGameTurn,
+ 14,
+ 9,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_GERMANIC_TRIBES"),
+ )
+
+ # Longobards in Italy
+ if DateTurn.i632AD <= iGameTurn <= DateTurn.i800AD:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (49, 33),
+ (53, 36),
+ Unit.AXEMAN,
+ 1 + iHandicap,
+ iGameTurn,
+ 10,
+ 3,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_LONGOBARDS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (49, 33),
+ (53, 36),
+ Unit.SPEARMAN,
+ 1,
+ iGameTurn,
+ 12,
+ 0,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_LONGOBARDS"),
+ )
+
+ # Visigoths in Iberia
+ if DateTurn.i712AD <= iGameTurn <= DateTurn.i892AD:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (22, 21),
+ (26, 25),
+ Unit.AXEMAN,
+ 1,
+ iGameTurn,
+ 7,
+ 0,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_VISIGOTHS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (23, 23),
+ (27, 28),
+ Unit.SPEARMAN,
+ 1,
+ iGameTurn,
+ 7,
+ 3,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_VISIGOTHS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (26, 27),
+ (31, 32),
+ Unit.MOUNTED_INFANTRY,
+ 1,
+ iGameTurn,
+ 9,
+ 5,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_VISIGOTHS"),
+ )
+ if Civ.CORDOBA == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (24, 31),
+ (27, 34),
+ Unit.AXEMAN,
+ 1 + iHandicap,
+ iGameTurn,
+ 7,
+ 0,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_VISIGOTHS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (27, 28),
+ (31, 36),
+ Unit.MOUNTED_INFANTRY,
+ 1,
+ iGameTurn,
+ 6,
+ 3,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_VISIGOTHS"),
+ )
+
+ # Berbers in North Africa
+ if DateTurn.i700AD <= iGameTurn < DateTurn.i1020AD:
+ # Tunesia
+ spawnUnits(
+ Civ.BARBARIAN,
+ (28, 10),
+ (35, 14),
+ Unit.HORSE_ARCHER,
+ 1 + iHandicap,
+ iGameTurn,
+ 8,
+ 0,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_BERBERS"),
+ )
+ # Morocco
+ if Civ.CORDOBA == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (21, 3),
+ (27, 12),
+ Unit.HORSE_ARCHER,
+ 1,
+ iGameTurn,
+ 9,
+ 0,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_BERBERS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (22, 3),
+ (27, 10),
+ Unit.AXEMAN,
+ 1,
+ iGameTurn,
+ 11,
+ 5,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_BERBERS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (23, 3),
+ (27, 8),
+ Unit.SPEARMAN,
+ 1,
+ iGameTurn,
+ 7,
+ 3,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_BERBERS"),
+ )
+ else:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (22, 3),
+ (27, 10),
+ Unit.AXEMAN,
+ 1,
+ iGameTurn,
+ 14,
+ 5,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_BERBERS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (23, 3),
+ (27, 8),
+ Unit.SPEARMAN,
+ 1,
+ iGameTurn,
+ 8,
+ 3,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_BERBERS"),
+ )
+
+ # Avars in the Carpathian Basin
+ if DateTurn.i632AD <= iGameTurn < DateTurn.i800AD:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (60, 30),
+ (75, 40),
+ Unit.HORSE_ARCHER,
+ 1,
+ iGameTurn,
+ 5,
+ 0,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_AVARS"),
+ )
+ if Civ.BULGARIA == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (66, 26),
+ (73, 29),
+ Unit.HORSE_ARCHER,
+ 1 + iHandicap,
+ iGameTurn,
+ 6,
+ 1,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_AVARS"),
+ )
+
+ # Early barbs for Byzantium:
+ if iGameTurn < DateTurn.i640AD:
+ # Pre-Bulgarian Slavs in the Balkans
+ spawnUnits(
+ Civ.BARBARIAN,
+ (68, 18),
+ (78, 28),
+ Unit.AXEMAN,
+ 1,
+ iGameTurn,
+ 8,
+ 0,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SOUTHERN_SLAVS"),
+ )
+ if Civ.BYZANTIUM == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (64, 21),
+ (75, 25),
+ Unit.AXEMAN,
+ 1 + iHandicap,
+ iGameTurn,
+ 11,
+ 3,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SOUTHERN_SLAVS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (68, 18),
+ (78, 28),
+ Unit.SPEARMAN,
+ 1,
+ iGameTurn,
+ 8,
+ 0,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SOUTHERN_SLAVS"),
+ )
+ # Sassanids in Anatolia
+ spawnUnits(
+ Civ.BARBARIAN,
+ (90, 15),
+ (99, 28),
+ Unit.LANCER,
+ 1,
+ iGameTurn,
+ 6,
+ 2,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SASSANIDS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (94, 19),
+ (98, 26),
+ Unit.LANCER,
+ 1,
+ iGameTurn,
+ 9,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SASSANIDS"),
+ )
+ if Civ.BYZANTIUM == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (90, 15),
+ (99, 28),
+ Unit.LANCER,
+ 1,
+ iGameTurn,
+ 6,
+ 2,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SASSANIDS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (94, 19),
+ (98, 26),
+ Unit.LANCER,
+ 1 + iHandicap,
+ iGameTurn,
+ 9,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SASSANIDS"),
+ )
+ # Barbs in NW Greece
+ if iGameTurn < DateTurn.i720AD:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (66, 21),
+ (69, 28),
+ Unit.AXEMAN,
+ 1,
+ iGameTurn,
+ 9,
+ 3,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ )
+ if Civ.BYZANTIUM == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (66, 21),
+ (69, 28),
+ Unit.SPEARMAN,
+ 1 + iHandicap,
+ iGameTurn,
+ 9,
+ 3,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ )
+
+ # Serbs in the Southern Balkans
+ if DateTurn.i1025AD <= iGameTurn < DateTurn.i1282AD:
+ if Civ.BYZANTIUM == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (67, 24),
+ (73, 28),
+ Unit.AXEMAN,
+ 1,
+ iGameTurn,
+ 9,
+ 3,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SERBS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (67, 24),
+ (73, 28),
+ Unit.LANCER,
+ 1 + iHandicap,
+ iGameTurn,
+ 11,
+ 7,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SERBS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (69, 25),
+ (71, 29),
+ Unit.SWORDSMAN,
+ 1,
+ iGameTurn,
+ 7,
+ 4,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SERBS"),
+ )
+ else:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (67, 24),
+ (73, 28),
+ Unit.AXEMAN,
+ 1,
+ iGameTurn,
+ 9,
+ 3,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SERBS"),
+ )
+
+ # Khazars
+ if DateTurn.i660AD <= iGameTurn < DateTurn.i864AD:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (88, 31),
+ (99, 40),
+ Unit.AXEMAN,
+ 1,
+ iGameTurn,
+ 8,
+ 0,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_KHAZARS"),
+ )
+ elif DateTurn.i864AD <= iGameTurn < DateTurn.i920AD:
+ if Civ.KIEV == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (88, 31),
+ (99, 40),
+ Unit.AXEMAN,
+ 1,
+ iGameTurn,
+ 7,
+ 2,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_KHAZARS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (88, 31),
+ (99, 40),
+ Unit.SPEARMAN,
+ 1,
+ iGameTurn,
+ 5,
+ 2,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_KHAZARS"),
+ )
+ else:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (88, 31),
+ (99, 40),
+ Unit.AXEMAN,
+ 1,
+ iGameTurn,
+ 11,
+ 2,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_KHAZARS"),
+ )
+
+ # Pechenegs
+ if DateTurn.i920AD <= iGameTurn < DateTurn.i1040AD:
+ # in the Rus
+ spawnUnits(
+ Civ.BARBARIAN,
+ (89, 34),
+ (97, 40),
+ Unit.STEPPE_HORSE_ARCHER,
+ 1,
+ iGameTurn,
+ 8,
+ 3,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_PECHENEGS"),
+ )
+ if Civ.KIEV == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (91, 35),
+ (99, 44),
+ Unit.STEPPE_HORSE_ARCHER,
+ 1 + iHandicap,
+ iGameTurn,
+ 5,
+ 1,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_PECHENEGS"),
+ )
+ # in Hungary
+ spawnUnits(
+ Civ.BARBARIAN,
+ (66, 35),
+ (75, 42),
+ Unit.STEPPE_HORSE_ARCHER,
+ 1,
+ iGameTurn,
+ 9,
+ 1,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_PECHENEGS"),
+ )
+ if Civ.HUNGARY == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (66, 35),
+ (75, 42),
+ Unit.STEPPE_HORSE_ARCHER,
+ 1 + iHandicap,
+ iGameTurn,
+ 9,
+ 1,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_PECHENEGS"),
+ )
+ # in Bulgaria
+ elif Civ.BULGARIA == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (77, 31),
+ (79, 33),
+ Unit.STEPPE_HORSE_ARCHER,
+ 2 + iHandicap,
+ iGameTurn,
+ 5,
+ 1,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_PECHENEGS"),
+ )
+
+ # Cumans and Kipchaks
+ elif DateTurn.i1040AD <= iGameTurn < DateTurn.i1200AD:
+ # in the Rus
+ if Civ.KIEV == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (89, 34),
+ (99, 40),
+ Unit.STEPPE_HORSE_ARCHER,
+ 2,
+ iGameTurn,
+ 7,
+ 5,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_CUMANS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (90, 33),
+ (97, 44),
+ Unit.STEPPE_HORSE_ARCHER,
+ 2 + iHandicap,
+ iGameTurn,
+ 9,
+ 1,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_KIPCHAKS"),
+ )
+ else:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (89, 34),
+ (99, 40),
+ Unit.STEPPE_HORSE_ARCHER,
+ 1,
+ iGameTurn,
+ 7,
+ 5,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_CUMANS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (90, 33),
+ (97, 44),
+ Unit.STEPPE_HORSE_ARCHER,
+ 1,
+ iGameTurn,
+ 9,
+ 1,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_KIPCHAKS"),
+ )
+ # in Hungary
+ spawnUnits(
+ Civ.BARBARIAN,
+ (64, 33),
+ (77, 43),
+ Unit.STEPPE_HORSE_ARCHER,
+ 1,
+ iGameTurn,
+ 7,
+ 1,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_CUMANS"),
+ )
+ if Civ.HUNGARY == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (64, 33),
+ (77, 43),
+ Unit.STEPPE_HORSE_ARCHER,
+ 1,
+ iGameTurn,
+ 7,
+ 1,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_CUMANS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (66, 35),
+ (75, 42),
+ Unit.STEPPE_HORSE_ARCHER,
+ 1,
+ iGameTurn,
+ 9,
+ 4,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_KIPCHAKS"),
+ )
+ # in Bulgaria
+ if Civ.BULGARIA == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (78, 32),
+ (80, 34),
+ Unit.STEPPE_HORSE_ARCHER,
+ 1,
+ iGameTurn,
+ 7,
+ 3,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_CUMANS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (78, 32),
+ (80, 34),
+ Unit.STEPPE_HORSE_ARCHER,
+ 1,
+ iGameTurn,
+ 7,
+ 3,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_KIPCHAKS"),
+ )
+
+ # Vikings on ships
+ if Civ.NORWAY == iHuman: # Humans can properly go viking without help
+ pass
+ elif DateTurn.i780AD <= iGameTurn < DateTurn.i1000AD:
+ if Civ.FRANCE == iHuman:
+ spawnVikings(
+ Civ.BARBARIAN,
+ (37, 48),
+ (50, 54),
+ Unit.VIKING_BERSERKER,
+ 2,
+ iGameTurn,
+ 8,
+ 0,
+ outerSeaSpawn,
+ text("TXT_KEY_BARBARIAN_NAMES_VIKINGS"),
+ )
+ else:
+ spawnVikings(
+ Civ.BARBARIAN,
+ (37, 48),
+ (50, 54),
+ Unit.VIKING_BERSERKER,
+ 1,
+ iGameTurn,
+ 8,
+ 0,
+ outerSeaSpawn,
+ text("TXT_KEY_BARBARIAN_NAMES_VIKINGS"),
+ )
+
+ # Swedish Crusades
+ elif DateTurn.i1150AD <= iGameTurn < DateTurn.i1210AD:
+ spawnVikings(
+ Civ.BARBARIAN,
+ (71, 62),
+ (76, 65),
+ Unit.VIKING_BERSERKER,
+ 2,
+ iGameTurn,
+ 6,
+ 1,
+ outerSeaSpawn,
+ text("TXT_KEY_BARBARIAN_NAMES_SWEDES"),
+ )
+
+ # Chudes in Finland and Estonia
+ if DateTurn.i864AD <= iGameTurn < DateTurn.i1150AD:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (72, 67),
+ (81, 72),
+ Unit.AXEMAN,
+ 1,
+ iGameTurn,
+ 7,
+ 0,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_CHUDES"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (74, 60),
+ (76, 63),
+ Unit.AXEMAN,
+ 1,
+ iGameTurn,
+ 11,
+ 3,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_CHUDES"),
+ )
+
+ # Livonian Order as barbs in the area before the Prussian spawn, but only if Prussia is AI (no need for potentially gained extra units for the human player)
+ # Also pre-Lithanian barbs for human Prussia a couple turns before the Lithuanian spawn
+ if Civ.PRUSSIA == iHuman:
+ if DateTurn.i1224AD <= iGameTurn < DateTurn.i1236AD:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (73, 56),
+ (76, 61),
+ Unit.AXEMAN,
+ 1,
+ iGameTurn,
+ 2,
+ 1,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_BALTICS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (72, 54),
+ (75, 59),
+ Unit.AXEMAN,
+ 1,
+ iGameTurn,
+ 2,
+ 1,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_BALTICS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (73, 56),
+ (76, 61),
+ Unit.HORSE_ARCHER,
+ 1 + iHandicap,
+ iGameTurn,
+ 2,
+ 1,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_BALTICS"),
+ )
+ elif DateTurn.i1200AD <= iGameTurn < DateTurn.i1224AD:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (73, 57),
+ (76, 61),
+ Unit.TEUTONIC,
+ 1,
+ iGameTurn,
+ 4,
+ 3,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SWORD_BRETHEN"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (73, 57),
+ (76, 61),
+ Unit.SWORDSMAN,
+ 1,
+ iGameTurn,
+ 4,
+ 1,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SWORD_BRETHEN"),
+ )
+
+ # Couple melee barb units in Ireland:
+ if DateTurn.i800AD <= iGameTurn < DateTurn.i900AD:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (28, 56),
+ (33, 62),
+ Unit.AXEMAN,
+ 1,
+ iGameTurn,
+ 7,
+ 3,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_IRISH"),
+ )
+
+ # Anglo-Saxons before the Danish 1st UHV (Conquer England)
+ elif DateTurn.i970AD <= iGameTurn < DateTurn.i1050AD:
+ if Civ.DENMARK == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (36, 53),
+ (41, 59),
+ Unit.AXEMAN,
+ 1,
+ iGameTurn,
+ 8,
+ 5,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_ANGLO_SAXONS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (33, 48),
+ (38, 54),
+ Unit.AXEMAN,
+ 1,
+ iGameTurn,
+ 5,
+ 2,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_ANGLO_SAXONS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (33, 48),
+ (38, 54),
+ Unit.SWORDSMAN,
+ 1,
+ iGameTurn,
+ 11,
+ 6,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_ANGLO_SAXONS"),
+ )
+ else:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (33, 48),
+ (38, 54),
+ Unit.AXEMAN,
+ 1,
+ iGameTurn,
+ 5,
+ 2,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_ANGLO_SAXONS"),
+ )
+
+ # Scots to keep England busy, but only if Scotland is dead
+ if not gc.getPlayer(Civ.SCOTLAND).isAlive():
+ if DateTurn.i1060AD <= iGameTurn < DateTurn.i1320AD:
+ if Civ.ENGLAND == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (39, 62),
+ (44, 66),
+ Unit.HIGHLANDER,
+ 2,
+ iGameTurn,
+ 11,
+ 0,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SCOTS"),
+ )
+ else:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (39, 62),
+ (44, 66),
+ Unit.HIGHLANDER,
+ 1,
+ iGameTurn,
+ 11,
+ 0,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SCOTS"),
+ )
+ elif DateTurn.i1320AD <= iGameTurn < DateTurn.i1500AD:
+ if Civ.ENGLAND == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (39, 62),
+ (44, 66),
+ Unit.HIGHLANDER,
+ 2,
+ iGameTurn,
+ 9,
+ 0,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SCOTS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (39, 64),
+ (44, 67),
+ Unit.HIGHLANDER,
+ 2 + iHandicap,
+ iGameTurn,
+ 17,
+ 4,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SCOTS"),
+ )
+ else:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (39, 64),
+ (44, 67),
+ Unit.HIGHLANDER,
+ 2,
+ iGameTurn,
+ 17,
+ 4,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SCOTS"),
+ )
+
+ # Welsh in Britain
+ if DateTurn.i1060AD <= iGameTurn < DateTurn.i1160AD:
+ if Civ.ENGLAND == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (37, 53),
+ (39, 57),
+ Unit.WELSH_LONGBOWMAN,
+ 1,
+ iGameTurn,
+ 7,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_WELSH"),
+ )
+ else:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (37, 53),
+ (39, 57),
+ Unit.WELSH_LONGBOWMAN,
+ 1,
+ iGameTurn,
+ 13,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_WELSH"),
+ )
+ elif DateTurn.i1160AD <= iGameTurn < DateTurn.i1452AD:
+ if Civ.ENGLAND == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (37, 53),
+ (39, 57),
+ Unit.WELSH_LONGBOWMAN,
+ 2 + iHandicap,
+ iGameTurn,
+ 12,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_WELSH"),
+ )
+ else:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (37, 53),
+ (39, 57),
+ Unit.WELSH_LONGBOWMAN,
+ 1,
+ iGameTurn,
+ 9,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_WELSH"),
+ )
+
+ # Magyars (preceeding Hungary)
+ if DateTurn.i840AD <= iGameTurn < DateTurn.i892AD:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (54, 38),
+ (61, 45),
+ Unit.HORSE_ARCHER,
+ 1,
+ iGameTurn,
+ 4,
+ 1,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_MAGYARS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (66, 26),
+ (73, 29),
+ Unit.HORSE_ARCHER,
+ 1,
+ iGameTurn,
+ 4,
+ 2,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_MAGYARS"),
+ )
+ if Civ.BULGARIA == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (77, 31),
+ (80, 34),
+ Unit.HORSE_ARCHER,
+ 2 + iHandicap,
+ iGameTurn,
+ 5,
+ 0,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_MAGYARS"),
+ )
+ elif Civ.GERMANY == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (54, 38),
+ (61, 45),
+ Unit.HORSE_ARCHER,
+ 2 + iHandicap,
+ iGameTurn,
+ 5,
+ 3,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_MAGYARS"),
+ )
+
+ # Wends in NE Germany
+ if DateTurn.i860AD <= iGameTurn < DateTurn.i1053AD:
+ if Civ.GERMANY == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (55, 49),
+ (60, 56),
+ Unit.AXEMAN,
+ 1,
+ iGameTurn,
+ 6,
+ 1,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_WENDS"),
+ )
+ else:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (55, 49),
+ (60, 56),
+ Unit.AXEMAN,
+ 1,
+ iGameTurn,
+ 8,
+ 1,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_WENDS"),
+ )
+
+ # Great Slav Rising in 983AD
+ if (DateTurn.i983AD - 1) <= iGameTurn < (DateTurn.i983AD + 1):
+ if Civ.GERMANY == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (53, 48),
+ (59, 55),
+ Unit.AXEMAN,
+ 2,
+ iGameTurn,
+ 2,
+ 0,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_WENDS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (53, 48),
+ (59, 55),
+ Unit.SPEARMAN,
+ 1,
+ iGameTurn,
+ 2,
+ 0,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_WENDS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (53, 48),
+ (59, 55),
+ Unit.SWORDSMAN,
+ 1,
+ iGameTurn,
+ 2,
+ 0,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_WENDS"),
+ )
+ else:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (53, 48),
+ (59, 55),
+ Unit.AXEMAN,
+ 1,
+ iGameTurn,
+ 2,
+ 0,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_WENDS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (53, 48),
+ (59, 55),
+ Unit.SPEARMAN,
+ 1,
+ iGameTurn,
+ 2,
+ 0,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_WENDS"),
+ )
+
+ # Barbs in the middle east
+ if DateTurn.i700AD <= iGameTurn <= DateTurn.i1300AD:
+ if not gc.getTeam(gc.getPlayer(Civ.ARABIA).getTeam()).isHasTech(Technology.FARRIERS):
+ spawnUnits(
+ Civ.BARBARIAN,
+ (94, 0),
+ (99, 3),
+ Unit.HORSE_ARCHER,
+ 1,
+ iGameTurn,
+ 11,
+ 3,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_BEDUINS"),
+ )
+ if gc.getPlayer(Civ.ARABIA).isHuman():
+ spawnUnits(
+ Civ.BARBARIAN,
+ (94, 0),
+ (99, 3),
+ Unit.HORSE_ARCHER,
+ 1 + iHandicap,
+ iGameTurn,
+ 11,
+ 3,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_BEDUINS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (92, 1),
+ (98, 4),
+ Unit.HORSE_ARCHER,
+ 1,
+ iGameTurn,
+ 8,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_BEDUINS"),
+ )
+ else:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (94, 0),
+ (99, 3),
+ Unit.BEDOUIN,
+ 1,
+ iGameTurn,
+ 10,
+ 2,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_BEDUINS"),
+ )
+ if gc.getPlayer(Civ.ARABIA).isHuman():
+ spawnUnits(
+ Civ.BARBARIAN,
+ (94, 0),
+ (99, 3),
+ Unit.BEDOUIN,
+ 1 + iHandicap,
+ iGameTurn,
+ 10,
+ 2,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_BEDUINS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (95, 1),
+ (98, 5),
+ Unit.BEDOUIN,
+ 1,
+ iGameTurn,
+ 7,
+ 3,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_BEDUINS"),
+ )
+
+ # Banu Hilal and Bani Hassan, in Morocco and Tunesia
+ if DateTurn.i1040AD <= iGameTurn < DateTurn.i1229AD:
+ if Civ.MOROCCO == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (40, 10),
+ (44, 14),
+ Unit.BEDOUIN,
+ 2 + iHandicap,
+ iGameTurn,
+ 11,
+ 2,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_BANU_HILAL"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (44, 1),
+ (50, 8),
+ Unit.TOUAREG,
+ 2 + iHandicap,
+ iGameTurn,
+ 8,
+ 5,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_BANU_HILAL"),
+ )
+ else:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (40, 10),
+ (44, 14),
+ Unit.BEDOUIN,
+ 1,
+ iGameTurn,
+ 11,
+ 2,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_BANU_HILAL"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (44, 1),
+ (50, 8),
+ Unit.TOUAREG,
+ 1,
+ iGameTurn,
+ 8,
+ 5,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_BANU_HILAL"),
+ )
+ if DateTurn.i1640AD <= iGameTurn < DateTurn.i1680AD:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (18, 1),
+ (22, 3),
+ Unit.BEDOUIN,
+ 5 + iHandicap * 2,
+ iGameTurn,
+ 3,
+ 1,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_BANI_HASSAN"),
+ )
+
+ # Pre Mongols to keep Kiev busy
+ if DateTurn.i900AD <= iGameTurn < DateTurn.i1020AD:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (93, 35),
+ (99, 44),
+ Unit.HORSE_ARCHER,
+ 1,
+ iGameTurn,
+ 13,
+ 1,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ )
+ elif DateTurn.i1020AD <= iGameTurn < DateTurn.i1236AD:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (93, 35),
+ (99, 44),
+ Unit.HORSE_ARCHER,
+ 1,
+ iGameTurn,
+ 9,
+ 5,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ )
+ if Civ.KIEV == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (94, 32),
+ (97, 39),
+ Unit.HORSE_ARCHER,
+ 2 + iHandicap,
+ iGameTurn,
+ 10,
+ 1,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ )
+
+ # Barbs in Anatolia pre Seljuks (but after Sassanids)
+ if DateTurn.i700AD <= iGameTurn < DateTurn.i1050AD:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (97, 20),
+ (99, 26),
+ Unit.HORSE_ARCHER,
+ 1,
+ iGameTurn,
+ 10,
+ 1,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (95, 20),
+ (99, 24),
+ Unit.AXEMAN,
+ 1,
+ iGameTurn,
+ 14,
+ 2,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (95, 22),
+ (97, 26),
+ Unit.SPEARMAN,
+ 1,
+ iGameTurn,
+ 16,
+ 6,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ )
+ if Civ.BYZANTIUM == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (97, 20),
+ (99, 26),
+ Unit.HORSE_ARCHER,
+ 1 + iHandicap,
+ iGameTurn,
+ 10,
+ 1,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (95, 20),
+ (99, 24),
+ Unit.AXEMAN,
+ 1,
+ iGameTurn,
+ 14,
+ 2,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (95, 20),
+ (99, 24),
+ Unit.HORSE_ARCHER,
+ 1 + iHandicap,
+ iGameTurn,
+ 14,
+ 2,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (95, 22),
+ (97, 26),
+ Unit.SPEARMAN,
+ 1,
+ iGameTurn,
+ 16,
+ 6,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (95, 22),
+ (97, 26),
+ Unit.HORSE_ARCHER,
+ 1 + iHandicap,
+ iGameTurn,
+ 16,
+ 6,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ )
+
+ # Seljuks
+ if DateTurn.i1064AD <= iGameTurn < DateTurn.i1094AD:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (90, 21),
+ (99, 28),
+ Unit.SELJUK_LANCER,
+ 3,
+ iGameTurn,
+ 3,
+ 0,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (90, 21),
+ (99, 28),
+ Unit.TURCOMAN_HORSE_ARCHER,
+ 1,
+ iGameTurn,
+ 3,
+ 0,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (90, 21),
+ (99, 28),
+ Unit.SELJUK_CROSSBOW,
+ 1,
+ iGameTurn,
+ 3,
+ 0,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (90, 21),
+ (99, 28),
+ Unit.SELJUK_SWORDSMAN,
+ 1,
+ iGameTurn,
+ 3,
+ 0,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (92, 20),
+ (99, 25),
+ Unit.SELJUK_LANCER,
+ 3,
+ iGameTurn,
+ 3,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (92, 20),
+ (99, 25),
+ Unit.TURCOMAN_HORSE_ARCHER,
+ 1,
+ iGameTurn,
+ 3,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (92, 20),
+ (99, 25),
+ Unit.SELJUK_GUISARME,
+ 1,
+ iGameTurn,
+ 3,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (92, 20),
+ (99, 25),
+ Unit.SELJUK_FOOTMAN,
+ 1,
+ iGameTurn,
+ 3,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (95, 8),
+ (99, 12),
+ Unit.SELJUK_LANCER,
+ 2,
+ iGameTurn,
+ 4,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (95, 8),
+ (99, 12),
+ Unit.SELJUK_CROSSBOW,
+ 1,
+ iGameTurn,
+ 4,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
+ )
+ if Civ.BYZANTIUM == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (90, 21),
+ (99, 28),
+ Unit.SELJUK_LANCER,
+ 1,
+ iGameTurn,
+ 3,
+ 0,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (90, 21),
+ (99, 28),
+ Unit.TURCOMAN_HORSE_ARCHER,
+ 1,
+ iGameTurn,
+ 3,
+ 0,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (90, 21),
+ (99, 28),
+ Unit.SELJUK_CROSSBOW,
+ 1 + iHandicap,
+ iGameTurn,
+ 3,
+ 0,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (90, 21),
+ (99, 28),
+ Unit.SELJUK_GUISARME,
+ 1,
+ iGameTurn,
+ 3,
+ 0,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (90, 21),
+ (99, 28),
+ Unit.SELJUK_FOOTMAN,
+ 1 + iHandicap,
+ iGameTurn,
+ 3,
+ 0,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (92, 20),
+ (99, 25),
+ Unit.SELJUK_LANCER,
+ 1,
+ iGameTurn,
+ 3,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (92, 20),
+ (99, 25),
+ Unit.TURCOMAN_HORSE_ARCHER,
+ 1,
+ iGameTurn,
+ 3,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (92, 20),
+ (99, 25),
+ Unit.SELJUK_GUISARME,
+ 1 + iHandicap,
+ iGameTurn,
+ 3,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (92, 20),
+ (99, 25),
+ Unit.SELJUK_CROSSBOW,
+ 1,
+ iGameTurn,
+ 3,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (92, 20),
+ (99, 25),
+ Unit.SELJUK_SWORDSMAN,
+ 1 + iHandicap,
+ iGameTurn,
+ 3,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
+ )
+ elif Civ.ARABIA == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (95, 8),
+ (99, 12),
+ Unit.SELJUK_LANCER,
+ 1 + iHandicap,
+ iGameTurn,
+ 4,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (95, 8),
+ (99, 12),
+ Unit.TURCOMAN_HORSE_ARCHER,
+ 1,
+ iGameTurn,
+ 4,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (95, 8),
+ (99, 12),
+ Unit.SELJUK_GUISARME,
+ 1,
+ iGameTurn,
+ 4,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
+ )
+
+ # Danishmends
+ if DateTurn.i1077AD <= iGameTurn < DateTurn.i1147AD:
+ if Civ.BYZANTIUM == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (93, 20),
+ (99, 22),
+ Unit.TURCOMAN_HORSE_ARCHER,
+ 3 + iHandicap,
+ iGameTurn,
+ 5,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_DANISHMENDS"),
+ )
+ else:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (93, 20),
+ (99, 22),
+ Unit.TURCOMAN_HORSE_ARCHER,
+ 2,
+ iGameTurn,
+ 5,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_DANISHMENDS"),
+ )
+
+ # Mongols
+ if DateTurn.i1236AD <= iGameTurn < DateTurn.i1288AD:
+ # Kiev
+ if Civ.KIEV == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (93, 32),
+ (99, 42),
+ Unit.MONGOL_KESHIK,
+ 5 + iHandicap,
+ iGameTurn,
+ 4,
+ 0,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (94, 34),
+ (99, 45),
+ Unit.MONGOL_KESHIK,
+ 4 + iHandicap,
+ iGameTurn,
+ 3,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
+ )
+ else:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (93, 32),
+ (99, 42),
+ Unit.MONGOL_KESHIK,
+ 3,
+ iGameTurn,
+ 4,
+ 0,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (94, 34),
+ (99, 45),
+ Unit.MONGOL_KESHIK,
+ 2,
+ iGameTurn,
+ 3,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
+ )
+ # Hungary
+ if Civ.HUNGARY == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (71, 38),
+ (75, 40),
+ Unit.MONGOL_KESHIK,
+ 4 + iHandicap,
+ iGameTurn,
+ 4,
+ 2,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (74, 35),
+ (77, 37),
+ Unit.MONGOL_KESHIK,
+ 2,
+ iGameTurn,
+ 4,
+ 2,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
+ )
+ else:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (71, 38),
+ (75, 40),
+ Unit.MONGOL_KESHIK,
+ 2,
+ iGameTurn,
+ 4,
+ 2,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (74, 35),
+ (77, 37),
+ Unit.MONGOL_KESHIK,
+ 1,
+ iGameTurn,
+ 4,
+ 2,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
+ )
+ # Poland
+ if Civ.POLAND == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (73, 43),
+ (78, 47),
+ Unit.MONGOL_KESHIK,
+ 5 + iHandicap,
+ iGameTurn,
+ 4,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
+ )
+ else:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (73, 43),
+ (78, 47),
+ Unit.MONGOL_KESHIK,
+ 2,
+ iGameTurn,
+ 4,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
+ )
+ # Bulgaria
+ if Civ.BULGARIA == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (79, 32),
+ (82, 35),
+ Unit.MONGOL_KESHIK,
+ 3 + iHandicap,
+ iGameTurn,
+ 4,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
+ )
+ else:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (79, 32),
+ (82, 35),
+ Unit.MONGOL_KESHIK,
+ 2,
+ iGameTurn,
+ 4,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
+ )
+ # Moscow area
+ spawnUnits(
+ Civ.BARBARIAN,
+ (89, 46),
+ (95, 54),
+ Unit.MONGOL_KESHIK,
+ 1,
+ iGameTurn,
+ 4,
+ 0,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (91, 48),
+ (97, 53),
+ Unit.MONGOL_KESHIK,
+ 2,
+ iGameTurn,
+ 6,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
+ )
+ # Middle East
+ spawnUnits(
+ Civ.BARBARIAN,
+ (94, 20),
+ (99, 26),
+ Unit.MONGOL_KESHIK,
+ 2,
+ iGameTurn,
+ 3,
+ 2,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (92, 21),
+ (97, 25),
+ Unit.MONGOL_KESHIK,
+ 2,
+ iGameTurn,
+ 6,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
+ )
+
+ # Timurids, Tamerlane's conquests (aka Mongols, the return!)
+ if (
+ DateTurn.i1380AD <= iGameTurn <= DateTurn.i1431AD
+ ): # Timur started his first western campaigns in 1380AD
+ # Eastern Europe
+ spawnUnits(
+ Civ.BARBARIAN,
+ (85, 47),
+ (99, 57),
+ Unit.MONGOL_KESHIK,
+ 2,
+ iGameTurn,
+ 7,
+ 0,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_TIMURIDS"),
+ )
+ # Anatolia
+ if Civ.OTTOMAN == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (87, 17),
+ (96, 24),
+ Unit.MONGOL_KESHIK,
+ 4 + iHandicap,
+ iGameTurn,
+ 4,
+ 0,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_TIMURIDS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (94, 18),
+ (99, 26),
+ Unit.MONGOL_KESHIK,
+ 6 + iHandicap,
+ iGameTurn,
+ 5,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_TIMURIDS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (89, 17),
+ (97, 22),
+ Unit.MONGOL_KESHIK,
+ 3 + iHandicap,
+ iGameTurn,
+ 4,
+ 2,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_TIMURIDS"),
+ )
+ else:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (87, 17),
+ (96, 24),
+ Unit.MONGOL_KESHIK,
+ 2,
+ iGameTurn,
+ 4,
+ 0,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_TIMURIDS"),
+ )
+ spawnUnits(
+ Civ.BARBARIAN,
+ (94, 18),
+ (99, 26),
+ Unit.MONGOL_KESHIK,
+ 3,
+ iGameTurn,
+ 5,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_TIMURIDS"),
+ )
+ # Arabia
+ if Civ.ARABIA == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (96, 9),
+ (99, 15),
+ Unit.MONGOL_KESHIK,
+ 5 + iHandicap,
+ iGameTurn,
+ 4,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_TIMURIDS"),
+ )
+ else:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (96, 9),
+ (99, 15),
+ Unit.MONGOL_KESHIK,
+ 2,
+ iGameTurn,
+ 4,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_TIMURIDS"),
+ )
+
+ # Nogais
+ if DateTurn.i1500AD <= iGameTurn <= DateTurn.i1600AD:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (93, 38),
+ (99, 54),
+ Unit.HORSE_ARCHER,
+ 3,
+ iGameTurn,
+ 7,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_NOGAIS"),
+ )
+ if Civ.MOSCOW == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (93, 38),
+ (99, 54),
+ Unit.HORSE_ARCHER,
+ 2 + iHandicap,
+ iGameTurn,
+ 7,
+ 1,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_NOGAIS"),
+ )
+
+ # Kalmyks
+ elif DateTurn.i1600AD <= iGameTurn <= DateTurn.i1715AD:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (93, 38),
+ (99, 54),
+ Unit.MONGOL_KESHIK,
+ 3,
+ iGameTurn,
+ 7,
+ 0,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_KALMYKS"),
+ )
+ if Civ.MOSCOW == iHuman:
+ spawnUnits(
+ Civ.BARBARIAN,
+ (93, 38),
+ (99, 54),
+ Unit.MONGOL_KESHIK,
+ 3 + iHandicap,
+ iGameTurn,
+ 7,
+ 0,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_KALMYKS"),
+ )
+
+ # Independent/barb city spawns and minor nations:
+ doIndependentCities(iGameTurn)
+
+ if iGameTurn == 1:
+ setupMinorNation()
+ doMinorNations(iGameTurn)
+
+
+def doIndependentCities(iGameTurn):
+ if iGameTurn in dIndependentCities.keys():
+ for tCity in dIndependentCities[iGameTurn]:
+ lVariations, iCiv, iPop, iUnit, iNumUnits, iReligion, iWorkers = tCity
+ iChosenCity = -1
+ iRand = percentage()
+ for iCity in range(len(lVariations)):
+ if iRand < lVariations[iCity][2]:
+ iChosenCity = iCity
+ break
+ iRand -= lVariations[iCity][2]
+ if iChosenCity == -1:
+ continue
+ tCoords, sName, iPos = lVariations[iChosenCity]
+ foundCity(iCiv, tCoords, sName, iPop, iUnit, iNumUnits, iReligion, iWorkers)
+
+
+def foundCity(iCiv, tCoords, name, iPopulation, iUnitType, iNumUnits, iReligion, iWorkers):
+ if checkRegion(tCoords):
+ gc.getPlayer(iCiv).found(tCoords[0], tCoords[1])
+ city = gc.getMap().plot(tCoords[0], tCoords[1]).getPlotCity()
+ city.setName(name, False)
+ if iPopulation != 1:
+ city.setPopulation(iPopulation)
+ if iNumUnits > 0:
+ make_units(iCiv, iUnitType, tCoords, iNumUnits)
+ if iReligion > -1:
+ city.setHasReligion(iReligion, True, True, False)
+ if iWorkers > 0:
+ make_units(iCiv, Unit.WORKER, tCoords, iWorkers)
+
+
+def checkRegion(tCoords):
+ cityPlot = gc.getMap().plot(tCoords[0], tCoords[1])
+
+ # checks if the plot already belongs to someone
+ if cityPlot.isOwned():
+ if cityPlot.getOwner() != Civ.BARBARIAN:
+ return False
+
+ # checks the surroundings for cities
+ if plots.surrounding(tCoords).cities().entities():
+ return False
+ return True
+
+
+def spawnUnits(
+ iCiv,
+ tTopLeft,
+ tBottomRight,
+ iUnitType,
+ iNumUnits,
+ iTurn,
+ iPeriod,
+ iRest,
+ function,
+ unit_ai,
+ unit_name=None,
+):
+ if (iTurn % iPeriod) == iRest:
+ plotList = squareSearch(tTopLeft, tBottomRight, function, [])
+ if plotList:
+ tPlot = random_entry(plotList)
+ if tPlot is not None:
+ make_units(iCiv, iUnitType, tPlot, iNumUnits, unit_ai, unit_name)
+
+
+def spawnVikings(
+ iCiv,
+ tTopLeft,
+ tBottomRight,
+ iUnitType,
+ iNumUnits,
+ iTurn,
+ iPeriod,
+ iRest,
+ function,
+ unit_name=None,
+):
+ if (iTurn % iPeriod) == iRest:
+ plotList = squareSearch(tTopLeft, tBottomRight, function, [])
+ if plotList:
+ tPlot = random_entry(plotList)
+ if tPlot is not None:
+ make_unit(iCiv, Unit.GALLEY, tPlot, UnitAITypes.UNITAI_ASSAULT_SEA, unit_name)
+ make_units(iCiv, iUnitType, tPlot, iNumUnits, UnitAITypes.UNITAI_ATTACK, unit_name)
+
+
+def spawnPirate(
+ iCiv,
+ tTopLeft,
+ tBottomRight,
+ iShipType,
+ iNumShips,
+ iFighterType,
+ iNumFighters,
+ iTurn,
+ iPeriod,
+ iRest,
+ function,
+ unit_name=None,
+):
+ if (iTurn % iPeriod) == iRest:
+ plotList = squareSearch(tTopLeft, tBottomRight, function, [])
+ if plotList:
+ tPlot = random_entry(plotList)
+ if tPlot is not None:
+ make_units(
+ iCiv, iShipType, tPlot, iNumShips, UnitAITypes.UNITAI_ATTACK_SEA, unit_name
+ )
+ make_units(
+ iCiv,
+ iFighterType,
+ tPlot,
+ iNumFighters,
+ UnitAITypes.UNITAI_ATTACK,
+ unit_name,
+ )
+
+
+def killNeighbours(tCoords):
+ "Kills all units in the neigbbouring tiles of plot (as well as plot it) so late starters have some space."
+ for unit in plots.surrounding(tCoords).units().entities():
+ unit.kill(False, Civ.BARBARIAN)
+
+
+def onImprovementDestroyed(iX, iY):
+ # getHandicapType: Viceroy=0, Monarch=1, Emperor=2)
+ iHandicap = gc.getGame().getHandicapType()
+ iTurn = turn()
+ if iTurn > DateTurn.i1500AD:
+ iBarbUnit = Unit.MUSKETMAN
+ elif iTurn > DateTurn.i1284AD:
+ iBarbUnit = Unit.ARQUEBUSIER
+ elif iTurn > DateTurn.i840AD:
+ iBarbUnit = Unit.HORSE_ARCHER
+ else:
+ iBarbUnit = Unit.SPEARMAN
+ spawnUnits(
+ Civ.BARBARIAN,
+ (iX - 1, iY - 1),
+ (iX + 1, iY + 1),
+ iBarbUnit,
+ 1 + iHandicap,
+ 1,
+ 1,
+ 0,
+ outerInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ )
+
+
+def setupMinorNation():
+ lNextMinorRevolt = getRevolDates()
+
+ for lNation in lMinorNations:
+ iNextRevolt = lNation[3][0]
+ while iNextRevolt in lNextMinorRevolt:
+ iNextRevolt = lNation[3][0] - 3 + rand(6)
+ iNationIndex = lMinorNations.index(lNation)
+ lNextMinorRevolt[iNationIndex] = iNextRevolt
+
+ setRevolDates(lNextMinorRevolt)
+
+
+def doMinorNations(iGameTurn):
+ lNextMinorRevolt = getRevolDates()
+
+ if iGameTurn in lNextMinorRevolt:
+ # iNation = lNextMinorRevolt.index( iGameTurn )
+ lNation = lMinorNations[lNextMinorRevolt.index(iGameTurn)]
+ lRevolts = lNation[3]
+ for iRevoltDate in lRevolts:
+ if (iRevoltDate - 3 <= iGameTurn) and (iRevoltDate + 3 >= iGameTurn):
+ iRevoltIndex = lRevolts.index(iRevoltDate)
+ break
+ # loop over all the province tiles to find the cities revolting
+ lPlayersOwning = [0] * civilizations().main().len()
+ iProvince = lNation[0]
+ for iI in range(gc.getNumProvinceTiles(iProvince)):
+ iX = gc.getProvinceX(iProvince, iI)
+ iY = gc.getProvinceY(iProvince, iI)
+ if gc.getMap().plot(iX, iY).isCity():
+ iOwner = gc.getMap().plot(iX, iY).getPlotCity().getOwner()
+ if -1 < iOwner < Civ.POPE: # pope doesn't count here
+ if (
+ iOwner not in lNation[1]
+ and gc.getPlayer(iOwner).getStateReligion() not in lNation[2]
+ ):
+ lPlayersOwning[iOwner] += 1
+
+ for iPlayer in civilizations().main().ids():
+ if lPlayersOwning[iPlayer] > 0:
+ if human() == iPlayer:
+ doRevoltHuman(iPlayer, iGameTurn, lNation, iRevoltIndex)
+ else:
+ doRevoltAI(iPlayer, iGameTurn, lNation, iRevoltIndex)
+ # setup next revolt
+ iRevoltIndex += 1
+ if iRevoltIndex < len(lNation[3]):
+ iNextRevolt = lNation[3][iRevoltIndex] - 3 + rand(6)
+ while iNextRevolt in lNextMinorRevolt:
+ iNextRevolt = lNation[3][iRevoltIndex] - 3 + rand(6)
+ lNextMinorRevolt[lNextMinorRevolt.index(iGameTurn)] = iNextRevolt
+ setRevolDates(lNextMinorRevolt)
+
+
+def doRevoltAI(iPlayer, iGameTurn, lNation, iRevoltIndex):
+ cityList = cities.owner(iPlayer).province(lNation[0]).entities()
+
+ iNumGarrison = 0
+ for iI in range(len(cityList)):
+ iNumGarrison += getGarrasonSize(cityList[iI])
+
+ # base rebellion odds: maximum 45%
+ # odds considering minor nation strength - between 10 and 40
+ iSuppressOdds = -lNation[4][iRevoltIndex]
+ # stability odds: maximum 20 + lNation[4][iRevoltIndex]
+ pPlayer = gc.getPlayer(iPlayer)
+ iSuppressOdds += 20 + max(-10, min(pPlayer.getStability() * 2, lNation[4][iRevoltIndex]))
+ # passive bonus from city garrison: maximum 15
+ iSuppressOdds += min((3 * iNumGarrison) / len(cityList), 15)
+ # AI bonus
+ iSuppressOdds += 10
+
+ # AI always cracks revolt: maximum 35%
+ # with a crackdown you will get a turn of unrest and some unhappiness even if it succeeds.
+ iSuppressOdds = 10
+ iSuppressOdds += min((5 * iNumGarrison) / len(cityList), 25)
+
+ # time to roll the dice
+ if percentage_chance(iSuppressOdds, strict=True, reverse=True):
+ # revolt suppressed
+ for iI in range(len(cityList)):
+ pCity = cityList[iI]
+ pCity.changeHurryAngerTimer(10)
+ pCity.changeOccupationTimer(1)
+ makeRebels(pCity, lNation[5][iRevoltIndex], lNation[6][iRevoltIndex], lNation[7][1])
+ else:
+ # revolt succeeded
+ iNewCiv = choice(INDEPENDENT_CIVS)
+ for iI in range(len(cityList)):
+ pCity = cityList[iI]
+ tCity = (pCity.getX(), pCity.getY())
+ cultureManager(tCity, 50, iNewCiv, iPlayer, False, True, True)
+ flipUnitsInCitySecession(tCity, iNewCiv, iPlayer)
+ setTempFlippingCity(tCity)
+ flipCity(
+ tCity, 0, 0, iNewCiv, [iPlayer]
+ ) # by trade because by conquest may raze the city
+ flipUnitsInCityAfter(getTempFlippingCity(), iNewCiv)
+
+
+@popup_handler(7627)
+def CounterReformationEvent(playerID, netUserData, popupReturn):
+ iDecision = popupReturn.getButtonClicked()
+ iNationIndex, iRevoltIndex = getNationRevoltIndex()
+ lNation = lMinorNations[iNationIndex]
+ iPlayer = human()
+
+ cityList = cities.owner(iPlayer).province(lNation[0]).entities()
+
+ iNumGarrison = 0
+ iBribeGold = 0
+ for iI in range(len(cityList)):
+ iNumGarrison += getGarrasonSize(cityList[iI])
+ iBribeGold += 10 * cityList[iI].getPopulation()
+
+ # raw suppress score
+ iSuppressOdds = -lNation[4][iRevoltIndex]
+ pPlayer = gc.getPlayer(iPlayer)
+ iSuppressOdds += 20 + max(-10, min(pPlayer.getStability() * 2, lNation[4][iRevoltIndex]))
+ iSuppressOdds += min((3 * iNumGarrison) / len(cityList), 15)
+
+ # 2nd or 4th choice
+ if iDecision in [1, 3]:
+ iSuppressOdds += 10 + min((5 * iNumGarrison) / len(cityList), 25)
+
+ # 3rd or 4th choice
+ if iDecision in [2, 3]:
+ iGovernment = pPlayer.getCivics(0)
+ if iGovernment == Civic.DESPOTISM:
+ iBribeOdds = 15
+ elif iGovernment == Civic.FEUDAL_MONARCHY:
+ iBribeOdds = 25
+ elif iGovernment == Civic.DIVINE_MONARCHY:
+ iBribeOdds = 30
+ elif iGovernment == Civic.LIMITE_DMONARCHY:
+ iBribeOdds = 25
+ elif iGovernment == Civic.MERCHANT_REPUBLIC:
+ iBribeOdds = 20
+ iGold = pPlayer.getGold()
+ if iGold < iBribeGold:
+ iBribeOdds = (iBribeOdds * iGold) / (iBribeGold)
+ pPlayer.setGold(iGold - min(iGold, iBribeGold))
+ iSuppressOdds += iBribeOdds
+
+ if percentage_chance(iSuppressOdds, strict=True, reverse=True):
+ # revolt suppressed
+ for iI in range(len(cityList)):
+ pCity = cityList[iI]
+ message(
+ iPlayer,
+ text("TXT_KEY_MINOR_NATION_REVOLT_SUPRESSED", pCity.getName()),
+ color=MessageData.BLUE,
+ )
+ # cracking the rebels results in unhappiness in the general population:
+ if iDecision in [1, 3]:
+ pCity.changeHurryAngerTimer(10)
+ pCity.changeOccupationTimer(1)
+ # bribing their lords away from their cause angers the rebel militia further:
+ if iDecision in [2, 3]:
+ makeRebels(
+ pCity,
+ lNation[5][iRevoltIndex],
+ 1 + lNation[6][iRevoltIndex],
+ lNation[7][1],
+ )
+ else:
+ makeRebels(
+ pCity, lNation[5][iRevoltIndex], lNation[6][iRevoltIndex], lNation[7][1]
+ )
+ else:
+ # revolt succeeded
+ iNewCiv = choice(INDEPENDENT_CIVS)
+ for iI in range(len(cityList)):
+ pCity = cityList[iI]
+ tCity = (pCity.getX(), pCity.getY())
+ sNationName = text(lNation[7][1])
+ message(
+ iPlayer,
+ text("TXT_KEY_MINOR_NATION_REVOLT_SUCCEEDED", sNationName, pCity.getName()),
+ color=MessageData.ORANGE,
+ )
+ cultureManager(tCity, 50, iNewCiv, iPlayer, False, True, True)
+ flipUnitsInCitySecession(tCity, iNewCiv, iPlayer)
+ setTempFlippingCity(tCity)
+ flipCity(
+ tCity, 0, 0, iNewCiv, [iPlayer]
+ ) # by trade because by conquest may raze the city
+ flipUnitsInCityAfter(getTempFlippingCity(), iNewCiv)
+
+
+# Absinthe: revolution choice effects:
+# base chance: stability bonus adjusted with the revolt strength + base chance + passive military presence - revolt strength
+# suppress with force: + base chance + military strength in the city. revolt +1 turn, unhappy +1 for 10 turns
+# bribe the lords: + financial chance: costs 10 gold per population, suppression depends on the government Divine Monarchy (30%), Feudal or Limited (25%), Merchant (20%), Decentral (15%)
+def doRevoltHuman(iPlayer, iGameTurn, lNation, iRevoltIndex):
+ setNationRevoltIndex(lMinorNations.index(lNation), iRevoltIndex)
+
+ cityList = cities.owner(iPlayer).province(lNation[0]).entities()
+
+ iNumGarrison = 0
+ iBribeGold = 0
+ for iI in range(len(cityList)):
+ iNumGarrison += getGarrasonSize(cityList[iI])
+ iBribeGold += 10 * cityList[iI].getPopulation()
+
+ # base rebellion odds: maximum 35%
+ # odds considering minor nation strength - usually 10, 20, 30, or 40
+ iRawOdds = -lNation[4][iRevoltIndex]
+ # stability odds: maximum 20 + lNation[4][iRevoltIndex]
+ pPlayer = gc.getPlayer(iPlayer)
+ iRawOdds += 20 + max(-10, min(pPlayer.getStability() * 2, lNation[4][iRevoltIndex]))
+ # passive bonus from city garrison: maximum 15
+ iRawOdds += min((3 * iNumGarrison) / len(cityList), 15)
+
+ # odds adjusted by a crackdown: maximum 35%
+ # with a crackdown you will get a turn of unrest and some unhappiness even if it succeeds.
+ iCrackOdds = 10
+ iCrackOdds += min((5 * iNumGarrison) / len(cityList), 25)
+
+ # odds adjusted by bribery: maximum 30%
+ # bribe the lords, cost 10 gold per population
+ # suppression depends on the government Divine Monarchy (30%), Feudal or Limited (25%), Merchant (20%), Decentral (15%)
+ iGovernment = pPlayer.getCivics(0)
+ if iGovernment == Civic.DESPOTISM:
+ iBribeOdds = 15
+ elif iGovernment == Civic.FEUDAL_MONARCHY:
+ iBribeOdds = 25
+ elif iGovernment == Civic.DIVINE_MONARCHY:
+ iBribeOdds = 30
+ elif iGovernment == Civic.LIMITE_DMONARCHY:
+ iBribeOdds = 25
+ elif iGovernment == Civic.MERCHANT_REPUBLIC:
+ iBribeOdds = 20
+ iGold = pPlayer.getGold()
+ if iGold < iBribeGold:
+ iBribeOdds = (iBribeOdds * iGold) / (iBribeGold)
+ iGold = min(iGold, iBribeGold)
+
+ # values should be between 0 and 100
+ iAllOdds = max(0, iRawOdds + iBribeOdds + iCrackOdds)
+ iBribeOdds = max(0, iRawOdds + iBribeOdds)
+ iCrackOdds = max(0, iRawOdds + iCrackOdds)
+ iRawOdds = max(0, iRawOdds)
+
+ rebel_name = text(lNation[7][0])
+ event_popup(
+ 7627,
+ text("TXT_KEY_MINOR_REBELLION_TITLE", rebel_name),
+ text("TXT_KEY_MINOR_REBELLION_DESC", rebel_name),
+ [
+ text("TXT_KEY_MINOR_REBELLION_DO_NOTHING", iRawOdds),
+ text("TXT_KEY_MINOR_REBELLION_CRACK", iCrackOdds),
+ text("TXT_KEY_MINOR_REBELLION_BRIBE", iGold, iBribeGold, iBribeOdds),
+ text("TXT_KEY_MINOR_REBELLION_ALL", iAllOdds),
+ ],
+ )
+
+
+def getGarrasonSize(pCity):
+ pPlot = gc.getMap().plot(pCity.getX(), pCity.getY())
+ iOwner = pPlot.getOwner()
+ if iOwner < 0:
+ return 0
+ iNumUnits = pPlot.getNumUnits()
+ iDefenders = 0
+ for i in range(iNumUnits):
+ if pPlot.getUnit(i).getOwner() == iOwner:
+ iDefenders += 1
+ return iDefenders
+
+
+def makeRebels(pCity, iUnit, iCount, szName):
+ lAvailableFreeTiles = []
+ lAvailableTiles = []
+ for plot in (
+ plots.surrounding(pCity)
+ .filter(lambda p: p.isHills() or p.isFlatlands())
+ .filter(lambda p: not p.isCity())
+ .entities()
+ ):
+ if plot.getNumUnits() == 0:
+ lAvailableFreeTiles.append(location(plot))
+ else:
+ lAvailableTiles.append(location(plot))
+
+ if lAvailableFreeTiles:
+ tPlot = choice(lAvailableFreeTiles)
+ elif lAvailableTiles:
+ # if all tiles are taken, select one tile at random and kill all units there
+ tPlot = choice(lAvailableTiles)
+ pPlot = gc.getMap().plot(tPlot[0], tPlot[1])
+ iN = pPlot.getNumUnits()
+ for i in range(iN):
+ pPlot.getUnit(0).kill(False, Civ.BARBARIAN)
+ else:
+ return
+
+ unit_name = text(szName)
+ make_units(Civ.BARBARIAN, iUnit, tPlot, iCount, UnitAITypes.UNITAI_ATTACK, unit_name)
diff --git a/Assets/Python/CityNameManager.py b/Assets/Python/CityNameManager.py
index 71ab8107f..6a5e76d7f 100644
--- a/Assets/Python/CityNameManager.py
+++ b/Assets/Python/CityNameManager.py
@@ -3,31 +3,43 @@
from CvPythonExtensions import *
from Core import civilizations, get_data_from_upside_down_map
from CityMapData import CITIES_MAP
+from Events import handler
gc = CyGlobalContext()
-class CityNameManager:
- def assignName(self, city):
- """Names a city depending on its plot"""
- iOwner = city.getOwner()
- if iOwner < civilizations().majors().len():
- cityName = get_data_from_upside_down_map(CITIES_MAP, iOwner, city)
- if cityName != "-1":
- city.setName(unicode(cityName), False)
-
- def renameCities(self, city, iNewOwner):
- """Renames a city depending on its owner"""
- if iNewOwner < civilizations().majors().len():
- cityName = get_data_from_upside_down_map(CITIES_MAP, iNewOwner, city)
- if cityName != "-1":
- city.setName(unicode(cityName), False)
-
- def lookupName(self, city, iPlayer):
- """Looks up a city name in another player's map"""
- if iPlayer < civilizations().majors().len():
- cityName = get_data_from_upside_down_map(CITIES_MAP, iPlayer, city)
- if cityName == "-1":
- return "Unknown"
- else:
- return cityName
+@handler("cityBuilt")
+def onCityBuilt(city):
+ assignName(city)
+
+
+@handler("cityAcquired")
+def onCityAcquired(iOwner, iNewOwner, city):
+ renameCities(city, iNewOwner)
+
+
+def assignName(city):
+ """Names a city depending on its plot"""
+ iOwner = city.getOwner()
+ if iOwner < civilizations().majors().len():
+ cityName = get_data_from_upside_down_map(CITIES_MAP, iOwner, city)
+ if cityName != "-1":
+ city.setName(unicode(cityName), False)
+
+
+def renameCities(city, iNewOwner):
+ """Renames a city depending on its owner"""
+ if iNewOwner < civilizations().majors().len():
+ cityName = get_data_from_upside_down_map(CITIES_MAP, iNewOwner, city)
+ if cityName != "-1":
+ city.setName(unicode(cityName), False)
+
+
+def lookupName(city, iPlayer):
+ """Looks up a city name in another player's map"""
+ if iPlayer < civilizations().majors().len():
+ cityName = get_data_from_upside_down_map(CITIES_MAP, iPlayer, city)
+ if cityName == "-1":
+ return "Unknown"
+ else:
+ return cityName
diff --git a/Assets/Python/Civilizations.py b/Assets/Python/Civilizations.py
index c5f9acf01..cfa13074a 100644
--- a/Assets/Python/Civilizations.py
+++ b/Assets/Python/Civilizations.py
@@ -15,12 +15,16 @@
from LocationsData import CIV_CAPITAL_LOCATIONS
from MiscData import REVEAL_DATE_TECHNOLOGY
from RFCUtils import change_attitude_extra_between_civ
+from Events import handler
+from TimelineData import TIMELINE_TECH_MODIFIER
gc = CyGlobalContext()
+@handler("GameStart")
def setup():
set_starting_turns()
+ set_tech_timeline_date()
def set_starting_turns():
@@ -28,6 +32,11 @@ def set_starting_turns():
gc.setStartingTurn(civ.id, civ.date.birth)
+def set_tech_timeline_date():
+ for tech, turn in TIMELINE_TECH_MODIFIER:
+ gc.setTimelineTechDateForTech(tech, year(turn))
+
+
def set_starting_gold():
for civ in civilizations():
condition = civ.scenario.get("condition")
@@ -145,7 +154,7 @@ def set_initial_contacts(iCiv, bMeet=True):
def reveal_rectangle(iCiv, area):
- for plot in plots().rectangle(area[Area.TILE_MIN], area[Area.TILE_MAX]).entities():
+ for plot in plots.rectangle(area[Area.TILE_MIN], area[Area.TILE_MAX]).entities():
plot.setRevealed(teamtype(iCiv), True, False, -1)
diff --git a/Assets/Python/components/Collapse.py b/Assets/Python/Collapse.py
similarity index 100%
rename from Assets/Python/components/Collapse.py
rename to Assets/Python/Collapse.py
diff --git a/Assets/Python/Companies.py b/Assets/Python/Companies.py
new file mode 100644
index 000000000..2e78b95aa
--- /dev/null
+++ b/Assets/Python/Companies.py
@@ -0,0 +1,790 @@
+# RFC Europe - Companies
+# Implemented by AbsintheRed, based on the wonderful idea of embryodead
+
+from CvPythonExtensions import *
+from Consts import MessageData
+from Core import (
+ civilizations,
+ get_scenario,
+ message,
+ human,
+ player,
+ text,
+ turn,
+ year,
+ cities,
+ companies,
+)
+from LocationsData import CITIES
+from PyUtils import rand
+import Crusades
+from operator import itemgetter
+from RFCUtils import getUniqueBuilding
+from Events import handler
+from MiscData import COMPANY_BUILDINGS
+from CoreTypes import (
+ Building,
+ City,
+ Civ,
+ Civic,
+ Company,
+ Province,
+ Scenario,
+ SpecialParameter,
+ Religion,
+ Technology,
+ Wonder,
+)
+
+gc = CyGlobalContext()
+
+
+@handler("GameStart")
+def setup():
+ # update companies at the beginning of the 1200AD scenario:
+ if get_scenario() == Scenario.i1200AD:
+ for company in companies:
+ if year(1200).between(company.birthdate, company.deathdate):
+ addCompany(company.id, 2)
+
+
+def getCityValue(city, iCompany):
+ if city is None:
+ return -1
+ elif city.isNone():
+ return -1
+
+ iValue = 0
+ owner = gc.getPlayer(city.getOwner())
+ iOwner = owner.getID()
+ ownerTeam = gc.getTeam(owner.getTeam())
+
+ # spread the Teutons to Teutonic Order cities and don't spread if the owner civ is at war with the Teutons
+ if iCompany == Company.TEUTONS:
+ if iOwner == Civ.PRUSSIA:
+ iValue += 5
+ elif ownerTeam.isAtWar(Civ.PRUSSIA):
+ return -1
+
+ # Genoese UP
+ if iOwner == Civ.GENOA:
+ iValue += 1
+ # extra bonus for banking companies
+ if iCompany in [Company.MEDICI, Company.AUGSBURG, Company.ST_GEORGE]:
+ iValue += 1
+
+ # state religion requirements
+ iStateReligion = owner.getStateReligion()
+ if iCompany in [Company.HOSPITALLERS, Company.TEMPLARS, Company.TEUTONS]:
+ if iStateReligion == Religion.CATHOLICISM:
+ iValue += 3
+ elif iStateReligion in [Religion.PROTESTANTISM, Religion.ORTHODOXY]:
+ iValue -= 2
+ else:
+ return -1
+ elif iCompany == Company.DRAGON:
+ if iStateReligion == Religion.CATHOLICISM:
+ iValue += 2
+ elif iStateReligion == Religion.ORTHODOXY:
+ iValue += 1
+ elif iStateReligion == Religion.ISLAM:
+ return -1
+ elif iCompany == Company.CALATRAVA:
+ if iStateReligion == Religion.CATHOLICISM:
+ iValue += 2
+ else:
+ return -1
+ else:
+ if iStateReligion == Religion.ISLAM:
+ return -1
+
+ # geographical requirements
+ iProvince = city.getProvince()
+ if len(companies[iCompany].region) and iProvince not in companies[iCompany].region:
+ return -1
+ if iCompany == Company.MEDICI:
+ if iProvince == Province.TUSCANY:
+ iValue += 4
+ elif iCompany == Company.AUGSBURG:
+ if iProvince == Province.BAVARIA:
+ iValue += 3
+ elif iProvince == Province.SWABIA:
+ iValue += 2
+ elif iCompany == Company.ST_GEORGE:
+ if iProvince == Province.LIGURIA:
+ iValue += 3
+ elif iCompany == Company.HANSA:
+ if iProvince == Province.HOLSTEIN:
+ iValue += 5
+ if iProvince in [Province.BRANDENBURG, Province.SAXONY]:
+ iValue += 2
+
+ # geographical requirement changes after the Crusades
+ iGameTurn = turn()
+ if iGameTurn < year(companies[Company.TEMPLARS].deathdate):
+ if iCompany in [
+ Company.HOSPITALLERS,
+ Company.TEMPLARS,
+ Company.TEUTONS,
+ ]:
+ if iStateReligion == Religion.CATHOLICISM:
+ if iProvince in [
+ Province.ANTIOCHIA,
+ Province.LEBANON,
+ Province.JERUSALEM,
+ ]:
+ iValue += 5
+ elif iProvince in [Province.CYPRUS, Province.EGYPT]:
+ iValue += 3
+ else:
+ if iCompany == Company.HOSPITALLERS:
+ if iProvince in [Province.RHODES, Province.MALTA]:
+ iValue += 4
+ elif iCompany == Company.TEUTONS:
+ if iProvince == Province.TRANSYLVANIA:
+ iValue += 2
+
+ # bonus for civs whom actively participate (with units) in the actual Crusade:
+ if iOwner < civilizations().majors().len():
+ if Crusades.getNumUnitsSent(iOwner) > 0:
+ if iCompany in [
+ Company.HOSPITALLERS,
+ Company.TEMPLARS,
+ Company.TEUTONS,
+ ]:
+ iValue += 2
+
+ # additional bonus for the city of Jerusalem
+ if (city.getX(), city.getY()) == CITIES[City.JERUSALEM]:
+ if iCompany in [
+ Company.HOSPITALLERS,
+ Company.TEMPLARS,
+ Company.TEUTONS,
+ ]:
+ iValue += 3
+
+ # coastal and riverside check
+ if iCompany == Company.HANSA:
+ if not city.isCoastal(20): # water body with at least 20 tiles
+ if not city.plot().isRiverSide():
+ return -1
+ elif iCompany == Company.HOSPITALLERS:
+ if city.isCoastal(20):
+ iValue += 2
+
+ # bonus for religions in the city
+ if iCompany in [
+ Company.HANSA,
+ Company.MEDICI,
+ Company.AUGSBURG,
+ Company.ST_GEORGE,
+ ]:
+ if city.isHasReligion(
+ Religion.JUDAISM
+ ): # not necessarily historic, but has great gameplay synergies
+ iValue += 1
+ elif iCompany in [
+ Company.HOSPITALLERS,
+ Company.TEMPLARS,
+ Company.TEUTONS,
+ Company.CALATRAVA,
+ ]:
+ # they have a harder time to choose a city without Catholicism, but they spread the religion there
+ if not city.isHasReligion(Religion.CATHOLICISM):
+ iValue -= 1
+ if city.isHasReligion(Religion.ISLAM):
+ iValue -= 1
+ elif iCompany == Company.DRAGON:
+ if city.isHasReligion(Religion.CATHOLICISM) or city.isHasReligion(Religion.ORTHODOXY):
+ iValue += 1
+ if city.isHasReligion(Religion.ISLAM):
+ iValue -= 1
+
+ # faith points of the population
+ if iCompany in [
+ Company.HOSPITALLERS,
+ Company.TEMPLARS,
+ Company.TEUTONS,
+ Company.CALATRAVA,
+ ]:
+ if owner.getFaith() >= 50:
+ iValue += 3
+ elif owner.getFaith() >= 30:
+ iValue += 2
+ elif owner.getFaith() >= 15:
+ iValue += 1
+
+ # city size
+ if iCompany in [
+ Company.HANSA,
+ Company.DRAGON,
+ Company.MEDICI,
+ Company.AUGSBURG,
+ Company.ST_GEORGE,
+ ]:
+ if city.getPopulation() > 9:
+ iValue += 3
+ elif city.getPopulation() > 6:
+ iValue += 2
+ elif city.getPopulation() > 3:
+ iValue += 1
+
+ # Galata Tower bonus: 2 for all cities, additional 2 for the wonder's city
+ if owner.getPicklefreeParameter(SpecialParameter.HAS_GALATA_TOWER) == 1:
+ iValue += 2
+ if city.isHasBuilding(Wonder.GALATA_TOWER):
+ iValue += 2
+
+ # various building bonuses, trade route bonus
+ iBuildCounter = 0 # building bonus counter: we don't want buildings to be the deciding factor in company spread
+ if iCompany in [Company.HOSPITALLERS, Company.TEMPLARS, Company.TEUTONS]:
+ iMaxPossible = 11 # building bonus counter: we don't want buildings to be the deciding factor in company spread
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.WALLS)) > 0:
+ iBuildCounter += 1
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.CASTLE)) > 0:
+ iBuildCounter += 2
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.BARRACKS)) > 0:
+ iBuildCounter += 1
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.STABLE)) > 0:
+ iBuildCounter += 1
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.ARCHERY_RANGE)) > 0:
+ iBuildCounter += 1
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.FORGE)) > 0:
+ iBuildCounter += 1
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.CATHOLIC_TEMPLE)) > 0:
+ iBuildCounter += 1
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.CATHOLIC_MONASTERY)) > 0:
+ iBuildCounter += 2
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.GUILD_HALL)) > 0:
+ iBuildCounter += 1
+ iValue += (4 * iBuildCounter) / iMaxPossible # maximum is 4, with all buildings built
+ # wonders should be handled separately
+ if city.getNumRealBuilding(Wonder.KRAK_DES_CHEVALIERS) > 0:
+ if iCompany == Company.HOSPITALLERS:
+ iValue += 5
+ else:
+ iValue += 2
+ if city.getNumRealBuilding(Wonder.DOME_ROCK) > 0:
+ if iCompany == Company.TEMPLARS:
+ iValue += 5
+ else:
+ iValue += 2
+ elif iCompany == Company.CALATRAVA:
+ iMaxPossible = 11 # building bonus counter: we don't want buildings to be the deciding factor in company spread
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.WALLS)) > 0:
+ iBuildCounter += 1
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.CASTLE)) > 0:
+ iBuildCounter += 2
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.BARRACKS)) > 0:
+ iBuildCounter += 1
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.STABLE)) > 0:
+ iBuildCounter += 1
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.ARCHERY_RANGE)) > 0:
+ iBuildCounter += 1
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.FORGE)) > 0:
+ iBuildCounter += 1
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.CATHOLIC_TEMPLE)) > 0:
+ iBuildCounter += 1
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.CATHOLIC_MONASTERY)) > 0:
+ iBuildCounter += 2
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.STAR_FORT)) > 0:
+ iBuildCounter += 1
+ iValue += (5 * iBuildCounter) / iMaxPossible # maximum is 5, with all buildings built
+ elif iCompany == Company.DRAGON:
+ iMaxPossible = 9 # building bonus counter: we don't want buildings to be the deciding factor in company spread
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.WALLS)) > 0:
+ iBuildCounter += 1
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.CASTLE)) > 0:
+ iBuildCounter += 2
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.BARRACKS)) > 0:
+ iBuildCounter += 1
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.STABLE)) > 0:
+ iBuildCounter += 1
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.ARCHERY_RANGE)) > 0:
+ iBuildCounter += 1
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.FORGE)) > 0:
+ iBuildCounter += 1
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.STAR_FORT)) > 0:
+ iBuildCounter += 2
+ iValue += (5 * iBuildCounter) / iMaxPossible # maximum is 5, with all buildings built
+ elif iCompany in [Company.MEDICI, Company.AUGSBURG, Company.ST_GEORGE]:
+ iMaxPossible = 11 # building bonus counter: we don't want buildings to be the deciding factor in company spread
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.MARKET)) > 0:
+ iBuildCounter += 1
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.BANK)) > 0:
+ iBuildCounter += 3
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.JEWELER)) > 0:
+ iBuildCounter += 2
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.GUILD_HALL)) > 0:
+ iBuildCounter += 1
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.LUXURY_STORE)) > 0:
+ iBuildCounter += 2
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.COURTHOUSE)) > 0:
+ iBuildCounter += 2
+ iValue += (5 * iBuildCounter) / iMaxPossible # maximum is 5, with all buildings built
+ # wonders should be handled separately
+ if city.getNumRealBuilding(Building.PALACE) > 0:
+ iValue += 1
+ if city.getNumRealBuilding(Building.SUMMER_PALACE) > 0:
+ iValue += 1
+ # bonus from trade routes
+ iValue += max(0, city.getTradeRoutes() - 1)
+ elif iCompany == Company.HANSA:
+ iMaxPossible = 16 # building bonus counter: we don't want buildings to be the deciding factor in company spread
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.HARBOR)) > 0:
+ iBuildCounter += 2
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.LIGHTHOUSE)) > 0:
+ iBuildCounter += 2
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.WHARF)) > 0:
+ iBuildCounter += 2
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.CUSTOM_HOUSE)) > 0:
+ iBuildCounter += 1
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.MARKET)) > 0:
+ iBuildCounter += 2
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.BREWERY)) > 0:
+ iBuildCounter += 1
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.WEAVER)) > 0:
+ iBuildCounter += 1
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.GUILD_HALL)) > 0:
+ iBuildCounter += 1
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.WAREHOUSE)) > 0:
+ iBuildCounter += 2
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.TANNERY)) > 0:
+ iBuildCounter += 1
+ if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.TEXTILE_MILL)) > 0:
+ iBuildCounter += 1
+ iValue += (6 * iBuildCounter) / iMaxPossible # maximum is 6, with all buildings built
+ # bonus from trade routes
+ iValue += city.getTradeRoutes()
+
+ # civic bonuses
+ if owner.getCivics(0) == Civic.MERCHANT_REPUBLIC:
+ if iCompany in [
+ Company.MEDICI,
+ Company.ST_GEORGE,
+ Company.HOSPITALLERS,
+ ]:
+ iValue += 1
+ elif iCompany == Company.HANSA:
+ iValue += 2
+ if owner.getCivics(1) == Civic.FEUDAL_LAW:
+ if iCompany in [
+ Company.HOSPITALLERS,
+ Company.TEMPLARS,
+ Company.TEUTONS,
+ Company.DRAGON,
+ Company.CALATRAVA,
+ ]:
+ iValue += 2
+ elif owner.getCivics(1) == Civic.RELIGIOUS_LAW:
+ if iCompany in [
+ Company.HOSPITALLERS,
+ Company.TEMPLARS,
+ Company.TEUTONS,
+ Company.CALATRAVA,
+ ]:
+ iValue += 1
+ if owner.getCivics(2) == Civic.APPRENTICESHIP:
+ if iCompany == Company.HANSA:
+ iValue += 1
+ if owner.getCivics(3) == Civic.TRADE_ECONOMY:
+ if iCompany in [Company.MEDICI, Company.AUGSBURG, Company.ST_GEORGE]:
+ iValue += 1
+ elif iCompany == Company.HANSA:
+ iValue += 2
+ elif owner.getCivics(3) == Civic.GUILDS:
+ if iCompany in [
+ Company.HOSPITALLERS,
+ Company.TEMPLARS,
+ Company.TEUTONS,
+ Company.MEDICI,
+ Company.AUGSBURG,
+ Company.ST_GEORGE,
+ Company.DRAGON,
+ Company.CALATRAVA,
+ ]:
+ iValue += 1
+ elif iCompany == Company.HANSA:
+ iValue += 2
+ elif owner.getCivics(3) == Civic.MERCANTILISM:
+ if iCompany == Company.HANSA:
+ return -1
+ elif iCompany in [
+ Company.MEDICI,
+ Company.AUGSBURG,
+ Company.ST_GEORGE,
+ ]:
+ iValue -= 2
+ if owner.getCivics(4) == Civic.THEOCRACY:
+ if iCompany in [Company.HOSPITALLERS, Company.TEMPLARS]:
+ iValue += 1
+ elif iCompany == Company.TEUTONS:
+ iValue += 2
+ elif owner.getCivics(4) == Civic.FREE_RELIGION:
+ if iCompany in [
+ Company.HOSPITALLERS,
+ Company.TEMPLARS,
+ Company.TEUTONS,
+ Company.DRAGON,
+ ]:
+ iValue -= 1
+ elif iCompany == Company.CALATRAVA:
+ iValue -= 2
+ if owner.getCivics(5) == Civic.OCCUPATION:
+ if iCompany in [
+ Company.HOSPITALLERS,
+ Company.TEMPLARS,
+ iCompany,
+ iCompany == Company.CALATRAVA,
+ ]:
+ iValue += 1
+
+ # bonus for techs
+ if iCompany in [
+ Company.HOSPITALLERS,
+ Company.TEMPLARS,
+ Company.TEUTONS,
+ Company.DRAGON,
+ Company.CALATRAVA,
+ ]:
+ for iTech in [
+ Technology.CHIVALRY,
+ Technology.PLATE_ARMOR,
+ Technology.GUILDS,
+ Technology.MILITARY_TRADITION,
+ ]:
+ if ownerTeam.isHasTech(iTech):
+ iValue += 1
+ elif iCompany == Company.HANSA:
+ for iTech in [
+ Technology.GUILDS,
+ Technology.CLOCKMAKING,
+ Technology.OPTICS,
+ Technology.SHIP_BUILDING,
+ ]:
+ if ownerTeam.isHasTech(iTech):
+ iValue += 1
+ elif iCompany in [Company.MEDICI, Company.ST_GEORGE]:
+ for iTech in [
+ Technology.BANKING,
+ Technology.PAPER,
+ Technology.CLOCKMAKING,
+ Technology.OPTICS,
+ Technology.SHIP_BUILDING,
+ ]:
+ if ownerTeam.isHasTech(iTech):
+ iValue += 1
+ elif iCompany == Company.AUGSBURG:
+ for iTech in [
+ Technology.BANKING,
+ Technology.PAPER,
+ Technology.CHEMISTRY,
+ ]:
+ if ownerTeam.isHasTech(iTech):
+ iValue += 1
+
+ # resources
+ iTempValue = 0
+ bFound = False
+ for i in range(5):
+ iBonus = gc.getCorporationInfo(iCompany).getPrereqBonus(i)
+ if iBonus > -1:
+ if city.getNumBonuses(iBonus) > 0:
+ bFound = True
+ if iCompany in [
+ Company.HOSPITALLERS,
+ Company.TEMPLARS,
+ Company.TEUTONS,
+ Company.DRAGON,
+ Company.CALATRAVA,
+ ]:
+ iTempValue += (
+ city.getNumBonuses(iBonus) + 2
+ ) # 3 for the first bonus, 1 for the rest of the same type
+ else:
+ iTempValue += (
+ city.getNumBonuses(iBonus) + 1
+ ) * 2 # 4 for the first bonus, 2 for the rest
+ if (
+ iCompany
+ in [
+ Company.HANSA,
+ Company.MEDICI,
+ Company.AUGSBURG,
+ Company.ST_GEORGE,
+ ]
+ and not bFound
+ ):
+ return -1
+ # we don't want the bonus to get too big, and dominate the selection values
+ iValue += iTempValue / 4
+
+ # bonus for resources in the fat cross of a city?
+
+ # competition
+ if iCompany == Company.HOSPITALLERS:
+ if city.isHasCorporation(Company.TEMPLARS):
+ iValue *= 2
+ iValue /= 3
+ if city.isHasCorporation(Company.TEUTONS):
+ iValue *= 2
+ iValue /= 3
+ elif iCompany == Company.TEMPLARS:
+ if city.isHasCorporation(Company.HOSPITALLERS):
+ iValue *= 2
+ iValue /= 3
+ if city.isHasCorporation(Company.TEUTONS):
+ iValue *= 2
+ iValue /= 3
+ elif iCompany == Company.TEUTONS:
+ if city.isHasCorporation(Company.TEMPLARS):
+ iValue *= 2
+ iValue /= 3
+ if city.isHasCorporation(Company.HOSPITALLERS):
+ iValue *= 2
+ iValue /= 3
+ elif iCompany == Company.MEDICI:
+ if city.isHasCorporation(Company.ST_GEORGE) or city.isHasCorporation(Company.AUGSBURG):
+ iValue /= 2
+ elif iCompany == Company.ST_GEORGE:
+ if city.isHasCorporation(Company.MEDICI) or city.isHasCorporation(Company.AUGSBURG):
+ iValue /= 2
+ elif iCompany == Company.AUGSBURG:
+ if city.isHasCorporation(Company.MEDICI) or city.isHasCorporation(Company.ST_GEORGE):
+ iValue /= 2
+
+ # threshold
+ if iValue < 3:
+ return -1
+
+ # spread it out
+ iCompOwned = owner.countCorporations(iCompany)
+ if city.isHasCorporation(iCompany):
+ iValue -= iCompOwned # -1 per city if the company is already present here (smaller penalty in the value list)
+ else:
+ iValue -= (
+ 5 * iCompOwned / 2
+ ) # -2,5 per city if it's a possible new spread (bigger penalty in the value list)
+
+ return iValue
+
+
+def addCompany(iCompany, iNumber):
+
+ # adds the company to the best iNumber cities
+ cityValueList = []
+ iCompaniesAdded = 0
+ for iPlayer in civilizations().majors().ids():
+ for city in cities.owner(iPlayer).entities():
+ iValue = getCityValue(city, iCompany)
+ if iValue > 0:
+ cityValueList.append((city, iValue * 10 + rand(10)))
+ # sort cities from highest to lowest value
+ cityValueList.sort(key=itemgetter(1), reverse=True)
+ # spread the company
+ for (city, _) in cityValueList:
+ if not city.isHasCorporation(iCompany):
+ city.setHasCorporation(iCompany, True, True, True)
+ city.setHasRealBuilding(COMPANY_BUILDINGS[iCompany], True)
+ iCompaniesAdded += 1
+ if iCompaniesAdded == iNumber:
+ break
+
+
+@handler("BeginGameTurn")
+def checkTurn(iGameTurn):
+ # check if it's not too early
+ iCompany = iGameTurn % companies.len()
+ if iGameTurn < year(companies[iCompany].birthdate):
+ return
+
+ # check if it's not too late
+ elif iGameTurn > year(companies[iCompany].deathdate) + rand(companies.len()):
+ iMaxCompanies = 0
+ # do not dissolve the Templars while Jerusalem is under Catholic control
+ if iCompany == Company.TEMPLARS:
+ plot = gc.getMap().plot(*CITIES[City.JERUSALEM])
+ if plot.isCity():
+ if (
+ gc.getPlayer(plot.getPlotCity().getOwner()).getStateReligion()
+ == Religion.CATHOLICISM
+ ):
+ iMaxCompanies = companies[iCompany].limit
+
+ # set the company limit
+ else:
+ iMaxCompanies = companies[iCompany].limit
+
+ # modified limit for Hospitallers and Teutons after the Crusades
+ if iGameTurn > year(companies[Company.TEMPLARS].deathdate):
+ if iCompany == Company.HOSPITALLERS and iGameTurn < year(companies[iCompany].deathdate):
+ iMaxCompanies -= 1
+ elif iCompany == Company.TEUTONS and iGameTurn < year(companies[iCompany].deathdate):
+ iMaxCompanies += 2
+ # increased limit for Hansa after their first general Diet in 1356
+ if iCompany == Company.HANSA:
+ if year(1356) < iGameTurn < year(companies[iCompany].deathdate):
+ iMaxCompanies += 3
+
+ # Templars are Teutons are gone after the Protestant reformation
+ if iCompany in [Company.TEMPLARS, Company.TEUTONS]:
+ if gc.getGame().isReligionFounded(Religion.PROTESTANTISM):
+ iMaxCompanies = 0
+ # Order of Calatrava is only active if Cordoba or Morocco is alive
+ # TODO: Only if Cordoba is alive, or Morocco has some territories in Europe?
+ if iCompany == Company.CALATRAVA:
+ if not (gc.getPlayer(Civ.CORDOBA).isAlive() or gc.getPlayer(Civ.MOROCCO).isAlive()):
+ iMaxCompanies = 0
+ # Order of the Dragon is only active if the Ottomans are alive
+ if iCompany == Company.DRAGON:
+ if not gc.getPlayer(Civ.OTTOMAN).isAlive():
+ iMaxCompanies = 0
+
+ # loop through all cities, check the company value for each and add the good ones to a list of tuples (city, value)
+ cityValueList = []
+ for iPlayer in civilizations().majors().ids():
+ for city in cities.owner(iPlayer).entities():
+ iValue = getCityValue(city, iCompany)
+ if iValue > 0:
+ sCityName = city.getName()
+ bPresent = False
+ if city.isHasCorporation(iCompany):
+ bPresent = True
+ cityValueList.append((city, iValue * 10 + rand(10)))
+ elif city.isHasCorporation(
+ iCompany
+ ): # remove company from cities with a negative value
+ city.setHasCorporation(iCompany, False, True, True)
+ city.setHasRealBuilding(COMPANY_BUILDINGS[iCompany], False)
+ sCityName = city.getName()
+ # interface message for the human player
+ announceHuman(iCompany, city, True)
+
+ # sort cities from highest to lowest value
+ cityValueList.sort(key=itemgetter(1), reverse=True)
+
+ # count the number of companies
+ iCompanyCount = 0
+ for civ in civilizations().majors():
+ if civ.player.isAlive():
+ iCompanyCount += civ.player.countCorporations(iCompany)
+
+ # spread the company
+ for i in range(len(cityValueList)):
+ city, iValue = cityValueList[i]
+ if city.isHasCorporation(iCompany):
+ continue
+ if (
+ i >= iMaxCompanies
+ ): # the goal is to have the company in the first iMaxCompanies number of cities
+ break
+ city.setHasCorporation(iCompany, True, True, True)
+ city.setHasRealBuilding(COMPANY_BUILDINGS[iCompany], True)
+ iCompanyCount += 1
+ sCityName = city.getName()
+ # interface message for the human player
+ announceHuman(iCompany, city)
+ # spread the religion if it wasn't present before
+ if iCompany in [
+ Company.HOSPITALLERS,
+ Company.TEMPLARS,
+ Company.TEUTONS,
+ Company.CALATRAVA,
+ ]:
+ if not city.isHasReligion(Religion.CATHOLICISM):
+ city.setHasReligion(Religion.CATHOLICISM, True, True, False)
+ # one change at a time, only add the highest ranked city (which didn't have the company before)
+ break
+
+ # if the limit was exceeded, remove company from it's worst city
+ if iCompanyCount > iMaxCompanies:
+ for (city, iValue) in reversed(cityValueList): # loop backwards in the ordered list
+ if city.isHasCorporation(iCompany):
+ city.setHasCorporation(iCompany, False, True, True)
+ city.setHasRealBuilding(COMPANY_BUILDINGS[iCompany], False)
+ sCityName = city.getName()
+ # interface message for the human player
+ announceHuman(iCompany, city, True)
+ # one change at a time, only add the lowest ranked city
+ break
+
+
+@handler("playerChangeStateReligion")
+def onPlayerChangeStateReligion(iPlayer, iNewReligion, iOldReligion):
+ if iPlayer < civilizations().majors().len():
+ for city in cities.owner(iPlayer).entities():
+ for iCompany in companies.ids():
+ if city.isHasCorporation(iCompany):
+ if getCityValue(city, iCompany) < 0:
+ city.setHasCorporation(iCompany, False, True, True)
+ city.setHasRealBuilding(COMPANY_BUILDINGS[iCompany], False)
+ announceHuman(iCompany, city, True)
+
+
+@handler("buildingBuilt")
+def onBuildingBuilt(city, building_type):
+ # Galata Tower ownership
+ if city.getOwner() < civilizations().majors().len():
+ iPlayer = city.getOwner()
+ pPlayer = gc.getPlayer(iPlayer)
+ if building_type == Wonder.GALATA_TOWER:
+ pPlayer.setPicklefreeParameter(SpecialParameter.HAS_GALATA_TOWER, 1)
+
+
+@handler("cityAcquired")
+def onCityAcquired(iOldOwner, iNewOwner, city):
+
+ for iCompany in companies.ids():
+ if city.isHasCorporation(iCompany):
+ if getCityValue(city, iCompany) < 0:
+ city.setHasCorporation(iCompany, False, True, True)
+ city.setHasRealBuilding(COMPANY_BUILDINGS[iCompany], False)
+ sCityName = city.getName()
+ # interface message for the human player
+ announceHuman(iCompany, city, True)
+
+ # Galata Tower ownership
+ pOldOwner = gc.getPlayer(iOldOwner)
+ pNewOwner = gc.getPlayer(iNewOwner)
+ if city.isHasBuilding(Wonder.GALATA_TOWER):
+ pNewOwner.setPicklefreeParameter(SpecialParameter.HAS_GALATA_TOWER, 1)
+ pOldOwner.setPicklefreeParameter(SpecialParameter.HAS_GALATA_TOWER, 0)
+
+
+@handler("cityRazed")
+def onCityRazed(city, iPlayer):
+ iPreviousOwner = city.getOwner()
+ if iPreviousOwner == iPlayer and city.getPreviousOwner() != -1:
+ iPreviousOwner = city.getPreviousOwner()
+
+ # TODO move to Wonders.py?
+ # Galata Tower ownership
+ pPreviousOwner = gc.getPlayer(iPreviousOwner)
+ pPlayer = gc.getPlayer(iPlayer)
+ if city.isHasBuilding(Wonder.GALATA_TOWER):
+ pPlayer.setPicklefreeParameter(SpecialParameter.HAS_GALATA_TOWER, 0)
+ pPreviousOwner.setPicklefreeParameter(SpecialParameter.HAS_GALATA_TOWER, 0)
+
+
+def announceHuman(iCompany, city, bRemove=False):
+ iHuman = human()
+ iHumanTeam = gc.getPlayer(iHuman).getTeam()
+ if not player().isExisting() or not city.isRevealed(iHumanTeam, False):
+ return
+
+ sCityName = city.getName()
+ sCompanyName = gc.getCorporationInfo(iCompany).getDescription()
+
+ if bRemove:
+ sText = text("TXT_KEY_MISC_CORPORATION_REMOVED", sCompanyName, sCityName)
+ else:
+ sText = text("TXT_KEY_MISC_CORPORATION_SPREAD", sCompanyName, sCityName)
+ message(
+ iHuman,
+ sText,
+ sound=gc.getCorporationInfo(iCompany).getSound(),
+ event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
+ button=gc.getCorporationInfo(iCompany).getButton(),
+ color=MessageData.WHITE,
+ location=city,
+ )
diff --git a/Assets/Python/Core.py b/Assets/Python/Core.py
index 4d55fd8fd..79e2d14ba 100644
--- a/Assets/Python/Core.py
+++ b/Assets/Python/Core.py
@@ -1,5 +1,3 @@
-# from BugEventManager import g_eventManager as events
-
from CivilizationsData import (
CIV_ADDITIONAL_UNITS,
CIV_AI_MODIFIERS,
@@ -22,6 +20,7 @@
)
from Consts import INDEPENDENT_CIVS, WORLD_HEIGHT, WORLD_WIDTH, MessageData
from CoreTypes import Civ, Scenario
+import CvUtil
from LocationsData import (
CIV_AREAS,
CIV_CAPITAL_LOCATIONS,
@@ -2241,6 +2240,11 @@ def font_symbol(iSymbol, fontsize=2):
return font_text(symbol(iSymbol), fontsize)
+def show_if_human(player, message, *format):
+ if human() == player:
+ show(message, *format)
+
+
def show(message, *format):
if format:
message = message % tuple(format)
@@ -2262,6 +2266,11 @@ def event_popup(id, title, message, labels=None):
popup.launch(not labels)
+def message_if_human(player, text, **settings):
+ if human() == player:
+ message(player, text, **settings)
+
+
def message(player, text, **settings):
force = settings.get("force", False)
duration = settings.get("duration", MessageData.DURATION)
@@ -2291,6 +2300,10 @@ def message(player, text, **settings):
)
+def log(message):
+ CvUtil.pyPrint(message)
+
+
def get_data_from_province_map(plot):
x, y = location(plot)
return PROVINCES_MAP[y][x]
@@ -2422,8 +2435,8 @@ def civilization(identifier=None):
.collect()
)
-techs = TechFactory
-units = UnitFactory
-plots = PlotFactory
-cities = CityFactory
-infos = Infos
+techs = TechFactory()
+units = UnitFactory()
+plots = PlotFactory()
+cities = CityFactory()
+infos = Infos()
diff --git a/Assets/Python/Crusades.py b/Assets/Python/Crusades.py
new file mode 100644
index 000000000..cd9528f91
--- /dev/null
+++ b/Assets/Python/Crusades.py
@@ -0,0 +1,1921 @@
+from CvPythonExtensions import *
+from Consts import MessageData
+from Core import (
+ civilization,
+ civilizations,
+ event_popup,
+ human,
+ location,
+ make_crusade_unit,
+ make_crusade_units,
+ message_if_human,
+ player,
+ team,
+ teamtype,
+ message,
+ text,
+ turn,
+ year,
+ cities,
+ plots,
+ units,
+)
+from Events import handler, popup_handler
+from PyUtils import percentage, percentage_chance, rand, choice
+from ProvinceMapData import PROVINCES_MAP
+from CityNameManager import lookupName
+from RFCUtils import convertPlotCulture, getMaster, getUniqueUnit, isAVassal
+from StoredData import data
+import random
+
+from CoreTypes import City, Civ, Religion, Promotion, Technology, Unit, Province
+from MiscData import NUM_CRUSADES
+from LocationsData import CITIES
+
+gc = CyGlobalContext()
+
+
+# Can call defensive crusade to aid Catholics, if at war with Non-Catholic and Non-Orthodox player, who isn't vassal of Catholic or Orthodox player and has at least one city in the provinces listed here
+tDefensiveCrusadeMap = [
+ [], # Byzantium
+ [
+ Province.ILE_DE_FRANCE,
+ Province.AQUITAINE,
+ Province.ORLEANS,
+ Province.CHAMPAGNE,
+ Province.BRETAGNE,
+ Province.NORMANDY,
+ Province.PROVENCE,
+ Province.FLANDERS,
+ Province.BURGUNDY,
+ Province.PICARDY,
+ ], # France
+ [], # Arabia
+ [], # Bulgaria
+ [
+ Province.LEON,
+ Province.GALICIA,
+ Province.LUSITANIA,
+ Province.ARAGON,
+ Province.CATALONIA,
+ Province.NAVARRE,
+ Province.CASTILE,
+ Province.ANDALUSIA,
+ Province.LA_MANCHA,
+ Province.VALENCIA,
+ ], # Cordoba (for consistency)
+ [
+ Province.VERONA,
+ Province.TUSCANY,
+ Province.ARBERIA,
+ Province.DALMATIA,
+ ], # Venecia
+ [
+ Province.FLANDERS,
+ Province.PROVENCE,
+ Province.BURGUNDY,
+ Province.CHAMPAGNE,
+ Province.LORRAINE,
+ Province.PICARDY,
+ ], # Burgundy
+ [
+ Province.LORRAINE,
+ Province.SWABIA,
+ Province.BAVARIA,
+ Province.SAXONY,
+ Province.FRANCONIA,
+ Province.FLANDERS,
+ Province.BRANDENBURG,
+ Province.HOLSTEIN,
+ Province.BOHEMIA,
+ ], # Germany
+ [], # Novgorod
+ [], # Norway
+ [], # Kiev
+ [
+ Province.HUNGARY,
+ Province.TRANSYLVANIA,
+ Province.UPPER_HUNGARY,
+ Province.WALLACHIA,
+ Province.SLAVONIA,
+ Province.PANNONIA,
+ Province.AUSTRIA,
+ Province.CARINTHIA,
+ Province.SERBIA,
+ Province.MOESIA,
+ Province.BANAT,
+ Province.BOSNIA,
+ Province.DALMATIA,
+ ], # Hungary
+ [
+ Province.LEON,
+ Province.GALICIA,
+ Province.LUSITANIA,
+ Province.ARAGON,
+ Province.CATALONIA,
+ Province.NAVARRE,
+ Province.CASTILE,
+ Province.ANDALUSIA,
+ Province.LA_MANCHA,
+ Province.VALENCIA,
+ ], # Spain
+ [Province.ESTONIA], # Denmark
+ [], # Scotland
+ [
+ Province.GREATER_POLAND,
+ Province.LESSER_POLAND,
+ Province.SILESIA,
+ Province.POMERANIA,
+ Province.MASOVIA,
+ Province.GALICJA,
+ Province.BREST,
+ ], # Poland
+ [
+ Province.LIGURIA,
+ Province.LOMBARDY,
+ Province.CORSICA,
+ Province.SARDINIA,
+ Province.TUSCANY,
+ ], # Genoa
+ [], # Morocco
+ [], # England
+ [
+ Province.LEON,
+ Province.GALICIA,
+ Province.LUSITANIA,
+ Province.ARAGON,
+ Province.CATALONIA,
+ Province.NAVARRE,
+ Province.CASTILE,
+ Province.ANDALUSIA,
+ Province.LA_MANCHA,
+ Province.VALENCIA,
+ ], # Portugal
+ [
+ Province.VALENCIA,
+ Province.BALEARS,
+ Province.SICILY,
+ Province.APULIA,
+ Province.CALABRIA,
+ ], # Aragon
+ [Province.OSTERLAND], # Sweden
+ [
+ Province.LIVONIA,
+ Province.ESTONIA,
+ Province.LITHUANIA,
+ Province.PRUSSIA,
+ ], # Prussia
+ [], # Lithuania
+ [
+ Province.AUSTRIA,
+ Province.CARINTHIA,
+ Province.BAVARIA,
+ Province.BOHEMIA,
+ Province.MORAVIA,
+ Province.SILESIA,
+ ], # Austria
+ [], # Turkey
+ [], # Moscow
+ [], # Dutch
+ [], # Papal States
+]
+
+
+def getCrusadeInit(iCrusade):
+ return data.lCrusadeInit[iCrusade]
+
+
+def setCrusadeInit(iCrusade, iNewCode):
+ # codes are: -2, no crusade yet
+ # -1 crusade is active but waiting to start (Holy City is Christian and/or another Crusade in progress)
+ # 0 or more, the turn when it was initialized
+ data.lCrusadeInit[iCrusade] = iNewCode
+
+
+def addSelectedUnit(iUnitPlace):
+ data.lSelectedUnits[iUnitPlace] += 1
+
+
+def setSelectedUnit(iUnitPlace, iNewNumber):
+ data.lSelectedUnits[iUnitPlace] = iNewNumber
+
+
+def getSelectedUnit(iUnitPlace):
+ return data.lSelectedUnits[iUnitPlace]
+
+
+def changeNumUnitsSent(iPlayer, iChange):
+ data.lNumUnitsSent[iPlayer] += iChange
+
+
+def setNumUnitsSent(iPlayer, iNewNumber):
+ data.lNumUnitsSent[iPlayer] = iNewNumber
+
+
+def getNumUnitsSent(iPlayer):
+ return data.lNumUnitsSent[iPlayer]
+
+
+def getActiveCrusade(iGameTurn):
+ for i in range(NUM_CRUSADES):
+ iInit = data.lCrusadeInit[i]
+ if iInit > -1 and iInit + 9 > iGameTurn:
+ return i
+ return -1
+
+
+def getParticipate():
+ return data.bParticipate
+
+
+def setParticipate(bVal):
+ data.bParticipate = bVal
+
+
+def getVotingPower(iCiv):
+ return data.lVotingPower[iCiv]
+
+
+def setVotingPower(iCiv, iVotes):
+ data.lVotingPower[iCiv] = iVotes
+
+
+def getCrusadePower():
+ return data.iCrusadePower
+
+
+def setCrusadePower(iPower):
+ data.iCrusadePower = iPower
+
+
+def getFavorite():
+ return data.iFavorite
+
+
+def setFavorite(iFavorite):
+ data.iFavorite = iFavorite
+
+
+def getPowerful():
+ return data.iPowerful
+
+
+def setPowerful(iPowerful):
+ data.iPowerful = iPowerful
+
+
+def getLeader():
+ return data.iLeader
+
+
+def setLeader(iLeader):
+ data.iLeader = iLeader
+
+
+def getVotesGatheredFavorite():
+ return data.lVotesGathered[0]
+
+
+def setVotesGatheredFavorite(iVotes):
+ data.lVotesGathered[0] = iVotes
+
+
+def getVotesGatheredPowerful():
+ return data.lVotesGathered[1]
+
+
+def setVotesGatheredPowerful(iVotes):
+ data.lVotesGathered[1] = iVotes
+
+
+def getRichestCatholic():
+ return data.iRichestCatholic
+
+
+def setRichestCatholic(iPlayer):
+ data.iRichestCatholic = iPlayer
+
+
+def getIsTarget(iCiv):
+ return data.lDeviateTargets[iCiv]
+
+
+def setIsTarget(iCiv, bTarget):
+ data.lDeviateTargets[iCiv] = bTarget
+
+
+def getTargetPlot():
+ return data.tTarget
+
+
+def setTarget(iX, iY):
+ data.tTarget = (iX, iY)
+
+
+def hasSucceeded():
+ iSucc = data.iCrusadeSucceeded
+ iTest = iSucc == 1
+ return iTest
+
+
+def setSucceeded():
+ data.iCrusadeSucceeded = 1
+
+
+def getCrusadeToReturn():
+ return data.iCrusadeToReturn
+
+
+def setCrusadeToReturn(iNewValue):
+ data.iCrusadeToReturn = iNewValue
+
+
+def isDefensiveCrusadeEnabled():
+ return data.bDCEnabled
+
+
+def setDefensiveCrusadeEnabled(bNewValue):
+ data.bDCEnabled = bNewValue
+
+
+def getDefensiveCrusadeLast():
+ return data.iDCLast
+
+
+def setDefensiveCrusadeLast(iLast):
+ data.iDCLast = iLast
+
+
+def initVotePopup():
+ iHuman = human()
+ pHuman = gc.getPlayer(iHuman)
+ iActiveCrusade = getActiveCrusade(turn())
+ iBribe = 200 + 50 * iActiveCrusade
+ if pHuman.getGold() >= iBribe:
+ event_popup(
+ 7616,
+ text("TXT_KEY_CRUSADE_INIT_POPUP"),
+ text("TXT_KEY_CRUSADE_INIT"),
+ [
+ text("TXT_KEY_CRUSADE_ACCEPT"),
+ text("TXT_KEY_CRUSADE_DENY"),
+ text("TXT_KEY_CRUSADE_DENY_RUDE"),
+ text("TXT_KEY_CRUSADE_BRIBE_OUT", iBribe),
+ ],
+ )
+ else:
+ event_popup(
+ 7616,
+ text("TXT_KEY_CRUSADE_INIT_POPUP"),
+ text("TXT_KEY_CRUSADE_INIT"),
+ [
+ text("TXT_KEY_CRUSADE_ACCEPT"),
+ text("TXT_KEY_CRUSADE_DENY"),
+ text("TXT_KEY_CRUSADE_DENY_RUDE"),
+ ],
+ )
+
+
+@popup_handler(7617)
+def event7617(playerID, netUserData, popupReturn):
+ pass
+
+
+def informLeaderPopup():
+ event_popup(
+ 7617,
+ text("TXT_KEY_CRUSADE_LEADER_POPUP"),
+ player(getLeader()).getName() + text("TXT_KEY_CRUSADE_LEAD"),
+ [text("TXT_KEY_CRUSADE_OK")],
+ )
+
+
+@popup_handler(7618)
+def HumanVotePopup(playerID, netUserData, popupReturn):
+ if popupReturn.getButtonClicked() == 0:
+ setVotesGatheredFavorite(getVotesGatheredFavorite() + getVotingPower(human()))
+ else:
+ setVotesGatheredPowerful(getVotesGatheredPowerful() + getVotingPower(human()))
+
+
+def voteHumanPopup():
+ favorite_txt = (
+ gc.getPlayer(getFavorite()).getName()
+ + " ("
+ + gc.getPlayer(getFavorite()).getCivilizationShortDescription(0)
+ + ")"
+ )
+ powerful_txt = (
+ gc.getPlayer(getPowerful()).getName()
+ + " ("
+ + gc.getPlayer(getPowerful()).getCivilizationShortDescription(0)
+ + ")"
+ )
+ event_popup(
+ 7618,
+ text("TXT_KEY_CRUSADE_VOTE_POPUP"),
+ text("TXT_KEY_CRUSADE_VOTE"),
+ [favorite_txt, powerful_txt],
+ )
+
+
+@popup_handler(7619)
+def HumanDeviate(playerID, netUserData, popupReturn):
+ if popupReturn.getButtonClicked() == 0:
+ player().changeGold(-player().getGold() / 3)
+ setLeader(human())
+ setCrusadePower(getCrusadePower() / 2)
+ deviateNewTargetPopup()
+ else:
+ setTarget(*CITIES[City.JERUSALEM])
+ startCrusade()
+
+
+def deviateHumanPopup():
+ iCost = gc.getPlayer(human()).getGold() / 3
+ sString = (
+ text("TXT_KEY_CRUSADE_RICHEST")
+ + text("TXT_KEY_CRUSADE_COST")
+ + " "
+ + str(iCost)
+ + " "
+ + text("TXT_KEY_CRUSADE_GOLD")
+ + gc.getPlayer(getLeader()).getName()
+ + " "
+ + text("TXT_KEY_CRUSADE_CURRENT_LEADER")
+ )
+ event_popup(
+ 7619,
+ text("TXT_KEY_CRUSADE_DEVIATE"),
+ sString,
+ [text("TXT_KEY_CRUSADE_DECIDE_WEALTH"), text("TXT_KEY_CRUSADE_DECIDE_FAITH")],
+ )
+
+
+@popup_handler(7620)
+def ChoseNewCrusadeTarget(playerID, netUserData, popupReturn):
+ iDecision = popupReturn.getButtonClicked()
+ if iDecision == 0:
+ setTarget(*CITIES[City.JERUSALEM])
+ startCrusade()
+ return
+ iTargets = 0
+ for i in civilizations().majors().ids():
+ if getIsTarget(i):
+ iTargets += 1
+ if iTargets == iDecision:
+ pTargetCity = gc.getPlayer(i).getCapitalCity()
+ setTarget(pTargetCity.getX(), pTargetCity.getY())
+ iDecision = -2
+
+ startCrusade()
+
+
+def deviateNewTargetPopup():
+ lTargetList = []
+ lTargetList.append(
+ gc.getMap().plot(*CITIES[City.JERUSALEM]).getPlotCity().getName()
+ + " ("
+ + gc.getPlayer(
+ gc.getMap().plot(*CITIES[City.JERUSALEM]).getPlotCity().getOwner()
+ ).getCivilizationAdjective(0)
+ + ")"
+ )
+ for iPlayer in civilizations().majors().ids():
+ pPlayer = gc.getPlayer(iPlayer)
+ if (
+ iPlayer == Civ.POPE
+ or pPlayer.getStateReligion() == Religion.CATHOLICISM
+ or not pPlayer.isAlive()
+ ):
+ setIsTarget(iPlayer, False)
+ else:
+ setIsTarget(iPlayer, True)
+ lTargetList.append(
+ pPlayer.getCapitalCity().getName()
+ + " ("
+ + pPlayer.getCivilizationAdjective(0)
+ + ")"
+ )
+ event_popup(7620, text("TXT_KEY_CRUSADE_CORRUPT"), text("TXT_KEY_CRUSADE_TARGET"), lTargetList)
+
+
+@popup_handler(7621)
+def event7621(playerID, netUserData, popupReturn):
+ pass
+
+
+def underCrusadeAttackPopup(sCityName, iLeader):
+ sText = text(
+ "TXT_KEY_CRUSADE_UNDER_ATTACK1",
+ gc.getPlayer(iLeader).getCivilizationAdjective(0),
+ gc.getPlayer(iLeader).getName(),
+ sCityName,
+ )
+ event_popup(
+ 7621, text("TXT_KEY_CRUSADE_UNDER_ATTACK"), sText, [text("TXT_KEY_CRUSADE_PREPARE")]
+ )
+
+
+@handler("religionFounded")
+def endCrusades(iReligion, iFounder):
+ # 3Miro: end Crusades for the Holy Land after the Reformation
+ if iReligion == Religion.PROTESTANTISM:
+ for i in range(NUM_CRUSADES):
+ if getCrusadeInit(i) < 0:
+ setCrusadeInit(i, 0)
+ # Absinthe: reset sent unit counter after the Crusades are over (so it won't give Company benefits forever based on the last one)
+ for iPlayer in civilizations().majors().ids():
+ setNumUnitsSent(iPlayer, 0)
+
+
+@handler("BeginGameTurn")
+def checkTurn(iGameTurn):
+ if getCrusadeToReturn() > -1:
+ freeCrusaders(getCrusadeToReturn())
+ setCrusadeToReturn(-1)
+
+ # Absinthe: crusade date - 5 means the exact time for the arrival
+ if iGameTurn == year(1096) - 5: # First Crusade arrives in 1096AD
+ setCrusadeInit(0, -1)
+ elif (
+ iGameTurn >= year(1147) - 7 and getCrusadeInit(0) > 0 and getCrusadeInit(1) == -2
+ ): # Crusade of 1147AD, little earlier (need to be more than 9 turns between crusades)
+ setCrusadeInit(1, -1) # turn 176
+ elif (
+ iGameTurn >= year(1187) - 8 and getCrusadeInit(1) > 0 and getCrusadeInit(2) == -2
+ ): # Crusade of 1187AD, little earlier (need to be more than 9 turns between crusades)
+ setCrusadeInit(2, -1) # turn 187
+ elif (
+ iGameTurn >= year(1202) - 4 and getCrusadeInit(2) > 0 and getCrusadeInit(3) == -2
+ ): # Crusade of 1202AD, little later (need to be more than 9 turns between crusades)
+ setCrusadeInit(3, -1) # turn 197
+ elif (
+ iGameTurn >= year(1229) - 3 and getCrusadeInit(3) > 0 and getCrusadeInit(4) == -2
+ ): # Crusade of 1229AD, little later (need to be more than 9 turns between crusades)
+ setCrusadeInit(4, -1) # turn 207
+ elif (
+ iGameTurn >= year(1271) - 5 and getCrusadeInit(4) > 0 and getCrusadeInit(5) == -2
+ ): # Crusade of 1270AD
+ setCrusadeInit(5, -1) # turn 219
+
+ # Start of Defensive Crusades: indulgences for the Reconquista given by the Catholic Church in 1000AD
+ if iGameTurn == year(1000):
+ setDefensiveCrusadeEnabled(True)
+
+ # End of Defensive Crusades: no more defensive crusades after Protestantism is founded
+ if isDefensiveCrusadeEnabled():
+ if gc.getGame().isReligionFounded(Religion.PROTESTANTISM):
+ setDefensiveCrusadeEnabled(False)
+
+ if isDefensiveCrusadeEnabled():
+ doDefensiveCrusade(iGameTurn)
+
+ checkToStart(iGameTurn)
+
+ iActiveCrusade = getActiveCrusade(iGameTurn)
+ if iActiveCrusade > -1:
+ iStartDate = getCrusadeInit(iActiveCrusade)
+ if iStartDate == iGameTurn:
+ doParticipation(iGameTurn)
+
+ elif iStartDate + 1 == iGameTurn:
+ computeVotingPower(iGameTurn)
+ setCrusaders()
+ for i in range(8):
+ setSelectedUnit(i, 0)
+ for iPlayer in civilizations().majors().ids():
+ # Absinthe: first we set all civs' unit counter to 0, then send the new round of units
+ setNumUnitsSent(iPlayer, 0)
+ if getVotingPower(iPlayer) > 0:
+ sendUnits(iPlayer)
+ if not anyParticipate():
+ return
+ chooseCandidates(iGameTurn)
+ voteForCandidatesAI()
+ voteForCandidatesHuman()
+
+ elif iStartDate + 2 == iGameTurn:
+ if not anyParticipate():
+ return
+ selectVoteWinner()
+ decideTheRichestCatholic(iActiveCrusade)
+ if getRichestCatholic() == human():
+ decideDeviateHuman()
+ else:
+ decideDeviateAI()
+
+ elif iStartDate + 5 == iGameTurn:
+ if not anyParticipate():
+ return
+ crusadeArrival(iActiveCrusade)
+
+ elif iStartDate + 8 == iGameTurn:
+ iLeader = getLeader()
+ setCrusadeToReturn(iLeader)
+ returnCrusaders()
+
+
+def checkToStart(iGameTurn):
+ # if Jerusalem is Islamic or Pagan, Crusade has been initialized and it has been at least 5 turns since the last crusade and there are any Catholics, begin crusade
+ pJPlot = gc.getMap().plot(*CITIES[City.JERUSALEM])
+ for i in range(NUM_CRUSADES): # check the Crusades
+ if getCrusadeInit(i) == -1: # if this one is to start
+ if (
+ pJPlot.isCity() and anyCatholic()
+ ): # if there is Jerusalem and there are any Catholics
+ # Sedna17 -- allowing crusades against independent Jerusalem
+ iVictim = pJPlot.getPlotCity().getOwner()
+ if isOrMasterChristian(iVictim):
+ break
+ if i == 0 or (
+ getCrusadeInit(i - 1) > -1 and getCrusadeInit(i - 1) + 9 < iGameTurn
+ ):
+ setCrusadeInit(i, iGameTurn)
+
+
+def anyCatholic():
+ return civilizations().main().any(lambda c: c.has_state_religion(Religion.CATHOLICISM))
+
+
+def anyParticipate():
+ for i in civilizations().main().ids():
+ if getVotingPower(i) > 0:
+ return True
+ return False
+
+
+@popup_handler(7616)
+def CrusadeInitVoteEvent(playerID, netUserData, popupReturn):
+ iHuman = human()
+ if popupReturn.getButtonClicked() == 0:
+ setParticipate(True)
+ gc.getPlayer(iHuman).setIsCrusader(True)
+ elif popupReturn.getButtonClicked() == 1 or popupReturn.getButtonClicked() == 2:
+ setParticipate(False)
+ pPlayer = gc.getPlayer(iHuman)
+ pPlayer.setIsCrusader(False)
+ pPlayer.changeFaith(-min(5, pPlayer.getFaith()))
+ message(
+ iHuman, text("TXT_KEY_CRUSADE_DENY_FAITH"), force=True, color=MessageData.LIGHT_RED
+ )
+ gc.getPlayer(Civ.POPE).AI_changeMemoryCount(iHuman, MemoryTypes.MEMORY_REJECTED_DEMAND, 2)
+ # Absinthe: some units from Chivalric Orders might leave you nevertheless
+ for pUnit in units.owner(iHuman).entities():
+ iUnitType = pUnit.getUnitType()
+ if iUnitType in [
+ Unit.KNIGHT_OF_ST_JOHNS,
+ Unit.TEMPLAR,
+ Unit.TEUTONIC,
+ ]:
+ pPlot = gc.getMap().plot(pUnit.getX(), pUnit.getY())
+ random_value = percentage()
+ # Absinthe: less chance for units currently on ships
+ if pUnit.isCargo():
+ random_value -= 10
+ if pPlot.isCity():
+ if getNumDefendersAtPlot(pPlot) > 3:
+ if random_value < 50:
+ addSelectedUnit(unitCrusadeCategory(iUnitType))
+ message(
+ iHuman,
+ text("TXT_KEY_CRUSADE_DENY_LEAVE_ANYWAY"),
+ button=gc.getUnitInfo(iUnitType).getButton(),
+ color=MessageData.LIGHT_RED,
+ location=pUnit,
+ )
+ pUnit.kill(0, -1)
+ elif getNumDefendersAtPlot(pPlot) > 1:
+ if random_value < 10:
+ addSelectedUnit(unitCrusadeCategory(iUnitType))
+ message(
+ iHuman,
+ text("TXT_KEY_CRUSADE_DENY_LEAVE_ANYWAY"),
+ button=gc.getUnitInfo(iUnitType).getButton(),
+ color=MessageData.LIGHT_RED,
+ location=pUnit,
+ )
+ pUnit.kill(0, -1)
+ elif random_value < 30:
+ addSelectedUnit(unitCrusadeCategory(iUnitType))
+ message(
+ iHuman,
+ text("TXT_KEY_CRUSADE_DENY_LEAVE_ANYWAY"),
+ button=gc.getUnitInfo(iUnitType).getButton(),
+ color=MessageData.LIGHT_RED,
+ location=pUnit,
+ )
+ pUnit.kill(0, -1)
+ # Absinthe: 3rd option, only if you have enough money to make a contribution to the Crusade instead of sending units
+ else:
+ setParticipate(False)
+ pPlayer = gc.getPlayer(iHuman)
+ pPlayer.setIsCrusader(False)
+ pPope = gc.getPlayer(Civ.POPE)
+ iActiveCrusade = getActiveCrusade(turn())
+ iBribe = 200 + 50 * iActiveCrusade
+ pPope.changeGold(iBribe)
+ pPlayer.changeGold(-iBribe)
+ gc.getPlayer(Civ.POPE).AI_changeMemoryCount(iHuman, MemoryTypes.MEMORY_REJECTED_DEMAND, 1)
+
+
+def doParticipation(iGameTurn):
+ iHuman = human()
+ if civilization(iHuman).date.birth < iGameTurn:
+ pHuman = gc.getPlayer(iHuman)
+ if pHuman.getStateReligion() != Religion.CATHOLICISM:
+ setParticipate(False)
+ message(
+ iHuman, text("TXT_KEY_CRUSADE_CALLED"), force=True, color=MessageData.LIGHT_RED
+ )
+ else:
+ initVotePopup()
+ else:
+ setParticipate(False)
+
+
+def chooseCandidates(iGameTurn):
+ bFound = False
+ iFavorite = 0
+ iFavor = 0
+ for i in civilizations().main().ids():
+ if getVotingPower(i) > 0:
+ if bFound:
+ iNFavor = gc.getRelationTowards(Civ.POPE, i)
+ if iNFavor > iFavor:
+ iNFavor = iFavor
+ iFavorite = i
+ else:
+ iFavor = gc.getRelationTowards(Civ.POPE, i)
+ iFavorite = i
+ bFound = True
+ setFavorite(iFavorite)
+
+ iPowerful = iFavorite
+ iPower = getVotingPower(iPowerful)
+
+ for i in civilizations().main().ids():
+ if getVotingPower(i) > iPower or (iPowerful == iFavorite and getVotingPower(i) > 0):
+ iPowerful = i
+ iPower = getVotingPower(iPowerful)
+
+ if iPowerful == iFavorite:
+ setPowerful(-1)
+ else:
+ setPowerful(iPowerful)
+
+
+def computeVotingPower(iGameTurn):
+ iTmJerusalem = gc.getPlayer(
+ gc.getMap().plot(*CITIES[City.JERUSALEM]).getPlotCity().getOwner()
+ ).getTeam()
+ for iPlayer in civilizations().majors().ids():
+ pPlayer = gc.getPlayer(iPlayer)
+ if (
+ civilization(iPlayer).date.birth > iGameTurn
+ or not pPlayer.isAlive()
+ or pPlayer.getStateReligion() != Religion.CATHOLICISM
+ or gc.getTeam(pPlayer.getTeam()).isVassal(iTmJerusalem)
+ ):
+ setVotingPower(iPlayer, 0)
+ else:
+ # We use the (similarly named) getVotingPower from CvPlayer.cpp to determine a vote value for a given State Religion, but it's kinda strange
+ # Will leave it this way for now, but might be a good idea to improve it at some point
+ setVotingPower(iPlayer, pPlayer.getVotingPower(Religion.CATHOLICISM))
+
+ # No votes from the human player if he/she won't participate (AI civs will always participate)
+ if not getParticipate():
+ setVotingPower(human(), 0)
+
+ # The Pope has more votes (Rome is small anyway)
+ setVotingPower(Civ.POPE, getVotingPower(Civ.POPE) * (5 / 4))
+
+ iPower = 0
+ for iPlayer in civilizations().majors().ids():
+ iPower += getVotingPower(iPlayer)
+
+ setCrusadePower(iPower)
+ # Note that voting power is increased after this (but before the actual vote) for each sent unit by 2
+
+
+def setCrusaders():
+ for iPlayer in civilizations().majors().ids():
+ if not iPlayer == human() and getVotingPower(iPlayer) > 0:
+ gc.getPlayer(iPlayer).setIsCrusader(True)
+
+
+def sendUnits(iPlayer):
+ pPlayer = gc.getPlayer(iPlayer)
+ iNumUnits = pPlayer.getNumUnits()
+ if civilization(iPlayer).date.birth + 10 > turn(): # in the first 10 turns
+ if iNumUnits < 10:
+ iMaxToSend = 0
+ else:
+ iMaxToSend = 1
+ elif civilization(iPlayer).date.birth + 25 > turn(): # between turn 11-25
+ iMaxToSend = min(10, max(1, (5 * iNumUnits) / 50))
+ else:
+ iMaxToSend = min(10, max(1, (5 * iNumUnits) / 35)) # after turn 25
+ iCrusadersSend = 0
+ if iMaxToSend > 0:
+ # Absinthe: a randomized list of all units of the civ
+ lUnits = [pPlayer.getUnit(i) for i in range(iNumUnits)]
+ random.shuffle(lUnits)
+ for pUnit in lUnits:
+ # Absinthe: check only for combat units and ignore naval units
+ if pUnit.baseCombatStr() > 0 and pUnit.getDomainType() != DomainTypes.DOMAIN_SEA:
+ # Absinthe: mercenaries and leaders (units with attached Great Generals) won't go
+ if not pUnit.isHasPromotion(Promotion.MERC) and not pUnit.isHasPromotion(
+ Promotion.LEADER
+ ):
+ iCrusadeCategory = unitCrusadeCategory(pUnit.getUnitType())
+ pPlot = gc.getMap().plot(pUnit.getX(), pUnit.getY())
+ iRandNum = percentage()
+ # Absinthe: much bigger chance for special Crusader units and Knights
+ if iCrusadeCategory < 4:
+ if pPlot.isCity():
+ if getNumDefendersAtPlot(pPlot) > 3:
+ if iRandNum < 80:
+ iCrusadersSend += 1
+ sendUnit(pUnit)
+ elif getNumDefendersAtPlot(pPlot) > 1:
+ if iRandNum < 40:
+ iCrusadersSend += 1
+ sendUnit(pUnit)
+ else:
+ # Absinthe: much less chance for units currently on ships
+ if pUnit.isCargo():
+ if iRandNum < 40:
+ iCrusadersSend += 1
+ sendUnit(pUnit)
+ else:
+ if iRandNum < 80:
+ iCrusadersSend += 1
+ sendUnit(pUnit)
+ else:
+ if pPlot.isCity():
+ if getNumDefendersAtPlot(pPlot) > 2:
+ if iRandNum < (unitProbability(pUnit.getUnitType()) - 10):
+ iCrusadersSend += 1
+ sendUnit(pUnit)
+ else:
+ # Absinthe: much less chance for units currently on ships
+ if pUnit.isCargo():
+ if iRandNum < (unitProbability(pUnit.getUnitType()) - 10) / 2:
+ iCrusadersSend += 1
+ sendUnit(pUnit)
+ else:
+ if iRandNum < (unitProbability(pUnit.getUnitType()) - 10):
+ iCrusadersSend += 1
+ sendUnit(pUnit)
+ if iCrusadersSend == iMaxToSend:
+ return
+ # Absinthe: extra chance for some random units, if we didn't fill the quota
+ for i in range(15):
+ iNumUnits = (
+ pPlayer.getNumUnits()
+ ) # we have to recalculate each time, as some units might have gone on the Crusade already
+ iRandUnit = rand(iNumUnits)
+ pUnit = pPlayer.getUnit(iRandUnit)
+ # Absinthe: check only for combat units and ignore naval units
+ if pUnit.baseCombatStr() > 0 and pUnit.getDomainType() != 0:
+ # Absinthe: mercenaries and leaders (units with attached Great Generals) won't go
+ if not pUnit.isHasPromotion(Promotion.MERC) and not pUnit.isHasPromotion(
+ Promotion.LEADER
+ ):
+ pPlot = gc.getMap().plot(pUnit.getX(), pUnit.getY())
+ if pPlot.isCity():
+ if getNumDefendersAtPlot(pPlot) > 2:
+ if percentage_chance(
+ unitProbability(pUnit.getUnitType()), strict=True
+ ):
+ iCrusadersSend += 1
+ sendUnit(pUnit)
+ else:
+ # Absinthe: much less chance for units currently on ships
+ if pUnit.isCargo() and percentage_chance(
+ unitProbability(pUnit.getUnitType() / 2), strict=True
+ ):
+ iCrusadersSend += 1
+ sendUnit(pUnit)
+ elif percentage_chance(unitProbability(pUnit.getUnitType()), strict=True):
+ iCrusadersSend += 1
+ sendUnit(pUnit)
+ if iCrusadersSend == iMaxToSend:
+ return
+
+
+def getNumDefendersAtPlot(pPlot):
+ iOwner = pPlot.getOwner()
+ if iOwner < 0:
+ return 0
+ iNumUnits = pPlot.getNumUnits()
+ iDefenders = 0
+ for i in range(iNumUnits):
+ pUnit = pPlot.getUnit(i)
+ if pUnit.getOwner() == iOwner:
+ if pUnit.baseCombatStr() > 0 and pUnit.getDomainType() != DomainTypes.DOMAIN_SEA:
+ iDefenders += 1
+ return iDefenders
+
+
+def sendUnit(pUnit):
+ iOwner = pUnit.getOwner()
+ addSelectedUnit(unitCrusadeCategory(pUnit.getUnitType()))
+ setVotingPower(iOwner, getVotingPower(iOwner) + 2)
+ changeNumUnitsSent(iOwner, 1) # Absinthe: counter for sent units per civ
+ # Absinthe: faith point boost for each sent unit (might get some more on successful Crusade):
+ player(iOwner).changeFaith(1)
+ message_if_human(
+ human(),
+ text("TXT_KEY_CRUSADE_LEAVE") + " " + pUnit.getName(),
+ sound="AS2D_BUILD_CATHOLIC",
+ color=MessageData.ORANGE,
+ )
+ pUnit.kill(0, -1)
+
+
+def unitProbability(iUnitType):
+ if iUnitType in [
+ Unit.ARCHER,
+ Unit.CROSSBOWMAN,
+ Unit.ARBALEST,
+ Unit.GENOA_BALESTRIERI,
+ Unit.LONGBOWMAN,
+ Unit.ENGLISH_LONGBOWMAN,
+ Unit.PORTUGAL_FOOT_KNIGHT,
+ ]:
+ return 10
+ if iUnitType in [
+ Unit.LANCER,
+ Unit.BULGARIAN_KONNIK,
+ Unit.CORDOBAN_BERBER,
+ Unit.HEAVY_LANCER,
+ Unit.HUNGARIAN_HUSZAR,
+ Unit.ARABIA_GHAZI,
+ Unit.BYZANTINE_CATAPHRACT,
+ Unit.KIEV_DRUZHINA,
+ Unit.KNIGHT,
+ Unit.MOSCOW_BOYAR,
+ Unit.BURGUNDIAN_PALADIN,
+ ]:
+ return 70
+ if iUnitType in [
+ Unit.TEMPLAR,
+ Unit.TEUTONIC,
+ Unit.KNIGHT_OF_ST_JOHNS,
+ Unit.CALATRAVA_KNIGHT,
+ Unit.DRAGON_KNIGHT,
+ ]:
+ return 90
+ if (
+ iUnitType <= Unit.ISLAMIC_MISSIONARY or iUnitType >= Unit.WORKBOAT
+ ): # Workers, Executives, Missionaries, Sea Units and Mercenaries do not go
+ return -1
+ return 50
+
+
+def unitCrusadeCategory(iUnitType):
+ if iUnitType == Unit.TEMPLAR:
+ return 0
+ if iUnitType == Unit.TEUTONIC:
+ return 1
+ if iUnitType in [
+ Unit.KNIGHT_OF_ST_JOHNS,
+ Unit.CALATRAVA_KNIGHT,
+ Unit.DRAGON_KNIGHT,
+ ]:
+ return 2
+ if iUnitType in [
+ Unit.KNIGHT,
+ Unit.MOSCOW_BOYAR,
+ Unit.BURGUNDIAN_PALADIN,
+ ]:
+ return 3
+ if iUnitType in [
+ Unit.HEAVY_LANCER,
+ Unit.HUNGARIAN_HUSZAR,
+ Unit.ARABIA_GHAZI,
+ Unit.BYZANTINE_CATAPHRACT,
+ Unit.KIEV_DRUZHINA,
+ ]:
+ return 4
+ if iUnitType in [
+ Unit.LANCER,
+ Unit.BULGARIAN_KONNIK,
+ Unit.CORDOBAN_BERBER,
+ ]:
+ return 5
+ if iUnitType in [Unit.CATAPULT, Unit.TREBUCHET]:
+ return 6
+ return 7
+
+
+def voteForCandidatesAI():
+ if getPowerful() == -1:
+ setLeader(getFavorite())
+ if getParticipate():
+ informLeaderPopup()
+ elif player().isExisting():
+ message(
+ human(),
+ gc.getPlayer(getLeader()).getName() + text("TXT_KEY_CRUSADE_LEAD"),
+ force=True,
+ color=MessageData.LIGHT_RED,
+ )
+ return
+
+ iFavorite = getFavorite()
+ iPowerful = getPowerful()
+ if iFavorite == human():
+ iFavorVotes = 0
+ else:
+ iFavorVotes = getVotingPower(iFavorite)
+ if iPowerful == human():
+ iPowerVotes = 0
+ else:
+ iPowerVotes = getVotingPower(iPowerful)
+
+ for civ in civilizations().majors().ai().drop(iFavorite, iPowerful).ids():
+ iVotes = getVotingPower(civ)
+ if iVotes > 0:
+ if gc.getRelationTowards(civ, iFavorite) > gc.getRelationTowards(civ, iPowerful):
+ iFavorVotes += iVotes
+ else:
+ iPowerVotes += iVotes
+
+ setVotesGatheredFavorite(iFavorVotes)
+ setVotesGatheredPowerful(iPowerVotes)
+
+
+def voteForCandidatesHuman():
+ if getParticipate() and not getPowerful() == -1:
+ voteHumanPopup()
+
+
+def selectVoteWinner():
+ if getVotesGatheredPowerful() > getVotesGatheredFavorite():
+ setLeader(getPowerful())
+ else:
+ setLeader(getFavorite())
+
+ if getParticipate():
+ informLeaderPopup()
+ elif player().isExisting():
+ message(
+ human(),
+ gc.getPlayer(getLeader()).getName() + text("TXT_KEY_CRUSADE_LEAD"),
+ force=True,
+ color=MessageData.LIGHT_RED,
+ )
+
+ # not yet, check to see for deviations
+ # pJPlot = gc.getMap().plot(*CITIES[City.JERUSALEM])
+ # gc.getTeam( gc.getPlayer( getLeader() ) ).declareWar( pJPlot.getPlotCity().getOwner(), True, -1 )
+
+
+def decideTheRichestCatholic(iActiveCrusade):
+ # The First Crusade cannot be deviated
+ if iActiveCrusade == 0:
+ setRichestCatholic(-1)
+ return
+
+ iRichest = -1
+ iMoney = 0
+ # iPopeMoney = gc.getPlayer( Civ.POPE ).getGold()
+ for i in civilizations().main().ids():
+ if getVotingPower(i) > 0:
+ pPlayer = gc.getPlayer(i)
+ iPlayerMoney = pPlayer.getGold()
+ # if ( iPlayerMoney > iMoney and iPlayerMoney > iPopeMoney ):
+ if iPlayerMoney > iMoney:
+ iRichest = i
+ iMoney = iPlayerMoney
+
+ if iRichest != Civ.POPE:
+ setRichestCatholic(iRichest)
+ else:
+ setRichestCatholic(-1)
+
+
+def decideDeviateHuman():
+ deviateHumanPopup()
+
+
+def decideDeviateAI():
+ iRichest = getRichestCatholic()
+ bStolen = False
+ if iRichest in [Civ.VENECIA, Civ.GENOA]:
+ pByzantium = gc.getPlayer(Civ.BYZANTIUM)
+ if pByzantium.isAlive():
+ # Only if the potential attacker is not vassal of the target
+ iTeamByzantium = pByzantium.getTeam()
+ pRichest = gc.getPlayer(iRichest)
+ pTeamRichest = gc.getTeam(pRichest.getTeam())
+ if not pTeamRichest.isVassal(iTeamByzantium):
+ # Only if Byzantium holds Constantinople and not a vassal
+ pConstantinoplePlot = gc.getMap().plot(
+ *civilization(Civ.BYZANTIUM).location.capital
+ )
+ pConstantinopleCity = pConstantinoplePlot.getPlotCity()
+ iConstantinopleOwner = pConstantinopleCity.getOwner()
+ # should check if Constantinople is their capital city to be fully correct, but we can assume that's the case
+ bIsNotAVassal = not isAVassal(Civ.BYZANTIUM)
+ if iConstantinopleOwner == Civ.BYZANTIUM and bIsNotAVassal:
+ crusadeStolenAI(iRichest, Civ.BYZANTIUM)
+ bStolen = True
+ elif iRichest in [Civ.CASTILE, Civ.PORTUGAL, Civ.ARAGON]:
+ pCordoba = gc.getPlayer(Civ.CORDOBA)
+ if pCordoba.isAlive():
+ # Only if the potential attacker is not vassal of the target
+ iTeamCordoba = pCordoba.getTeam()
+ pRichest = gc.getPlayer(iRichest)
+ pTeamRichest = gc.getTeam(pRichest.getTeam())
+ if not pTeamRichest.isVassal(iTeamCordoba):
+ # Only if Cordoba is Muslim and not a vassal
+ bIsNotAVassal = not isAVassal(Civ.CORDOBA)
+ if pCordoba.getStateReligion() == Religion.ISLAM and bIsNotAVassal:
+ crusadeStolenAI(iRichest, Civ.CORDOBA)
+ bStolen = True
+ elif iRichest in [Civ.HUNGARY, Civ.POLAND, Civ.AUSTRIA]:
+ pTurkey = gc.getPlayer(Civ.OTTOMAN)
+ if pTurkey.isAlive():
+ # Only if the potential attacker is not vassal of the target
+ iTeamTurkey = pTurkey.getTeam()
+ pRichest = gc.getPlayer(iRichest)
+ pTeamRichest = gc.getTeam(pRichest.getTeam())
+ if not pTeamRichest.isVassal(iTeamTurkey):
+ # Only if the Ottomans are Muslim and not a vassal
+ bIsNotAVassal = not isAVassal(Civ.OTTOMAN)
+ if pTurkey.getStateReligion() == Religion.ISLAM and bIsNotAVassal:
+ crusadeStolenAI(iRichest, Civ.OTTOMAN)
+ bStolen = True
+
+ if not bStolen:
+ setTarget(*CITIES[City.JERUSALEM])
+
+ startCrusade()
+
+
+def crusadeStolenAI(iNewLeader, iNewTarget):
+ setLeader(iNewLeader)
+ pLeader = gc.getPlayer(iNewLeader)
+ if player().isExisting():
+ message(
+ human(),
+ pLeader.getName() + text("TXT_KEY_CRUSADE_DEVIATED"),
+ color=MessageData.LIGHT_RED,
+ )
+ # pLeader.setGold( pLeader.getGold() - gc.getPlayer( Civ.POPE ).getGold() / 3 )
+ # pLeader.setGold( gc.getPlayer( Civ.POPE ).getGold() / 4 )
+ pLeader.setGold(2 * pLeader.getGold() / 3)
+ pTarget = gc.getPlayer(iNewTarget).getCapitalCity()
+ setTarget(pTarget.getX(), pTarget.getY())
+ setCrusadePower(getCrusadePower() / 2)
+
+
+def startCrusade():
+ iHuman = human()
+ iLeader = getLeader()
+ iX, iY = getTargetPlot()
+ pTargetCity = gc.getMap().plot(iX, iY).getPlotCity()
+ iTargetPlayer = pTargetCity.getOwner()
+ # Absinthe: in case the Crusader civ has been destroyed
+ if not gc.getPlayer(iLeader).isAlive():
+ returnCrusaders()
+ return
+ # Target city can change ownership during the voting
+ if gc.getPlayer(iTargetPlayer).getStateReligion() == Religion.CATHOLICISM:
+ returnCrusaders()
+ return
+ # Absinthe: do not Crusade against themselves
+ if iTargetPlayer == iLeader:
+ returnCrusaders()
+ return
+ if iTargetPlayer == iHuman:
+ underCrusadeAttackPopup(pTargetCity.getName(), iLeader)
+ elif player().isExisting():
+ sCityName = lookupName(pTargetCity, Civ.POPE)
+ if sCityName == "Unknown":
+ sCityName = lookupName(pTargetCity, iLeader)
+ sText = text(
+ "TXT_KEY_CRUSADE_START",
+ gc.getPlayer(iLeader).getCivilizationAdjectiveKey(),
+ gc.getPlayer(iLeader).getName(),
+ gc.getPlayer(iTargetPlayer).getCivilizationAdjectiveKey(),
+ sCityName,
+ )
+ message(iHuman, sText, color=MessageData.LIGHT_RED)
+
+ # Absinthe: proper war declaration checks
+ teamLeader = gc.getTeam(gc.getPlayer(iLeader).getTeam())
+ iTeamTarget = gc.getPlayer(iTargetPlayer).getTeam()
+ if not teamLeader.isAtWar(iTeamTarget):
+ # Absinthe: add contact if they did not meet before
+ if not teamLeader.isHasMet(iTeamTarget):
+ teamLeader.meet(iTeamTarget, False)
+ if teamLeader.canDeclareWar(iTeamTarget):
+ teamLeader.declareWar(iTeamTarget, True, -1)
+ else:
+ # we cannot declare war to the current owner of the target city
+ returnCrusaders()
+ return
+
+
+def returnCrusaders():
+ setLeader(-1)
+ for i in civilizations().majors().ids():
+ gc.getPlayer(i).setIsCrusader(False)
+
+
+def crusadeArrival(iActiveCrusade):
+ iTX, iTY = getTargetPlot()
+ iChosenX = -1
+ iChosenY = -1
+
+ # if the leader has been destroyed, cancel the Crusade
+ iLeader = getLeader()
+ if iLeader == -1 or not gc.getPlayer(iLeader).isAlive():
+ returnCrusaders()
+ return
+
+ # if the target is Jerusalem, and in the mean time it has been captured by an Orthodox or Catholic player (or the owner of Jerusalem converted to a Christian religion), cancel the Crusade
+ if (iTX, iTY) == CITIES[City.JERUSALEM]:
+ pPlot = gc.getMap().plot(*CITIES[City.JERUSALEM])
+ if pPlot.isCity():
+ iVictim = pPlot.getPlotCity().getOwner()
+ if iVictim < civilizations().majors().len():
+ iReligion = gc.getPlayer(iVictim).getStateReligion()
+ if iReligion in [Religion.CATHOLICISM, Religion.ORTHODOXY]:
+ return
+
+ # if not at war with the owner of the city, declare war
+ pPlot = gc.getMap().plot(iTX, iTY)
+ if pPlot.isCity():
+ iVictim = pPlot.getPlotCity().getOwner()
+ if iVictim != iLeader and gc.getPlayer(iVictim).getStateReligion() != Religion.CATHOLICISM:
+ teamLeader = gc.getTeam(gc.getPlayer(iLeader).getTeam())
+ iTeamVictim = gc.getPlayer(iVictim).getTeam()
+ if not teamLeader.isAtWar(iTeamVictim):
+ # Absinthe: add contact if they did not meet before
+ if not teamLeader.isHasMet(iTeamVictim):
+ teamLeader.meet(iTeamVictim, False)
+ if teamLeader.canDeclareWar(iTeamVictim):
+ teamLeader.declareWar(iTeamVictim, False, -1)
+ else:
+ # we cannot declare war to the current owner of the target city
+ returnCrusaders()
+ return
+
+ lFreeLandPlots = []
+ lLandPlots = []
+ for plot in (
+ plots.surrounding((iTX, iTY))
+ .filter(lambda p: (p.isHills() or p.isFlatlands()) and not p.isCity())
+ .entities()
+ ):
+ lLandPlots.append(location(plot))
+ if plot.getNumUnits() == 0:
+ lFreeLandPlots.append(location(plot))
+ # Absinthe: we try to spawn the army west from the target city (preferably northwest), or at least on as low x coordinates as possible
+ # works great both for Jerusalem (try not to spawn across the Jordan river) and for Constantinople (European side, where the actual city is located)
+ # also better for most cities in the Levant and in Egypt, and doesn't really matter for the rest
+ if lFreeLandPlots:
+ iChosenX = 200
+ iChosenY = 200
+ for tFreeLandPlot in lFreeLandPlots:
+ if tFreeLandPlot[0] < iChosenX:
+ iChosenX = tFreeLandPlot[0]
+ iChosenY = tFreeLandPlot[1]
+ elif tFreeLandPlot[0] == iChosenX:
+ if tFreeLandPlot[0] > iChosenY:
+ iChosenY = tFreeLandPlot[1]
+ elif lLandPlots:
+ iChosenX = 200
+ iChosenY = 200
+ for tLandPlot in lLandPlots:
+ if tLandPlot[0] < iChosenX:
+ iChosenX = tLandPlot[0]
+ iChosenY = tLandPlot[1]
+ elif tLandPlot[0] == iChosenX:
+ if tLandPlot[0] > iChosenY:
+ iChosenY = tLandPlot[1]
+ pPlot = gc.getMap().plot(iChosenX, iChosenY)
+ for i in range(pPlot.getNumUnits()):
+ pPlot.getUnit(0).kill(False, Civ.BARBARIAN)
+
+ # Absinthe: if a valid plot is found, make the units and send a message about the arrival to the human player
+ if (iChosenX, iChosenY) != (-1, -1):
+ crusadeMakeUnits((iChosenX, iChosenY), iActiveCrusade)
+ if human() == iLeader:
+ pTargetCity = gc.getMap().plot(iTX, iTY).getPlotCity()
+ sCityName = lookupName(pTargetCity, Civ.POPE)
+ if sCityName == "Unknown":
+ sCityName = lookupName(pTargetCity, iLeader)
+ message(
+ human(),
+ text("TXT_KEY_CRUSADE_ARRIVAL", sCityName) + "!",
+ color=MessageData.GREEN,
+ location=(iChosenX, iChosenY),
+ )
+ else:
+ returnCrusaders()
+
+
+def crusadeMakeUnits(tPlot, iActiveCrusade):
+ iLeader = getLeader()
+ teamLeader = gc.getTeam(gc.getPlayer(iLeader).getTeam())
+ iTX, iTY = getTargetPlot()
+ # if the target is Jerusalem
+ if (iTX, iTY) == CITIES[City.JERUSALEM]:
+ iRougeModifier = 100
+ # human player should always face powerful units when defending Jerusalem
+ iHuman = human()
+ pPlot = gc.getMap().plot(*CITIES[City.JERUSALEM])
+ iVictim = pPlot.getPlotCity().getOwner()
+ if teamLeader.isHasTech(Technology.CHIVALRY) or iVictim == iHuman:
+ make_crusade_unit(iLeader, Unit.BURGUNDIAN_PALADIN, tPlot, iActiveCrusade)
+ make_crusade_unit(iLeader, Unit.TEMPLAR, tPlot, iActiveCrusade)
+ make_crusade_unit(iLeader, Unit.TEUTONIC, tPlot, iActiveCrusade)
+ make_crusade_unit(iLeader, Unit.KNIGHT_OF_ST_JOHNS, tPlot, iActiveCrusade)
+ make_crusade_unit(iLeader, Unit.GUISARME, tPlot, iActiveCrusade)
+ make_crusade_unit(iLeader, Unit.CATAPULT, tPlot, iActiveCrusade)
+ else:
+ make_crusade_units(iLeader, Unit.HEAVY_LANCER, tPlot, iActiveCrusade, 2)
+ make_crusade_unit(iLeader, Unit.LANCER, tPlot, iActiveCrusade)
+ make_crusade_unit(iLeader, Unit.LONG_SWORDSMAN, tPlot, iActiveCrusade)
+ make_crusade_unit(iLeader, Unit.SPEARMAN, tPlot, iActiveCrusade)
+ make_crusade_unit(iLeader, Unit.TREBUCHET, tPlot, iActiveCrusade)
+ # there are way too many generic units in most Crusades:
+ if getSelectedUnit(7) > 1:
+ iReducedNumber = (
+ getSelectedUnit(7) * 6 / 10
+ ) # note that this is before the specific Crusade reduction
+ setSelectedUnit(7, iReducedNumber)
+ # if the Crusade was derailed
+ else:
+ iRougeModifier = 200
+ if teamLeader.isHasTech(Technology.CHIVALRY):
+ make_crusade_unit(iLeader, Unit.KNIGHT, tPlot, iActiveCrusade)
+ make_crusade_unit(iLeader, Unit.TEUTONIC, tPlot, iActiveCrusade)
+ make_crusade_unit(iLeader, Unit.LONG_SWORDSMAN, tPlot, iActiveCrusade)
+ make_crusade_unit(iLeader, Unit.GUISARME, tPlot, iActiveCrusade)
+ make_crusade_unit(iLeader, Unit.CATAPULT, tPlot, iActiveCrusade)
+ else:
+ make_crusade_unit(iLeader, Unit.HEAVY_LANCER, tPlot, iActiveCrusade)
+ make_crusade_unit(iLeader, Unit.LANCER, tPlot, iActiveCrusade)
+ make_crusade_unit(iLeader, Unit.LONG_SWORDSMAN, tPlot, iActiveCrusade)
+ make_crusade_unit(iLeader, Unit.SPEARMAN, tPlot, iActiveCrusade)
+ make_crusade_unit(iLeader, Unit.TREBUCHET, tPlot, iActiveCrusade)
+ # there are way too many generic units in most Crusades:
+ if getSelectedUnit(7) > 1:
+ iReducedNumber = (
+ getSelectedUnit(7) * 8 / 10
+ ) # note that this is before the specific Crusade reduction
+ setSelectedUnit(7, iReducedNumber)
+
+ # Absinthe: not all units should arrive near Jerusalem
+ # later Crusades have more units in the pool, so they should have bigger reduction
+ iHuman = human()
+ pPlot = gc.getMap().plot(*CITIES[City.JERUSALEM])
+ iVictim = pPlot.getPlotCity().getOwner()
+ # Absinthe: this reduction is very significant for an AI-controlled Jerusalem, but Crusades should remain an increasing threat to the human player
+ if iVictim != iHuman:
+ if iActiveCrusade == 0:
+ iRougeModifier *= 7 / 5
+ elif iActiveCrusade == 1:
+ iRougeModifier *= 8 / 5
+ elif iActiveCrusade == 2:
+ iRougeModifier *= 9 / 5
+ elif iActiveCrusade == 3:
+ iRougeModifier *= 10 / 5
+ elif iActiveCrusade == 4:
+ iRougeModifier *= 12 / 5
+ else:
+ iRougeModifier *= 14 / 5
+ else:
+ if iActiveCrusade == 0:
+ iRougeModifier *= 11 / 10
+ elif iActiveCrusade == 1:
+ iRougeModifier *= 5 / 5
+ elif iActiveCrusade == 2:
+ iRougeModifier *= 6 / 5
+ elif iActiveCrusade == 3:
+ iRougeModifier *= 7 / 5
+ elif iActiveCrusade == 4:
+ iRougeModifier *= 8 / 5
+ else:
+ iRougeModifier *= 8 / 5
+
+ if getSelectedUnit(0) > 0:
+ make_crusade_units(
+ iLeader,
+ Unit.TEMPLAR,
+ tPlot,
+ iActiveCrusade,
+ getSelectedUnit(0) * 100 / iRougeModifier,
+ )
+ if getSelectedUnit(1) > 0:
+ make_crusade_units(
+ iLeader,
+ Unit.TEUTONIC,
+ tPlot,
+ iActiveCrusade,
+ getSelectedUnit(1) * 100 / iRougeModifier,
+ )
+ if getSelectedUnit(2) > 0:
+ make_crusade_units(
+ iLeader,
+ Unit.KNIGHT_OF_ST_JOHNS,
+ tPlot,
+ iActiveCrusade,
+ getSelectedUnit(2) * 100 / iRougeModifier,
+ )
+ if getSelectedUnit(3) > 0:
+ iKnightNumber = getSelectedUnit(3) * 100 / iRougeModifier
+ if iLeader == Civ.BURGUNDY:
+ for i in range(0, iKnightNumber):
+ if percentage_chance(50, strict=True):
+ make_crusade_unit(iLeader, Unit.BURGUNDIAN_PALADIN, tPlot, iActiveCrusade)
+ else:
+ make_crusade_unit(iLeader, Unit.KNIGHT, tPlot, iActiveCrusade)
+ else:
+ for i in range(0, iKnightNumber):
+ if percentage_chance(20, strict=True):
+ make_crusade_unit(iLeader, Unit.BURGUNDIAN_PALADIN, tPlot, iActiveCrusade)
+ else:
+ make_crusade_unit(iLeader, Unit.KNIGHT, tPlot, iActiveCrusade)
+ if getSelectedUnit(4) > 0:
+ iLightCavNumber = getSelectedUnit(4) * 100 / iRougeModifier
+ if iLeader == Civ.HUNGARY:
+ for i in range(0, iLightCavNumber):
+ if percentage_chance(50, strict=True):
+ make_crusade_unit(iLeader, Unit.HUNGARIAN_HUSZAR, tPlot, iActiveCrusade)
+ else:
+ make_crusade_unit(iLeader, Unit.HEAVY_LANCER, tPlot, iActiveCrusade)
+ else:
+ make_crusade_units(iLeader, Unit.HEAVY_LANCER, tPlot, iActiveCrusade, iLightCavNumber)
+ if getSelectedUnit(5) > 0:
+ make_crusade_units(
+ iLeader,
+ Unit.LANCER,
+ tPlot,
+ iActiveCrusade,
+ getSelectedUnit(5) * 100 / iRougeModifier,
+ )
+ if getSelectedUnit(6) > 0:
+ iSiegeNumber = getSelectedUnit(6) * 100 / iRougeModifier
+ if iSiegeNumber > 2:
+ make_crusade_units(iLeader, Unit.CATAPULT, tPlot, iActiveCrusade, 2)
+ make_crusade_units(iLeader, Unit.TREBUCHET, tPlot, iActiveCrusade, iSiegeNumber - 2)
+ else:
+ make_crusade_units(iLeader, Unit.CATAPULT, tPlot, iActiveCrusade, iSiegeNumber)
+ if getSelectedUnit(7) > 0:
+ iFootNumber = getSelectedUnit(7) * 100 / iRougeModifier
+ for i in range(0, iFootNumber):
+ if percentage_chance(50, strict=True):
+ make_crusade_unit(iLeader, Unit.LONG_SWORDSMAN, tPlot, iActiveCrusade)
+ else:
+ make_crusade_unit(iLeader, Unit.GUISARME, tPlot, iActiveCrusade)
+
+
+def freeCrusaders(iPlayer):
+ # the majority of Crusader units will return from the Crusade, so the Crusading civ will have harder time keeping Jerusalem and the Levant
+ iPrevGameTurn = (
+ turn() - 1
+ ) # process for freeCrusaders was actually started in the previous turn, iActiveCrusade might have changed for the current turn
+ iActiveCrusade = getActiveCrusade(
+ iPrevGameTurn
+ ) # Absinthe: the Crusader units are called back before the next Crusade is initialized
+ iHuman = human()
+ for pUnit in units.owner(iPlayer).entities():
+ if pUnit.getMercID() == (
+ -5 - iActiveCrusade
+ ): # Absinthe: so this is a Crusader Unit of the active Crusade
+ pPlot = gc.getMap().plot(pUnit.getX(), pUnit.getY())
+ iOdds = 80
+ iCrusadeCategory = unitCrusadeCategory(pUnit.getUnitType())
+ if iCrusadeCategory < 3:
+ continue # Knightly Orders don't return
+ elif iCrusadeCategory == 7:
+ iOdds = 50 # leave some defenders
+ if pPlot.isCity():
+ if pPlot.getPlotCity().getOwner() == iPlayer:
+ iDefenders = getNumDefendersAtPlot(pPlot)
+ if iDefenders < 4:
+ iOdds = 20
+ if iDefenders == 0:
+ continue
+
+ if percentage_chance(iOdds, strict=True):
+ pUnit.kill(0, -1)
+ if iHuman == iPlayer:
+ message(
+ iHuman,
+ text("TXT_KEY_CRUSADE_CRUSADERS_RETURNING_HOME") + " " + pUnit.getName(),
+ color=MessageData.LIME,
+ )
+
+ # benefits for the other participants on Crusade return - Faith points, GG points, Relics
+ for iCiv in civilizations().main().ids():
+ pCiv = gc.getPlayer(iCiv)
+ if pCiv.getStateReligion() == Religion.CATHOLICISM and pCiv.isAlive():
+ iUnitNumber = getNumUnitsSent(iCiv)
+ if iUnitNumber > 0:
+ # the leader already got exp points through the Crusade it
+ if iCiv == iPlayer:
+ # if Jerusalem is held by a Christian civ (maybe some cities in the Levant should be enough) (maybe there should be a unit in the Levant from this Crusade)
+ pCity = gc.getMap().plot(*CITIES[City.JERUSALEM]).getPlotCity()
+ pPlayer = gc.getPlayer(pCity.getOwner())
+ if pPlayer.getStateReligion() == Religion.CATHOLICISM:
+ pCiv.changeFaith(1 * iUnitNumber)
+ # add relics in the capital
+ capital = pCiv.getCapitalCity()
+ iCapitalX = capital.getX()
+ iCapitalY = capital.getY()
+ pCiv.initUnit(
+ Unit.HOLY_RELIC,
+ iCapitalX,
+ iCapitalY,
+ UnitAITypes.NO_UNITAI,
+ DirectionTypes.DIRECTION_SOUTH,
+ )
+ if iCiv == iHuman:
+ message(
+ iHuman,
+ text("TXT_KEY_CRUSADE_NEW_RELIC"),
+ sound="AS2D_UNIT_BUILD_UNIQUE_UNIT",
+ button=gc.getUnitInfo(Unit.HOLY_RELIC).getButton(),
+ color=MessageData.GREEN,
+ location=(iCapitalX, iCapitalY),
+ )
+ if iUnitNumber > 3 and percentage_chance(80, strict=True):
+ pCiv.initUnit(
+ Unit.HOLY_RELIC,
+ iCapitalX,
+ iCapitalY,
+ UnitAITypes.NO_UNITAI,
+ DirectionTypes.DIRECTION_SOUTH,
+ )
+ if iUnitNumber > 9 and percentage_chance(80, strict=True):
+ pCiv.initUnit(
+ Unit.HOLY_RELIC,
+ iCapitalX,
+ iCapitalY,
+ UnitAITypes.NO_UNITAI,
+ DirectionTypes.DIRECTION_SOUTH,
+ )
+ # all other civs get experience points as well
+ else:
+ if iCiv == iHuman:
+ message(
+ iHuman,
+ text("TXT_KEY_CRUSADE_CRUSADERS_ARRIVED_HOME"),
+ color=MessageData.GREEN,
+ )
+ pCiv.changeCombatExperience(12 * iUnitNumber)
+ # if Jerusalem is held by a Christian civ (maybe some cities in the Levant should be enough) (maybe there should be a unit in the Levant from this Crusade)
+ pCity = gc.getMap().plot(*CITIES[City.JERUSALEM]).getPlotCity()
+ pPlayer = gc.getPlayer(pCity.getOwner())
+ if pPlayer.getStateReligion() == Religion.CATHOLICISM:
+ pCiv.changeFaith(1 * iUnitNumber)
+ # add relics in the capital
+ capital = pCiv.getCapitalCity()
+ iCapitalX = capital.getX()
+ iCapitalY = capital.getY()
+ # safety check, game crashes if it wants to create a unit in a non-existing city
+ if capital.getName():
+ if percentage_chance(80, strict=True):
+ pCiv.initUnit(
+ Unit.HOLY_RELIC,
+ iCapitalX,
+ iCapitalY,
+ UnitAITypes.NO_UNITAI,
+ DirectionTypes.DIRECTION_SOUTH,
+ )
+ if iCiv == iHuman:
+ message(
+ iHuman,
+ text("TXT_KEY_CRUSADE_NEW_RELIC"),
+ sound="AS2D_UNIT_BUILD_UNIQUE_UNIT",
+ button=gc.getUnitInfo(Unit.HOLY_RELIC).getButton(),
+ color=MessageData.GREEN,
+ location=(iCapitalX, iCapitalY),
+ )
+ if iUnitNumber > 3 and percentage_chance(60, strict=True):
+ pCiv.initUnit(
+ Unit.HOLY_RELIC,
+ iCapitalX,
+ iCapitalY,
+ UnitAITypes.NO_UNITAI,
+ DirectionTypes.DIRECTION_SOUTH,
+ )
+ if iUnitNumber > 9 and percentage_chance(60, strict=True):
+ pCiv.initUnit(
+ Unit.HOLY_RELIC,
+ iCapitalX,
+ iCapitalY,
+ UnitAITypes.NO_UNITAI,
+ DirectionTypes.DIRECTION_SOUTH,
+ )
+
+
+# Absinthe: called from CvRFCEventHandler.onCityAcquired
+def success(iPlayer):
+ pPlayer = gc.getPlayer(iPlayer)
+ if not hasSucceeded():
+ pPlayer.changeGoldenAgeTurns(gc.getPlayer(iPlayer).getGoldenAgeLength())
+ setSucceeded()
+ for plot in plots.surrounding(CITIES[City.JERUSALEM]).entities():
+ convertPlotCulture(plot, iPlayer, 100, False)
+
+
+@handler("BeginPlayerTurn")
+def checkPlayerTurn(iGameTurn, iPlayer):
+ # Absinthe: pilgrims in Jerusalem if it's held by a Catholic civ
+ if iGameTurn % 3 == 1: # checked every 3rd turn
+ pCity = gc.getMap().plot(*CITIES[City.JERUSALEM]).getPlotCity()
+ if pCity.getOwner() == iPlayer:
+ pPlayer = gc.getPlayer(iPlayer)
+ if pPlayer.getStateReligion() == Religion.CATHOLICISM:
+ # possible population gain, chance based on the current size
+ iRandom = rand(10)
+ if (
+ 1 + pCity.getPopulation()
+ ) <= iRandom: # 1 -> 80%, 2 -> 70%, 3 -> 60% ... 7 -> 20%, 8 -> 10%, 9+ -> 0%
+ pCity.changePopulation(1)
+ message_if_human(
+ iPlayer,
+ text("TXT_KEY_CRUSADE_JERUSALEM_PILGRIMS"),
+ color=MessageData.GREEN,
+ location=pCity,
+ )
+ # spread Catholicism if not present
+ if not pCity.isHasReligion(Religion.CATHOLICISM):
+ pCity.setHasReligion(Religion.CATHOLICISM, True, True, False)
+
+
+def doDefensiveCrusade(iGameTurn):
+ if iGameTurn < getDefensiveCrusadeLast() + 15: # wait 15 turns between defensive crusades
+ return
+ if iGameTurn % 5 != rand(5):
+ return
+ if percentage_chance(33, strict=True):
+ return
+ lPotentials = [
+ iPlayer
+ for iPlayer in civilizations().main().ids()
+ if canDefensiveCrusade(iPlayer, iGameTurn)
+ ]
+ if lPotentials:
+ pPope = gc.getPlayer(Civ.POPE)
+ weights = []
+ for iPlayer in lPotentials:
+ iCatholicFaith = 0
+ pPlayer = gc.getPlayer(iPlayer)
+ # while faith points matter more, diplomatic relations are also very important
+ iCatholicFaith += pPlayer.getFaith()
+ iCatholicFaith += 3 * max(0, pPope.AI_getAttitude(iPlayer))
+ if iCatholicFaith > 0:
+ weights.append(iCatholicFaith)
+ else:
+ weights.append(0)
+
+ iChosenPlayer = choice(lPotentials, weights)
+ if iChosenPlayer == human():
+ callDefensiveCrusadeHuman()
+ else:
+ callDefensiveCrusadeAI(iChosenPlayer)
+ setDefensiveCrusadeLast(iGameTurn)
+
+
+def canDefensiveCrusade(iPlayer, iGameTurn):
+ pPlayer = gc.getPlayer(iPlayer)
+ teamPlayer = gc.getTeam(pPlayer.getTeam())
+ # only born, flipped and living Catholics can defensive crusade
+ if (
+ (iGameTurn < civilization(iPlayer).date.birth + 5)
+ or not pPlayer.isAlive()
+ or pPlayer.getStateReligion() != Religion.CATHOLICISM
+ ):
+ return False
+ # need to have open borders with the Pope
+ if not teamPlayer.isOpenBorders(gc.getPlayer(Civ.POPE).getTeam()):
+ return False
+
+ tPlayerDCMap = tDefensiveCrusadeMap[iPlayer]
+ # Can defensive crusade if at war with a non-catholic/orthodox enemy, enemy is not a vassal of a catholic/orthodox civ and has a city in the defensive crusade map
+ for iEnemy in civilizations().main().ids():
+ pEnemy = gc.getPlayer(iEnemy)
+ if (
+ teamPlayer.isAtWar(pEnemy.getTeam())
+ and civilization(iEnemy).date.birth + 10 < iGameTurn
+ ):
+ if isOrMasterChristian(iEnemy):
+ continue
+ for pCity in cities.owner(iEnemy).entities():
+ if PROVINCES_MAP[pCity.getY()][pCity.getX()] in tPlayerDCMap:
+ return True
+ return False
+
+
+@popup_handler(7625)
+def DefensiveCrusadeEvent(playerID, netUserData, popupReturn):
+ iDecision = popupReturn.getButtonClicked()
+ if iDecision == 0:
+ makeDefensiveCrusadeUnits(human())
+ player().changeFaith(-min(2, player().getFaith()))
+
+
+def callDefensiveCrusadeHuman():
+ event_popup(
+ 7625,
+ text("TXT_KEY_CRUSADE_DEFENSIVE_PROPOSAL_POPUP"),
+ text("TXT_KEY_CRUSADE_DEFENSIVE_PROPOSAL"),
+ [
+ text("TXT_KEY_CRUSADE_DEFENSIVE_PROPOSAL_YES"),
+ text("TXT_KEY_CRUSADE_DEFENSIVE_PROPOSAL_NO"),
+ ],
+ )
+
+
+def callDefensiveCrusadeAI(iPlayer):
+ if player().isExisting():
+ if (
+ team().canContact(teamtype(iPlayer))
+ or player().getStateReligion() == Religion.CATHOLICISM
+ ): # as you have contact with the Pope by default
+ sText = text("TXT_KEY_CRUSADE_DEFENSIVE_AI_MESSAGE") + " " + player(iPlayer).getName()
+ message(human(), sText, force=True, color=MessageData.LIGHT_RED)
+ makeDefensiveCrusadeUnits(iPlayer)
+ player(iPlayer).changeFaith(-min(2, player(iPlayer).getFaith()))
+
+
+def makeDefensiveCrusadeUnits(iPlayer):
+ pPlayer = gc.getPlayer(iPlayer)
+ iFaith = pPlayer.getFaith()
+ iBestInfantry = getDefensiveCrusadeBestInfantry(iPlayer)
+ iBestCavalry = getDefensiveCrusadeBestCavalry(iPlayer)
+ pCapital = pPlayer.getCapitalCity()
+ if pCapital:
+ iX = pCapital.getX()
+ iY = pCapital.getY()
+ else:
+ city = cities.owner(iPlayer).random_entry()
+ if city is not None:
+ iX = city.getX()
+ iY = city.getY()
+ else:
+ return
+
+ # Absinthe: interface message for the player
+ if gc.getPlayer(iPlayer).isHuman():
+ message(
+ iPlayer,
+ text("TXT_KEY_CRUSADE_DEFENSIVE_HUMAN_MESSAGE"),
+ color=MessageData.GREEN,
+ location=(iX, iY),
+ )
+
+ pPlayer.initUnit(
+ iBestInfantry, iX, iY, UnitAITypes.UNITAI_ATTACK, DirectionTypes.DIRECTION_SOUTH
+ )
+ pPlayer.initUnit(
+ iBestCavalry, iX, iY, UnitAITypes.UNITAI_ATTACK, DirectionTypes.DIRECTION_SOUTH
+ )
+
+ # smaller Empires need a bit more help
+ if pPlayer.getNumCities() < 6:
+ if iBestCavalry == Unit.KNIGHT:
+ if percentage_chance(30, strict=True):
+ pPlayer.initUnit(
+ Unit.BURGUNDIAN_PALADIN,
+ iX,
+ iY,
+ UnitAITypes.UNITAI_ATTACK,
+ DirectionTypes.DIRECTION_SOUTH,
+ )
+ else:
+ pPlayer.initUnit(
+ iBestCavalry,
+ iX,
+ iY,
+ UnitAITypes.UNITAI_ATTACK,
+ DirectionTypes.DIRECTION_SOUTH,
+ )
+ else:
+ pPlayer.initUnit(
+ iBestCavalry, iX, iY, UnitAITypes.UNITAI_ATTACK, DirectionTypes.DIRECTION_SOUTH
+ )
+
+ if iFaith > 4:
+ pPlayer.initUnit(
+ iBestInfantry, iX, iY, UnitAITypes.UNITAI_ATTACK, DirectionTypes.DIRECTION_SOUTH
+ )
+ if iFaith > 11:
+ if iBestCavalry == Unit.KNIGHT:
+ if percentage_chance(30, strict=True):
+ pPlayer.initUnit(
+ Unit.BURGUNDIAN_PALADIN,
+ iX,
+ iY,
+ UnitAITypes.UNITAI_ATTACK,
+ DirectionTypes.DIRECTION_SOUTH,
+ )
+ else:
+ pPlayer.initUnit(
+ iBestCavalry,
+ iX,
+ iY,
+ UnitAITypes.UNITAI_ATTACK,
+ DirectionTypes.DIRECTION_SOUTH,
+ )
+ else:
+ pPlayer.initUnit(
+ iBestCavalry, iX, iY, UnitAITypes.UNITAI_ATTACK, DirectionTypes.DIRECTION_SOUTH
+ )
+ if iFaith > 20:
+ pPlayer.initUnit(
+ iBestInfantry, iX, iY, UnitAITypes.UNITAI_ATTACK, DirectionTypes.DIRECTION_SOUTH
+ )
+ if iFaith > 33:
+ pPlayer.initUnit(
+ iBestCavalry, iX, iY, UnitAITypes.UNITAI_ATTACK, DirectionTypes.DIRECTION_SOUTH
+ )
+
+ # extra units for the AI, it is dumb anyway
+ if not iPlayer == human():
+ pPlayer.initUnit(
+ iBestInfantry, iX, iY, UnitAITypes.UNITAI_ATTACK, DirectionTypes.DIRECTION_SOUTH
+ )
+ pPlayer.initUnit(
+ iBestCavalry, iX, iY, UnitAITypes.UNITAI_ATTACK, DirectionTypes.DIRECTION_SOUTH
+ )
+ if iBestCavalry == Unit.KNIGHT:
+ if percentage_chance(30, strict=True):
+ pPlayer.initUnit(
+ Unit.BURGUNDIAN_PALADIN,
+ iX,
+ iY,
+ UnitAITypes.UNITAI_ATTACK,
+ DirectionTypes.DIRECTION_SOUTH,
+ )
+ else:
+ pPlayer.initUnit(
+ iBestCavalry,
+ iX,
+ iY,
+ UnitAITypes.UNITAI_ATTACK,
+ DirectionTypes.DIRECTION_SOUTH,
+ )
+ else:
+ pPlayer.initUnit(
+ iBestCavalry, iX, iY, UnitAITypes.UNITAI_ATTACK, DirectionTypes.DIRECTION_SOUTH
+ )
+
+
+def getDefensiveCrusadeBestInfantry(iPlayer):
+ pPlayer = gc.getPlayer(iPlayer)
+ lUnits = [
+ Unit.GRENADIER,
+ Unit.MACEMAN,
+ Unit.LONG_SWORDSMAN,
+ Unit.SWORDSMAN,
+ ]
+ for iUnit in lUnits:
+ if pPlayer.canTrain(getUniqueUnit(iPlayer, iUnit), False, False):
+ return getUniqueUnit(iPlayer, iUnit)
+ return getUniqueUnit(iPlayer, Unit.AXEMAN)
+
+
+def getDefensiveCrusadeBestCavalry(iPlayer):
+ pPlayer = gc.getPlayer(iPlayer)
+ lUnits = [
+ Unit.CUIRASSIER,
+ Unit.KNIGHT,
+ Unit.HEAVY_LANCER,
+ Unit.LANCER,
+ ]
+ for iUnit in lUnits:
+ if pPlayer.canTrain(getUniqueUnit(iPlayer, iUnit), False, False):
+ return getUniqueUnit(iPlayer, iUnit)
+ return getUniqueUnit(iPlayer, Unit.SCOUT)
+
+
+def do1200ADCrusades():
+ setCrusadeInit(0, year(1096))
+ setCrusadeInit(1, year(1147))
+ setCrusadeInit(2, year(1187))
+
+
+def isOrMasterChristian(iPlayer):
+ pPlayer = gc.getPlayer(iPlayer)
+ iReligion = pPlayer.getStateReligion()
+ if iReligion in [Religion.CATHOLICISM, Religion.ORTHODOXY]:
+ return True
+ iMaster = getMaster(iPlayer)
+ if iMaster != -1:
+ iMasterReligion = gc.getPlayer(iMaster).getStateReligion()
+ if iMasterReligion in [Religion.CATHOLICISM, Religion.ORTHODOXY]:
+ return True
+ return False
diff --git a/Assets/Python/CvEventManager.py b/Assets/Python/CvEventManager.py
index cc62e911b..132655647 100644
--- a/Assets/Python/CvEventManager.py
+++ b/Assets/Python/CvEventManager.py
@@ -1,54 +1,14 @@
from CvPythonExtensions import *
-from Core import (
- civilization,
- civilizations,
- get_data_from_upside_down_map,
- human,
- text,
- message,
- player,
- team,
- cities,
-)
-import CvEspionageAdvisor
-import CvUtil
-import CvScreensInterface
+import CvPlatyBuilderSettings
import CvDebugTools
-import CvWBPopups
-from MiscData import MODNET_EVENTS
-import PyHelpers
-import Popup as PyPopup
-import CvCameraControls
-import CvTopCivs
-import CvAdvisorUtils
-from PyUtils import percentage_chance, rand, choice
-from RFCUtils import getBaseUnit, getUniqueUnit
-import random
-from Consts import MessageData
-from CityMapData import CITIES_MAP
-from CoreTypes import Building, Wonder, Promotion, Project, Improvement, Feature, Unit, Bonus
-
-## Ultrapack ##
-import WBCityEditScreen
-import WBUnitScreen
-import WBPlayerScreen
-import WBGameDataScreen
-import WBPlotScreen
-import CvPlatyBuilderScreen
-
-## Ultrapack ##
+import CvUtil
+
gc = CyGlobalContext()
-PyPlayer = PyHelpers.PyPlayer
-PyInfo = PyHelpers.PyInfo
# globals
###################################################
class CvEventManager(object):
-
- global iImpBeforeCity
- iImpBeforeCity = 0
-
def __init__(self):
#################### ON EVENT MAP ######################
self.bCtrl = False
@@ -65,28 +25,28 @@ def __init__(self):
self.EventKeyDown = 6
self.EventKeyUp = 7
- self.__LOG_MOVEMENT = 0
- self.__LOG_BUILDING = 0
- self.__LOG_COMBAT = 0
- self.__LOG_CONTACT = 0
- self.__LOG_IMPROVEMENT = 1
- self.__LOG_CITYLOST = 0
- self.__LOG_CITYBUILDING = 0
- self.__LOG_TECH = 0
- self.__LOG_UNITBUILD = 0
- self.__LOG_UNITKILLED = 0 # Rhye
- self.__LOG_UNITLOST = 0
- self.__LOG_UNITPROMOTED = 0
- self.__LOG_UNITSELECTED = 0
- self.__LOG_UNITPILLAGE = 0
- self.__LOG_GOODYRECEIVED = 0
- self.__LOG_GREATPERSON = 0
- self.__LOG_RELIGION = 0
- self.__LOG_RELIGIONSPREAD = 0
- self.__LOG_GOLDENAGE = 0
- self.__LOG_ENDGOLDENAGE = 0
- self.__LOG_WARPEACE = 0
- self.__LOG_PUSH_MISSION = 0
+ self._LOG_MOVEMENT = 0
+ self._LOG_BUILDING = 0
+ self._LOG_COMBAT = 0
+ self._LOG_CONTACT = 0
+ self._LOG_IMPROVEMENT = 1
+ self._LOG_CITYLOST = 0
+ self._LOG_CITYBUILDING = 0
+ self._LOG_TECH = 0
+ self._LOG_UNITBUILD = 0
+ self._LOG_UNITKILLED = 0 # Rhye
+ self._LOG_UNITLOST = 0
+ self._LOG_UNITPROMOTED = 0
+ self._LOG_UNITSELECTED = 0
+ self._LOG_UNITPILLAGE = 0
+ self._LOG_GOODYRECEIVED = 0
+ self._LOG_GREATPERSON = 0
+ self._LOG_RELIGION = 0
+ self._LOG_RELIGIONSPREAD = 0
+ self._LOG_GOLDENAGE = 0
+ self._LOG_ENDGOLDENAGE = 0
+ self._LOG_WARPEACE = 0
+ self._LOG_PUSH_MISSION = 0
## EVENTLIST
self.EventHandlerMap = {
@@ -179,65 +139,7 @@ def __init__(self):
# Normal events first, random events after
#
################## Events List ###############################
- self.Events = {
- CvUtil.EventEditCityName: (
- "EditCityName",
- self.__eventEditCityNameApply,
- self.__eventEditCityNameBegin,
- ),
- CvUtil.EventPlaceObject: (
- "PlaceObject",
- self.__eventPlaceObjectApply,
- self.__eventPlaceObjectBegin,
- ),
- CvUtil.EventAwardTechsAndGold: (
- "AwardTechsAndGold",
- self.__eventAwardTechsAndGoldApply,
- self.__eventAwardTechsAndGoldBegin,
- ),
- CvUtil.EventEditUnitName: (
- "EditUnitName",
- self.__eventEditUnitNameApply,
- self.__eventEditUnitNameBegin,
- ),
- ## Platy Builder ##
- CvUtil.EventWBLandmarkPopup: (
- "WBLandmarkPopup",
- self.__eventWBLandmarkPopupApply,
- self.__eventWBScriptPopupBegin,
- ),
- CvUtil.EventShowWonder: (
- "ShowWonder",
- self.__eventShowWonderApply,
- self.__eventShowWonderBegin,
- ),
- 1111: (
- "WBPlayerScript",
- self.__eventWBPlayerScriptPopupApply,
- self.__eventWBScriptPopupBegin,
- ),
- 2222: (
- "WBCityScript",
- self.__eventWBCityScriptPopupApply,
- self.__eventWBScriptPopupBegin,
- ),
- 3333: (
- "WBUnitScript",
- self.__eventWBUnitScriptPopupApply,
- self.__eventWBScriptPopupBegin,
- ),
- 4444: (
- "WBGameScript",
- self.__eventWBGameScriptPopupApply,
- self.__eventWBScriptPopupBegin,
- ),
- 5555: (
- "WBPlotScript",
- self.__eventWBPlotScriptPopupApply,
- self.__eventWBScriptPopupBegin,
- ),
- ## Platy Builder ##
- }
+ self.Events = {}
#################### EVENT STARTERS ######################
def handleEvent(self, argsList):
@@ -290,98 +192,10 @@ def reportEvent(self, entry, context, argsList):
#################### ON EVENTS ######################
def onKbdEvent(self, argsList):
"keypress handler - return 1 if the event was consumed"
-
- eventType, key, mx, my, px, py = argsList
- game = gc.getGame()
-
- if self.bAllowCheats:
- # notify debug tools of input to allow it to override the control
- argsList = (
- eventType,
- key,
- self.bCtrl,
- self.bShift,
- self.bAlt,
- mx,
- my,
- px,
- py,
- gc.getGame().isNetworkMultiPlayer(),
- )
- if CvDebugTools.g_CvDebugTools.notifyInput(argsList):
- return 0
-
- if eventType == self.EventKeyDown:
- theKey = int(key)
-
- CvCameraControls.g_CameraControls.handleInput(theKey)
-
- if self.bAllowCheats:
- # Shift - T (Debug - No MP)
- if theKey == int(InputTypes.KB_T):
- if self.bShift:
- self.beginEvent(CvUtil.EventAwardTechsAndGold)
- # self.beginEvent(CvUtil.EventCameraControlPopup)
- return 1
-
- elif theKey == int(InputTypes.KB_W):
- if self.bShift and self.bCtrl:
- self.beginEvent(CvUtil.EventShowWonder)
- return 1
-
- # Shift - ] (Debug - currently mouse-overd unit, health += 10
- elif theKey == int(InputTypes.KB_LBRACKET) and self.bShift:
- unit = CyMap().plot(px, py).getUnit(0)
- if not unit.isNone():
- d = min(unit.maxHitPoints() - 1, unit.getDamage() + 10)
- unit.setDamage(d, PlayerTypes.NO_PLAYER)
-
- # Shift - [ (Debug - currently mouse-overd unit, health -= 10
- elif theKey == int(InputTypes.KB_RBRACKET) and self.bShift:
- unit = CyMap().plot(px, py).getUnit(0)
- if not unit.isNone():
- d = max(0, unit.getDamage() - 10)
- unit.setDamage(d, PlayerTypes.NO_PLAYER)
-
- elif theKey == int(InputTypes.KB_F1):
- if self.bShift:
- CvScreensInterface.replayScreen.showScreen(False)
- return 1
- # don't return 1 unless you want the input consumed
-
- elif theKey == int(InputTypes.KB_F2):
- if self.bShift:
- CvScreensInterface.showDebugInfoScreen()
- return 1
-
- elif theKey == int(InputTypes.KB_F3):
- if self.bShift:
- CvScreensInterface.showDanQuayleScreen(())
- return 1
-
- elif theKey == int(InputTypes.KB_F4):
- if self.bShift:
- CvScreensInterface.showUnVictoryScreen(())
- return 1
-
return 0
def onModNetMessage(self, argsList):
"Called whenever CyMessageControl().sendModNetMessage() is called - this is all for you modders!"
- iData1, iData2, iData3, iData4, iData5 = argsList
- if iData1 == MODNET_EVENTS["CHANGE_COMMERCE_PERCENT"]:
- CommerceType = [
- CommerceTypes.COMMERCE_GOLD,
- CommerceTypes.COMMERCE_RESEARCH,
- CommerceTypes.COMMERCE_CULTURE,
- CommerceTypes.COMMERCE_ESPIONAGE,
- ]
- gc.getPlayer(iData2).changeCommercePercent(CommerceType[iData3], iData4)
- if iData2 == CyGame().getActivePlayer():
- screen = CvEspionageAdvisor.CvEspionageAdvisor().getScreen()
- if screen.isActive():
- CvEspionageAdvisor.CvEspionageAdvisor().updateEspionageWeights()
-
CvUtil.pyPrint("onModNetMessage")
def onInit(self, argsList):
@@ -392,9 +206,6 @@ def onUpdate(self, argsList):
"Called every frame"
fDeltaTime = argsList[0]
- # allow camera to be updated
- CvCameraControls.g_CameraControls.onUpdate(fDeltaTime)
-
def onWindowActivation(self, argsList):
"Called when the game window activates or deactivates"
bActive = argsList[0]
@@ -412,32 +223,11 @@ def onSaveGame(self, argsList):
return ""
def onLoadGame(self, argsList):
- CvAdvisorUtils.resetNoLiberateCities()
return 0
def onGameStart(self, argsList):
"Called at the start of the game"
-
- # Rhye - Dawn of Man must appear in late starts too
- # Duplicate with Assets/Python/Contrib/CvAllErasDawnOfManScreenEventManager.py
- if (
- gc.getGame().getStartEra() == gc.getDefineINT("STANDARD_ERA")
- or gc.getGame().isOption(GameOptionTypes.GAMEOPTION_ADVANCED_START)
- ) and player().isAlive():
- popupInfo = CyPopupInfo()
- popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_PYTHON_SCREEN)
- popupInfo.setText(u"showDawnOfMan")
- popupInfo.addPopup(human())
- else:
- CyInterface().setSoundSelectionReady(True)
-
- if gc.getGame().isPbem() and player().isAlive():
- popupInfo = CyPopupInfo()
- popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_DETAILS)
- popupInfo.setOption1(True)
- popupInfo.addPopup(human())
-
- CvAdvisorUtils.resetNoLiberateCities()
+ pass
def onGameEnd(self, argsList):
"Called at the End of the game"
@@ -446,7 +236,6 @@ def onGameEnd(self, argsList):
def onBeginGameTurn(self, argsList):
"Called at the beginning of the end of each turn"
iGameTurn = argsList[0]
- CvTopCivs.CvTopCivs().turnChecker(iGameTurn)
def onEndGameTurn(self, argsList):
"Called at the end of the end of each turn"
@@ -460,60 +249,15 @@ def onEndPlayerTurn(self, argsList):
"Called at the end of a players turn"
iGameTurn, iPlayer = argsList
- if gc.getGame().getElapsedGameTurns() == 1:
- if gc.getPlayer(iPlayer).isHuman():
- if gc.getPlayer(iPlayer).canRevolution(0):
- popupInfo = CyPopupInfo()
- popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_CHANGECIVIC)
- popupInfo.addPopup(iPlayer)
-
- CvAdvisorUtils.resetAdvisorNags()
- CvAdvisorUtils.endTurnFeats(iPlayer)
-
def onEndTurnReady(self, argsList):
iGameTurn = argsList[0]
def onFirstContact(self, argsList):
- ## Platy Builder ##
- if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderScreen.bPython:
- return
- ## Platy Builder ##
- "Contact"
- iTeamX, iHasMetTeamY = argsList
- if not self.__LOG_CONTACT:
- return
- CvUtil.pyPrint("Team %d has met Team %d" % (iTeamX, iHasMetTeamY))
+ pass
def onCombatResult(self, argsList):
"Combat Result"
pWinner, pLoser = argsList
- playerX = PyPlayer(pWinner.getOwner())
- unitX = PyInfo.UnitInfo(pWinner.getUnitType())
- playerY = PyPlayer(pLoser.getOwner())
- unitY = PyInfo.UnitInfo(pLoser.getUnitType())
- if not self.__LOG_COMBAT:
- return
- if playerX and playerX and unitX and playerY:
- CvUtil.pyPrint(
- "Player %d Civilization %s Unit %s has defeated Player %d Civilization %s Unit %s"
- % (
- playerX.getID(),
- playerX.getCivilizationName(),
- unitX.getDescription(),
- playerY.getID(),
- playerY.getCivilizationName(),
- unitY.getDescription(),
- )
- )
- # Absinthe: Gediminas Tower wonder effect: extra city defence on unit win in the city
- pPlayer = gc.getPlayer(pWinner.getOwner())
- if pPlayer.countNumBuildings(Wonder.GEDIMINAS_TOWER) > 0:
- pPlot = pWinner.plot()
- if pPlot.isCity():
- pCity = pPlot.getPlotCity()
- if pCity.getNumActiveBuilding(Wonder.GEDIMINAS_TOWER):
- pCity.changeDefenseDamage(-10)
- # Absinthe: Gediminas Tower end
def onCombatLogCalc(self, argsList):
"Combat Result"
@@ -521,128 +265,27 @@ def onCombatLogCalc(self, argsList):
cdAttacker = genericArgs[0]
cdDefender = genericArgs[1]
iCombatOdds = genericArgs[2]
- CvUtil.combatMessageBuilder(cdAttacker, cdDefender, iCombatOdds)
def onCombatLogHit(self, argsList):
"Combat Message"
- global gCombatMessages, gCombatLog
genericArgs = argsList[0][0]
cdAttacker = genericArgs[0]
cdDefender = genericArgs[1]
iIsAttacker = genericArgs[2]
iDamage = genericArgs[3]
- if cdDefender.eOwner == cdDefender.eVisualOwner:
- szDefenderName = gc.getPlayer(cdDefender.eOwner).getNameKey()
- else:
- szDefenderName = text("TXT_KEY_TRAIT_PLAYER_UNKNOWN")
- if cdAttacker.eOwner == cdAttacker.eVisualOwner:
- szAttackerName = gc.getPlayer(cdAttacker.eOwner).getNameKey()
- else:
- szAttackerName = text("TXT_KEY_TRAIT_PLAYER_UNKNOWN")
-
- if iIsAttacker == 0:
- combatMessage = text(
- "TXT_KEY_COMBAT_MESSAGE_HIT",
- szDefenderName,
- cdDefender.sUnitName,
- iDamage,
- cdDefender.iCurrHitPoints,
- cdDefender.iMaxHitPoints,
- )
- CyInterface().addCombatMessage(cdAttacker.eOwner, combatMessage)
- CyInterface().addCombatMessage(cdDefender.eOwner, combatMessage)
- if cdDefender.iCurrHitPoints <= 0:
- combatMessage = text(
- "TXT_KEY_COMBAT_MESSAGE_DEFEATED",
- szAttackerName,
- cdAttacker.sUnitName,
- szDefenderName,
- cdDefender.sUnitName,
- )
- CyInterface().addCombatMessage(cdAttacker.eOwner, combatMessage)
- CyInterface().addCombatMessage(cdDefender.eOwner, combatMessage)
- elif iIsAttacker == 1:
- combatMessage = text(
- "TXT_KEY_COMBAT_MESSAGE_HIT",
- szAttackerName,
- cdAttacker.sUnitName,
- iDamage,
- cdAttacker.iCurrHitPoints,
- cdAttacker.iMaxHitPoints,
- )
- CyInterface().addCombatMessage(cdAttacker.eOwner, combatMessage)
- CyInterface().addCombatMessage(cdDefender.eOwner, combatMessage)
- if cdAttacker.iCurrHitPoints <= 0:
- combatMessage = text(
- "TXT_KEY_COMBAT_MESSAGE_DEFEATED",
- szDefenderName,
- cdDefender.sUnitName,
- szAttackerName,
- cdAttacker.sUnitName,
- )
- CyInterface().addCombatMessage(cdAttacker.eOwner, combatMessage)
- CyInterface().addCombatMessage(cdDefender.eOwner, combatMessage)
-
def onImprovementBuilt(self, argsList):
- ## Platy Builder ##
- if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderScreen.bPython:
- return
- ## Platy Builder ##
- "Improvement Built"
- iImprovement, iX, iY = argsList
- # Absinthe: Stephansdom start
- if iImprovement == Improvement.COTTAGE:
- pPlot = CyMap().plot(iX, iY)
- iOwner = pPlot.getOwner()
- # if there is an owner
- if iOwner >= 0:
- pOwner = gc.getPlayer(iOwner)
- if pOwner.countNumBuildings(Wonder.STEPHANSDOM) > 0:
- pPlot.setImprovementType(Improvement.HAMLET)
- # Absinthe: Stephansdom end
- if not self.__LOG_IMPROVEMENT:
- return
- CvUtil.pyPrint(
- "Improvement %s was built at %d, %d"
- % (PyInfo.ImprovementInfo(iImprovement).getDescription(), iX, iY)
- )
+ pass
def onImprovementDestroyed(self, argsList):
- ## Platy Builder ##
- if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderScreen.bPython:
- return
- ## Platy Builder ##
- "Improvement Destroyed"
iImprovement, iOwner, iX, iY = argsList
- if not self.__LOG_IMPROVEMENT:
- return
- CvUtil.pyPrint(
- "Improvement %s was Destroyed at %d, %d"
- % (PyInfo.ImprovementInfo(iImprovement).getDescription(), iX, iY)
- )
- # Absinthe: Free walls if city is built on a fort
- # This is a hack for it, checking what was the improvement before the city was built
- # Saving the improvement type and coordinates here as a global variable, and accessing later in the onCityBuilt function
- global iImpBeforeCity
- iImpBeforeCity = 10000 * iImprovement + 100 * iX + 1 * iY
def onRouteBuilt(self, argsList):
- ## Platy Builder ##
- if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderScreen.bPython:
- return
- ## Platy Builder ##
- "Route Built"
- iRoute, iX, iY = argsList
- if not self.__LOG_IMPROVEMENT:
- return
- CvUtil.pyPrint(
- "Route %s was built at %d, %d" % (gc.getRouteInfo(iRoute).getDescription(), iX, iY)
- )
+ pass
def onPlotRevealed(self, argsList):
## Platy Builder ##
- if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderScreen.bPython:
+ if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderSettings.bPython:
return
## Platy Builder ##
"Plot Revealed"
@@ -656,38 +299,6 @@ def onPlotFeatureRemoved(self, argsList):
iFeatureType = argsList[2]
pCity = argsList[1] # This can be null
- # Absinthe: remove specific resources if the forest/dense forest/palm forest was cut down:
- if pPlot.getBonusType(-1) != -1: # only proceed if there is a bonus resource on the plot
- if (
- iFeatureType == gc.getInfoTypeForString("FEATURE_FOREST")
- or iFeatureType == Feature.DENSEFOREST
- or iFeatureType == Feature.PALMFOREST
- ):
- iBonusType = pPlot.getBonusType(-1)
- if iBonusType in [Bonus.TIMBER, Bonus.DEER, Bonus.FUR]:
- pPlot.setBonusType(-1)
- # also remove corresponding improvements
- iImprovementType = pPlot.getImprovementType()
- if (
- iImprovementType == Improvement.CAMP
- ): # camp is only buildable on resources, while lumbermills are removed by default on forest removal
- pPlot.setImprovementType(-1)
- # Absinthe: message for the human player if it was inside it's territory
- iOwner = pPlot.getOwner()
- if iOwner == human():
- message(
- iOwner,
- text(
- "TXT_KEY_NO_FOREST_NO_RESOURCE",
- gc.getBonusInfo(iBonusType).getTextKey(),
- ),
- sound="AS2D_DISCOVERBONUS",
- event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
- button=gc.getBonusInfo(iBonusType).getButton(),
- color=MessageData.LIME,
- location=pPlot,
- )
-
def onPlotPicked(self, argsList):
"Plot Picked"
pPlot = argsList[0]
@@ -705,316 +316,10 @@ def onGotoPlotSet(self, argsList):
def onBuildingBuilt(self, argsList):
"Building Completed"
pCity, iBuildingType = argsList
- iPlayer = pCity.getOwner()
- pPlayer = gc.getPlayer(iPlayer)
-
- # Absinthe: Leaning Tower start
- if iBuildingType == Wonder.LEANING_TOWER:
- iX = pCity.getX()
- iY = pCity.getY()
- iUnit = Unit.GREAT_PROPHET + rand(7)
- pNewUnit = pPlayer.initUnit(
- iUnit,
- iX,
- iY,
- UnitAITypes(gc.getUnitInfo(iUnit).getDefaultUnitAIType()),
- DirectionTypes.NO_DIRECTION,
- )
- if player().isExisting():
- szText = (
- text("TXT_KEY_BUILDING_LEANING_TOWER_EFFECT")
- + " "
- + gc.getUnitInfo(iUnit).getDescription()
- )
- message(
- human(),
- szText,
- event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
- color=MessageData.LIGHT_BLUE,
- )
- # Absinthe: Leaning Tower end
-
- # Absinthe: Bibliotheca Corviniana start
- if iBuildingType == Wonder.BIBLIOTHECA_CORVINIANA:
- # techs known by the owner civ
- iTeam = pPlayer.getTeam()
- pTeam = gc.getTeam(iTeam)
- lBuilderKnownTechs = []
- for iTech in xrange(gc.getNumTechInfos()): # type: ignore
- if pTeam.isHasTech(iTech):
- lBuilderKnownTechs.append(iTech)
-
- # techs known by the other civs
- lOthersKnownTechs = []
- for iLoopPlayer in civilizations().majors().ids():
- pLoopPlayer = gc.getPlayer(iLoopPlayer)
- iLoopTeam = pLoopPlayer.getTeam()
- pLoopTeam = gc.getTeam(iLoopTeam)
- # only for known civs
- if iLoopPlayer != iPlayer and pTeam.isHasMet(iLoopTeam):
- for iTech in xrange(gc.getNumTechInfos()): # type: ignore
- if pLoopTeam.isHasTech(iTech):
- lOthersKnownTechs.append(iTech)
-
- # collecting the not known techs which are available for at least one other civ
- # note that we can have the same tech multiple times
- lPotentialTechs = []
- for iTech in lOthersKnownTechs:
- if iTech not in lBuilderKnownTechs:
- lPotentialTechs.append(iTech)
-
- if len(lPotentialTechs) > 0:
- # converting to a set (and then back to a list), as sets only keep unique elements
- lUniquePotentialTechs = list(set(lPotentialTechs))
-
- # randomizing the order of the techs
- random.shuffle(lPotentialTechs)
-
- # adding the techs, with message for the human player
- if len(lUniquePotentialTechs) == 1:
- # add the first instance of the single tech, with message for the human player
- iChosenTech = lPotentialTechs[0]
- pTeam.setHasTech(iChosenTech, True, iPlayer, False, True)
- if iPlayer == human():
- sText = text(
- "TXT_KEY_BUILDING_BIBLIOTHECA_CORVINIANA_EFFECT",
- gc.getTechInfo(iChosenTech).getDescription(),
- )
- message(iPlayer, sText, force=True, color=MessageData.LIGHT_BLUE)
- elif len(lUniquePotentialTechs) > 1:
- # add two different random techs, with message for the human player
- for tech in random.sample(lPotentialTechs, 2):
- pTeam.setHasTech(tech, True, iPlayer, False, True)
- if iPlayer == human():
- sText = text(
- "TXT_KEY_BUILDING_BIBLIOTHECA_CORVINIANA_EFFECT",
- gc.getTechInfo(tech).getDescription(),
- )
- message(iPlayer, sText, force=True, color=MessageData.LIGHT_BLUE)
- # Absinthe: Bibliotheca Corviniana end
-
- # Absinthe: Kalmar Castle start
- if iBuildingType == Wonder.KALMAR_CASTLE:
- for neighbour in civilization(iPlayer).location.neighbours:
- iNeighbour = neighbour
- pNeighbour = gc.getPlayer(iNeighbour)
- if pNeighbour.isAlive() and iPlayer != iNeighbour:
- pPlayer.AI_changeAttitudeExtra(iNeighbour, 3)
- pNeighbour.AI_changeAttitudeExtra(iPlayer, 3)
- # Absinthe: Kalmar Castle end
-
- # Absinthe: Grand Arsenal start
- if iBuildingType == Wonder.GRAND_ARSENAL:
- iX = pCity.getX()
- iY = pCity.getY()
- for i in range(3):
- # should we have Galleass for all civs, or use the getUniqueUnit function in RFCUtils?
- pNewUnit = pPlayer.initUnit(
- Unit.VENICE_GALLEAS,
- iX,
- iY,
- UnitAITypes(gc.getUnitInfo(Unit.VENICE_GALLEAS).getDefaultUnitAIType()),
- DirectionTypes.DIRECTION_SOUTH,
- )
- pNewUnit.setExperience(6, -1)
- for iPromo in [
- Promotion.COMBAT,
- Promotion.LEADERSHIP,
- Promotion.NAVIGATION,
- ]:
- pNewUnit.setHasPromotion(iPromo, True)
- # Absinthe: Grand Arsenal end
-
- # Absinthe: Magellan's Voyage start
- if iBuildingType == Wonder.MAGELLANS_VOYAGE:
- iTeam = pPlayer.getTeam()
- pTeam = gc.getTeam(iTeam)
- pTeam.changeExtraMoves(gc.getInfoTypeForString("DOMAIN_SEA"), 2)
- # Absinthe: Magellan's Voyage end
-
- # Absinthe: St. Catherine's Monastery start
- if iBuildingType == Wonder.ST_CATHERINE_MONASTERY:
- iX = pCity.getX()
- iY = pCity.getY()
- for i in range(2):
- pPlayer.initUnit(
- Unit.HOLY_RELIC,
- iX,
- iY,
- UnitAITypes.NO_UNITAI,
- DirectionTypes.DIRECTION_SOUTH,
- )
- if human() == iPlayer:
- message(
- iPlayer,
- text("TXT_KEY_BUILDING_SAINT_CATHERINE_MONASTERY_EFFECT"),
- color=MessageData.LIGHT_BLUE,
- )
- # Absinthe: St. Catherine's Monastery end
-
- # Absinthe: Al-Azhar University start
- if iBuildingType == Wonder.ALAZHAR:
- iTeam = pPlayer.getTeam()
- pTeam = gc.getTeam(iTeam)
- for iTech in xrange(gc.getNumTechInfos()): # type: ignore
- if not pTeam.isHasTech(iTech):
- if gc.getTechInfo(iTech).getAdvisorType() == gc.getInfoTypeForString(
- "ADVISOR_RELIGION"
- ):
- research_cost = pTeam.getResearchCost(iTech)
- pTeam.changeResearchProgress(
- iTech,
- min(
- research_cost - pTeam.getResearchProgress(iTech), research_cost / 2
- ),
- iPlayer,
- )
- # Absinthe: Al-Azhar University end
-
- # Absinthe: Sistine Chapel start
- if iBuildingType == Wonder.SISTINE_CHAPEL:
- for city in cities().owner(iPlayer).entities():
- if city.getNumWorldWonders() > 0:
- city.changeFreeSpecialistCount(gc.getInfoTypeForString("SPECIALIST_ARTIST"), 1)
- elif isWorldWonderClass(gc.getBuildingInfo(iBuildingType).getBuildingClassType()):
- # if the given civ already had the Sistine Chapel, and built another wonder in a new city
- if pPlayer.countNumBuildings(Wonder.SISTINE_CHAPEL) > 0:
- if pCity.getNumWorldWonders() == 1:
- pCity.changeFreeSpecialistCount(
- gc.getInfoTypeForString("SPECIALIST_ARTIST"), 1
- )
- # Absinthe: Sistine Chapel end
-
- # Absinthe: Jasna Gora start
- if iBuildingType == Wonder.JASNA_GORA:
- for city in cities().owner(iPlayer).entities():
- city.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_CATHOLIC_TEMPLE"),
- CommerceTypes.COMMERCE_CULTURE,
- 1,
- )
- city.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_ORTHODOX_TEMPLE"),
- CommerceTypes.COMMERCE_CULTURE,
- 1,
- )
- city.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_PROTESTANT_TEMPLE"),
- CommerceTypes.COMMERCE_CULTURE,
- 1,
- )
- city.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_ISLAMIC_TEMPLE"),
- CommerceTypes.COMMERCE_CULTURE,
- 1,
- )
- # Absinthe: Jasna Gora end
-
- # Absinthe: Kizil Kule start
- if iBuildingType == Wonder.KIZIL_KULE:
- for city in cities().owner(iPlayer).entities():
- city.setBuildingYieldChange(
- gc.getInfoTypeForString("BUILDINGCLASS_HARBOR"), YieldTypes.YIELD_COMMERCE, 2
- )
- # Absinthe: Kizil Kule end
-
- # Absinthe: Samogitian Alkas start
- if iBuildingType == Wonder.SAMOGITIAN_ALKAS:
- for city in cities().owner(iPlayer).entities():
- city.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_PAGAN_SHRINE"),
- CommerceTypes.COMMERCE_RESEARCH,
- 2,
- )
- # Absinthe: Samogitian Alkas end
-
- # Absinthe: Magna Carta start
- if iBuildingType == Wonder.MAGNA_CARTA:
- for city in cities().owner(iPlayer).entities():
- city.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_COURTHOUSE"),
- CommerceTypes.COMMERCE_CULTURE,
- 2,
- )
- # Absinthe: Magna Carta end
-
- game = gc.getGame()
- if (
- (not game.isNetworkMultiPlayer())
- and (iPlayer == game.getActivePlayer())
- and isWorldWonderClass(gc.getBuildingInfo(iBuildingType).getBuildingClassType())
- ):
- popupInfo = CyPopupInfo()
- popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_PYTHON_SCREEN)
- popupInfo.setData1(iBuildingType)
- popupInfo.setData2(pCity.getID())
- popupInfo.setData3(0)
- popupInfo.setText(u"showWonderMovie")
- popupInfo.addPopup(iPlayer)
- ## Platy Builder ##
- if not CyGame().GetWorldBuilderMode():
- ## Platy Builder ##
- popupInfo = CyPopupInfo()
- popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_PYTHON_SCREEN)
- popupInfo.setData1(iBuildingType)
- popupInfo.setData2(pCity.getID())
- popupInfo.setData3(0)
- popupInfo.setText(u"showWonderMovie")
- popupInfo.addPopup(pCity.getOwner())
-
- CvAdvisorUtils.buildingBuiltFeats(pCity, iBuildingType)
-
- if not self.__LOG_BUILDING:
- return
- CvUtil.pyPrint(
- "%s was finished by Player %d Civilization %s"
- % (
- PyInfo.BuildingInfo(iBuildingType).getDescription(),
- iPlayer,
- pPlayer.getCivilizationDescription(0),
- )
- )
def onProjectBuilt(self, argsList):
"Project Completed"
pCity, iProjectType = argsList
- iPlayer = pCity.getOwner()
- game = gc.getGame()
- if (not game.isNetworkMultiPlayer()) and (iPlayer == game.getActivePlayer()):
- popupInfo = CyPopupInfo()
- popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_PYTHON_SCREEN)
- popupInfo.setData1(iProjectType)
- popupInfo.setData2(pCity.getID())
- popupInfo.setData3(2)
- popupInfo.setText(u"showWonderMovie")
- popupInfo.addPopup(iPlayer)
-
- ## Platy Builder ##
- if not CyGame().GetWorldBuilderMode():
- ## Platy Builder ##
- popupInfo = CyPopupInfo()
- popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_PYTHON_SCREEN)
- popupInfo.setData1(iProjectType)
- popupInfo.setData2(pCity.getID())
- popupInfo.setData3(2)
- popupInfo.setText(u"showWonderMovie")
- popupInfo.addPopup(iPlayer)
-
- # Absinthe: Torre del Oro start
- if iProjectType >= len(Project):
- pPlayer = gc.getPlayer(iPlayer)
- if pPlayer.countNumBuildings(Wonder.TORRE_DEL_ORO) > 0:
- # 70% chance for a 3 turn Golden Age
- if percentage_chance(70, strict=True):
- pPlayer.changeGoldenAgeTurns(3)
- if human() == iPlayer:
- message(
- iPlayer,
- text("TXT_KEY_PROJECT_COLONY_GOLDEN_AGE"),
- color=MessageData.GREEN,
- )
- # Absinthe: Torre del Oro end
- popupInfo.addPopup(pCity.getOwner())
def onSelectionGroupPushMission(self, argsList):
"selection group mission"
@@ -1023,238 +328,52 @@ def onSelectionGroupPushMission(self, argsList):
iNumUnits = argsList[2]
listUnitIds = argsList[3]
- if not self.__LOG_PUSH_MISSION:
- return
- if pHeadUnit: # type: ignore
- CvUtil.pyPrint("Selection Group pushed mission %d" % (eMission))
-
def onUnitMove(self, argsList):
"unit move"
pPlot, pUnit, pOldPlot = argsList
- player = PyPlayer(pUnit.getOwner())
- unitInfo = PyInfo.UnitInfo(pUnit.getUnitType())
- if not self.__LOG_MOVEMENT:
- return
- if player and unitInfo:
- CvUtil.pyPrint(
- "Player %d Civilization %s unit %s is moving to %d, %d"
- % (
- player.getID(),
- player.getCivilizationName(),
- unitInfo.getDescription(),
- pUnit.getX(),
- pUnit.getY(),
- )
- )
def onUnitSetXY(self, argsList):
"units xy coords set manually"
- pPlot, pUnit = argsList
- player = PyPlayer(pUnit.getOwner())
- unitInfo = PyInfo.UnitInfo(pUnit.getUnitType())
- if not self.__LOG_MOVEMENT:
+ if not self._LOG_MOVEMENT:
return
def onUnitCreated(self, argsList):
- ## Platy Builder ##
- if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderScreen.bPython:
- return
- ## Platy Builder ##
"Unit Completed"
- unit = argsList[0]
- player = PyPlayer(unit.getOwner())
- if not self.__LOG_UNITBUILD:
- return
+ pass
def onUnitBuilt(self, argsList):
"Unit Completed"
city = argsList[0]
unit = argsList[1]
- player = PyPlayer(city.getOwner())
-
- # Absinthe: Topkapi Palace start
- iPlayer = unit.getOwner()
- pPlayer = gc.getPlayer(iPlayer)
- iUnitType = unit.getUnitType()
- iTeam = pPlayer.getTeam()
- pTeam = gc.getTeam(iTeam)
-
- if pTeam.isTrainVassalUU():
- l_vassalUU = []
- iDefaultUnit = getBaseUnit(iUnitType)
- for iLoopPlayer in civilizations().majors().ids():
- pLoopPlayer = gc.getPlayer(iLoopPlayer)
- if pLoopPlayer.isAlive():
- if gc.getTeam(pLoopPlayer.getTeam()).isVassal(iTeam):
- iUniqueUnit = getUniqueUnit(iLoopPlayer, iUnitType)
- if iUniqueUnit != iDefaultUnit:
- l_vassalUU.append(iUniqueUnit)
- if l_vassalUU: # Only convert if vassal UU is possible
- iPlayerUU = getUniqueUnit(iPlayer, iUnitType)
- if iPlayerUU != iDefaultUnit:
- # double chance for the original UU
- l_vassalUU.append(iPlayerUU)
- l_vassalUU.append(iPlayerUU)
- iUnit = choice(l_vassalUU)
- pNewUnit = pPlayer.initUnit(
- iUnit,
- unit.getX(),
- unit.getY(),
- UnitAITypes.NO_UNITAI,
- DirectionTypes.NO_DIRECTION,
- )
- pNewUnit.convert(unit)
- # message if it was changed to a vassal UU
- if iUnit != iPlayerUU and iUnit != iDefaultUnit:
- if human() == iPlayer:
- szText = text(
- "TXT_KEY_BUILDING_TOPKAPI_PALACE_EFFECT",
- gc.getUnitInfo(iUnit).getDescription(),
- gc.getUnitInfo(iPlayerUU).getDescription(),
- )
- message(
- human(),
- szText,
- event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
- button=gc.getUnitInfo(iUnit).getButton(),
- color=MessageData.LIGHT_BLUE,
- location=city,
- )
- # Absinthe: Topkapi Palace end
-
- # Absinthe: Brandenburg Gate start
- if unit.getUnitCombatType() != -1:
- if pPlayer.countNumBuildings(Wonder.BRANDENBURG_GATE) > 0:
- unit.changeExperience(
- (
- 2
- * city.getAddedFreeSpecialistCount(
- gc.getInfoTypeForString("SPECIALIST_GREAT_GENERAL")
- )
- ),
- 999,
- False,
- False,
- False,
- )
- # Absinthe: Brandenburg Gate end
-
- # Absinthe: Selimiye Mosque start
- if pPlayer.countNumBuildings(Wonder.SELIMIYE_MOSQUE) > 0:
- if pPlayer.isGoldenAge():
- unit.changeExperience(unit.getExperience(), 999, False, False, False)
- # Absinthe: Selimiye Mosque end
-
- CvAdvisorUtils.unitBuiltFeats(city, unit)
-
- if not self.__LOG_UNITBUILD:
- return
- CvUtil.pyPrint(
- "%s was finished by Player %d Civilization %s"
- % (
- PyInfo.UnitInfo(unit.getUnitType()).getDescription(),
- player.getID(),
- player.getCivilizationName(),
- )
- )
def onUnitKilled(self, argsList):
"Unit Killed"
unit, iAttacker = argsList
- player = PyPlayer(unit.getOwner())
- attacker = PyPlayer(iAttacker)
- if not self.__LOG_UNITKILLED:
- return
- CvUtil.pyPrint(
- "Player %d Civilization %s Unit %s was killed by Player %d"
- % (
- player.getID(),
- player.getCivilizationName(),
- PyInfo.UnitInfo(unit.getUnitType()).getDescription(),
- attacker.getID(),
- )
- )
def onUnitLost(self, argsList):
- ## Platy Builder ##
- if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderScreen.bPython:
- return
- ## Platy Builder ##
"Unit Lost"
unit = argsList[0]
- player = PyPlayer(unit.getOwner())
- if not self.__LOG_UNITLOST:
- return
- CvUtil.pyPrint(
- "%s was lost by Player %d Civilization %s"
- % (
- PyInfo.UnitInfo(unit.getUnitType()).getDescription(),
- player.getID(),
- player.getCivilizationName(),
- )
- )
def onUnitPromoted(self, argsList):
"Unit Promoted"
pUnit, iPromotion = argsList
- player = PyPlayer(pUnit.getOwner())
- if not self.__LOG_UNITPROMOTED:
- return
- CvUtil.pyPrint(
- "Unit Promotion Event: %s - %s" % (player.getCivilizationName(), pUnit.getName())
- )
def onUnitSelected(self, argsList):
"Unit Selected"
unit = argsList[0]
- player = PyPlayer(unit.getOwner())
- if not self.__LOG_UNITSELECTED:
- return
- CvUtil.pyPrint(
- "%s was selected by Player %d Civilization %s"
- % (
- PyInfo.UnitInfo(unit.getUnitType()).getDescription(),
- player.getID(),
- player.getCivilizationName(),
- )
- )
def onUnitRename(self, argsList):
"Unit is renamed"
pUnit = argsList[0]
- if pUnit.getOwner() == gc.getGame().getActivePlayer():
- self.__eventEditUnitNameBegin(pUnit)
def onUnitPillage(self, argsList):
"Unit pillages a plot"
pUnit, iImprovement, iRoute, iOwner = argsList
- iPlotX = pUnit.getX()
- iPlotY = pUnit.getY()
- pPlot = CyMap().plot(iPlotX, iPlotY)
-
- if not self.__LOG_UNITPILLAGE:
- return
- CvUtil.pyPrint(
- "Player %d's %s pillaged improvement %d and route %d at plot at (%d, %d)"
- % (
- iOwner,
- PyInfo.UnitInfo(pUnit.getUnitType()).getDescription(),
- iImprovement,
- iRoute,
- iPlotX,
- iPlotY,
- )
- )
def onUnitSpreadReligionAttempt(self, argsList):
"Unit tries to spread religion to a city"
pUnit, iReligion, bSuccess = argsList
- iX = pUnit.getX()
- iY = pUnit.getY()
- pPlot = CyMap().plot(iX, iY)
- pCity = pPlot.getPlotCity()
-
def onUnitGifted(self, argsList):
"Unit is gifted from one player to another"
pUnit, iGiftingPlayer, pPlotLocation = argsList
@@ -1266,290 +385,57 @@ def onUnitBuildImprovement(self, argsList):
def onGoodyReceived(self, argsList):
"Goody received"
iPlayer, pPlot, pUnit, iGoodyType = argsList
- if not self.__LOG_GOODYRECEIVED:
- return
- CvUtil.pyPrint(
- "%s received a goody" % (gc.getPlayer(iPlayer).getCivilizationDescription(0))
- )
def onGreatPersonBorn(self, argsList):
- ## Platy Builder ##
- if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderScreen.bPython:
- return
- ## Platy Builder ##
"Unit Promoted"
pUnit, iPlayer, pCity = argsList
- player = PyPlayer(iPlayer)
- pPlayer = gc.getPlayer(iPlayer)
- if pUnit.isNone() or pCity.isNone():
- return
- if not self.__LOG_GREATPERSON:
- # Absinthe: Louvre start
- if pPlayer.countNumBuildings(Wonder.LOUVRE) > 0:
- for loopCity in cities().owner(iPlayer).entities():
- # bigger boost for the GP city and the Louvre city
- if loopCity.getNumActiveBuilding(Wonder.LOUVRE) or pCity == loopCity:
- loopCity.changeCulture(
- iPlayer, min(300, loopCity.getCultureThreshold() / 5), True
- )
- else:
- loopCity.changeCulture(
- iPlayer, min(100, loopCity.getCultureThreshold() / 10), True
- )
- # Absinthe: Louvre end
-
- # Absinthe: Peterhof Palace start
- if pPlayer.countNumBuildings(Wonder.PETERHOF_PALACE) > 0:
- if percentage_chance(70, strict=True):
- if pUnit.getUnitType() == Unit.GREAT_SCIENTIST:
- pCity.changeFreeSpecialistCount(
- gc.getInfoTypeForString("SPECIALIST_SCIENTIST"), 1
- )
- elif pUnit.getUnitType() == Unit.GREAT_PROPHET:
- pCity.changeFreeSpecialistCount(
- gc.getInfoTypeForString("SPECIALIST_PRIEST"), 1
- )
- elif pUnit.getUnitType() == Unit.GREAT_ARTIST:
- pCity.changeFreeSpecialistCount(
- gc.getInfoTypeForString("SPECIALIST_ARTIST"), 1
- )
- elif pUnit.getUnitType() == Unit.GREAT_MERCHANT:
- pCity.changeFreeSpecialistCount(
- gc.getInfoTypeForString("SPECIALIST_MERCHANT"), 1
- )
- elif pUnit.getUnitType() == Unit.GREAT_ENGINEER:
- pCity.changeFreeSpecialistCount(
- gc.getInfoTypeForString("SPECIALIST_ENGINEER"), 1
- )
- elif pUnit.getUnitType() == Unit.GREAT_SPY:
- pCity.changeFreeSpecialistCount(
- gc.getInfoTypeForString("SPECIALIST_SPY"), 1
- )
- # Absinthe: Peterhof Palace start
- return
- CvUtil.pyPrint(
- "A %s was born for %s in %s"
- % (pUnit.getName(), player.getCivilizationName(), pCity.getName())
- )
def onTechAcquired(self, argsList):
- ## Platy Builder ##
- if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderScreen.bPython:
- return
- ## Platy Builder ##
"Tech Acquired"
iTechType, iTeam, iPlayer, bAnnounce = argsList
- # Note that iPlayer may be NULL (-1) and not a refer to a player object
-
- # Show tech splash when applicable
- if iPlayer > -1 and bAnnounce and not CyInterface().noTechSplash():
- if gc.getGame().isFinalInitialized() and not gc.getGame().GetWorldBuilderMode():
- if (not gc.getGame().isNetworkMultiPlayer()) and (
- iPlayer == gc.getGame().getActivePlayer()
- ):
- popupInfo = CyPopupInfo()
- popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_PYTHON_SCREEN)
- popupInfo.setData1(iTechType)
- popupInfo.setText(u"showTechSplash")
- popupInfo.addPopup(iPlayer)
-
- if not self.__LOG_TECH:
- return
- CvUtil.pyPrint(
- "%s was finished by Team %d"
- % (PyInfo.TechnologyInfo(iTechType).getDescription(), iTeam)
- )
def onTechSelected(self, argsList):
"Tech Selected"
iTechType, iPlayer = argsList
- if not self.__LOG_TECH:
- return
- CvUtil.pyPrint(
- "%s was selected by Player %d"
- % (PyInfo.TechnologyInfo(iTechType).getDescription(), iPlayer)
- )
def onReligionFounded(self, argsList):
- ## Platy Builder ##
- if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderScreen.bPython:
- return
- ## Platy Builder ##
"Religion Founded"
iReligion, iFounder = argsList
- player = PyPlayer(iFounder)
-
- iCityId = gc.getGame().getHolyCity(iReligion).getID()
- if gc.getGame().isFinalInitialized() and not gc.getGame().GetWorldBuilderMode():
- if (not gc.getGame().isNetworkMultiPlayer()) and (
- iFounder == gc.getGame().getActivePlayer()
- ):
- popupInfo = CyPopupInfo()
- popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_PYTHON_SCREEN)
- popupInfo.setData1(iReligion)
- popupInfo.setData2(iCityId)
- popupInfo.setData3(1)
- popupInfo.setText(u"showWonderMovie")
- popupInfo.addPopup(iFounder)
-
- if not self.__LOG_RELIGION:
- return
- CvUtil.pyPrint(
- "Player %d Civilization %s has founded %s"
- % (
- iFounder,
- player.getCivilizationName(),
- gc.getReligionInfo(iReligion).getDescription(),
- )
- )
def onReligionSpread(self, argsList):
- ## Platy Builder ##
- if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderScreen.bPython:
- return
- ## Platy Builder ##
"Religion Has Spread to a City"
iReligion, iOwner, pSpreadCity = argsList
- player = PyPlayer(iOwner)
- if not self.__LOG_RELIGIONSPREAD:
- return
- CvUtil.pyPrint(
- "%s has spread to Player %d Civilization %s city of %s"
- % (
- gc.getReligionInfo(iReligion).getDescription(),
- iOwner,
- player.getCivilizationName(),
- pSpreadCity.getName(),
- )
- )
def onReligionRemove(self, argsList):
- ## Platy Builder ##
- if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderScreen.bPython:
- return
- ## Platy Builder ##
"Religion Has been removed from a City"
iReligion, iOwner, pRemoveCity = argsList
- player = PyPlayer(iOwner)
- if not self.__LOG_RELIGIONSPREAD:
- return
- CvUtil.pyPrint(
- "%s has been removed from Player %d Civilization %s city of %s"
- % (
- gc.getReligionInfo(iReligion).getDescription(),
- iOwner,
- player.getCivilizationName(),
- pRemoveCity.getName(),
- )
- )
def onCorporationFounded(self, argsList):
- ## Platy Builder ##
- if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderScreen.bPython:
- return
- ## Platy Builder ##
"Corporation Founded"
iCorporation, iFounder = argsList
- player = PyPlayer(iFounder)
-
- if not self.__LOG_RELIGION:
- return
- CvUtil.pyPrint(
- "Player %d Civilization %s has founded %s"
- % (
- iFounder,
- player.getCivilizationName(),
- gc.getCorporationInfo(iCorporation).getDescription(),
- )
- )
def onCorporationSpread(self, argsList):
- ## Platy Builder ##
- if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderScreen.bPython:
- return
- ## Platy Builder ##
"Corporation Has Spread to a City"
iCorporation, iOwner, pSpreadCity = argsList
- player = PyPlayer(iOwner)
- if not self.__LOG_RELIGIONSPREAD:
- return
- CvUtil.pyPrint(
- "%s has spread to Player %d Civilization %s city of %s"
- % (
- gc.getCorporationInfo(iCorporation).getDescription(),
- iOwner,
- player.getCivilizationName(),
- pSpreadCity.getName(),
- )
- )
def onCorporationRemove(self, argsList):
- ## Platy Builder ##
- if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderScreen.bPython:
- return
- ## Platy Builder ##
"Corporation Has been removed from a City"
iCorporation, iOwner, pRemoveCity = argsList
- player = PyPlayer(iOwner)
- if not self.__LOG_RELIGIONSPREAD:
- return
- CvUtil.pyPrint(
- "%s has been removed from Player %d Civilization %s city of %s"
- % (
- gc.getReligionInfo(iReligion).getDescription(), # type: ignore
- iOwner,
- player.getCivilizationName(),
- pRemoveCity.getName(),
- )
- )
def onGoldenAge(self, argsList):
- ## Platy Builder ##
- if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderScreen.bPython:
- return
- ## Platy Builder ##
"Golden Age"
iPlayer = argsList[0]
- player = PyPlayer(iPlayer)
- if not self.__LOG_GOLDENAGE:
- return
- CvUtil.pyPrint(
- "Player %d Civilization %s has begun a golden age"
- % (iPlayer, player.getCivilizationName())
- )
def onEndGoldenAge(self, argsList):
- ## Platy Builder ##
- if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderScreen.bPython:
- return
- ## Platy Builder ##
"End Golden Age"
iPlayer = argsList[0]
- player = PyPlayer(iPlayer)
- if not self.__LOG_ENDGOLDENAGE:
- return
- CvUtil.pyPrint(
- "Player %d Civilization %s golden age has ended"
- % (iPlayer, player.getCivilizationName())
- )
# Absinthe: currently unused
def onChangeWar(self, argsList):
- ## Platy Builder ##
- if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderScreen.bPython:
- return
- ## Platy Builder ##
"War Status Changes"
bIsWar = argsList[0]
iTeam = argsList[1]
iRivalTeam = argsList[2]
- if not self.__LOG_WARPEACE:
- return
- if bIsWar:
- strStatus = "declared war"
- else:
- strStatus = "declared peace"
- CvUtil.pyPrint("Team %d has %s on Team %d" % (iTeam, strStatus, iRivalTeam))
def onChat(self, argsList):
"Chat Message Event"
@@ -1561,34 +447,20 @@ def onSetPlayerAlive(self, argsList):
bNewValue = argsList[1]
CvUtil.pyPrint("Player %d's alive status set to: %d" % (iPlayerID, int(bNewValue)))
- # Absinthe: Python Event for civic changes
def onPlayerChangeAllCivics(self, argsList):
# note that this only reports civic change if it happened via normal revolution
"Player changes his civics"
iPlayer = argsList[0]
- lNewCivics = [argsList[1], argsList[2], argsList[3], argsList[4], argsList[5], argsList[6]]
- lOldCivics = [
- argsList[7],
- argsList[8],
- argsList[9],
- argsList[10],
- argsList[11],
- argsList[12],
- ]
def onPlayerChangeSingleCivic(self, argsList):
# note that this reports all civic changes in single instances (so also reports force converts by diplomacy or with spies)
"Civics are changed for a player"
iPlayer, iNewCivic, iOldCivic = argsList
- # Absinthe: end
-
def onPlayerChangeStateReligion(self, argsList):
- ## Platy Builder ##
- if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderScreen.bPython:
- return
- ## Platy Builder ##
"Player changes his state religion"
+ if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderSettings.bPython:
+ return
iPlayer, iNewReligion, iOldReligion = argsList
def onPlayerGoldTrade(self, argsList):
@@ -1598,544 +470,26 @@ def onPlayerGoldTrade(self, argsList):
def onCityBuilt(self, argsList):
"City Built"
city = argsList[0]
- iPlayer = city.getOwner()
- pPlayer = gc.getPlayer(iPlayer)
-
- # Absinthe: city naming popup on city foundation - settable in GlobalDefines_Alt.xml
- bCityNamePopup = gc.getDefineINT("CITY_NAME_POPUP") == 1
- if bCityNamePopup:
- if iPlayer == gc.getGame().getActivePlayer():
- self.__eventEditCityNameBegin(city, False)
- # Absinthe: end
-
- # Absinthe: Jasna Gora start
- if pPlayer.countNumBuildings(Wonder.JASNA_GORA) > 0:
- city.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_CATHOLIC_TEMPLE"),
- CommerceTypes.COMMERCE_CULTURE,
- 1,
- )
- city.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_ORTHODOX_TEMPLE"),
- CommerceTypes.COMMERCE_CULTURE,
- 1,
- )
- city.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_PROTESTANT_TEMPLE"),
- CommerceTypes.COMMERCE_CULTURE,
- 1,
- )
- city.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_ISLAMIC_TEMPLE"),
- CommerceTypes.COMMERCE_CULTURE,
- 1,
- )
- # Absinthe: Jasna Gora end
-
- # Absinthe: Kizil Kule start
- if pPlayer.countNumBuildings(Wonder.KIZIL_KULE) > 0:
- city.setBuildingYieldChange(
- gc.getInfoTypeForString("BUILDINGCLASS_HARBOR"), YieldTypes.YIELD_COMMERCE, 2
- )
- # Absinthe: Kizil Kule end
-
- # Absinthe: Samogitian Alkas start
- if pPlayer.countNumBuildings(Wonder.SAMOGITIAN_ALKAS) > 0:
- city.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_PAGAN_SHRINE"),
- CommerceTypes.COMMERCE_RESEARCH,
- 2,
- )
- # Absinthe: Samogitian Alkas end
-
- # Absinthe: Magna Carta start
- if pPlayer.countNumBuildings(Wonder.MAGNA_CARTA) > 0:
- city.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_COURTHOUSE"),
- CommerceTypes.COMMERCE_CULTURE,
- 2,
- )
- # Absinthe: Magna Carta end
-
- CvUtil.pyPrint("City Built Event: %s" % (city.getName()))
def onCityRazed(self, argsList):
"City Razed"
city, iPlayer = argsList
- # Rhye - start bugfix
- owner = PyPlayer(city.getOwner())
- if city.getOwner() == iPlayer:
- if city.getPreviousOwner() != -1:
- owner = PyPlayer(city.getPreviousOwner())
- # Rhye - end bugfix
-
- CvUtil.pyPrint("City Razed Event: %s" % (city.getName(),))
- razor = PyPlayer(iPlayer)
- CvUtil.pyPrint(
- "Player %d Civilization %s City %s was razed by Player %d Civilization %s"
- % (
- owner.getID(),
- owner.getCivilizationName(),
- city.getName(),
- razor.getID(),
- razor.getCivilizationName(),
- )
- )
-
- # Absinthe: Al-Azhar University start
- if city.getNumActiveBuilding(Wonder.ALAZHAR):
- pPlayer = gc.getPlayer(iPlayer)
- iTeam = pPlayer.getTeam()
- pTeam = gc.getTeam(iTeam)
- for iTech in xrange(gc.getNumTechInfos()): # type: ignore
- if not pTeam.isHasTech(iTech):
- if gc.getTechInfo(iTech).getAdvisorType() == gc.getInfoTypeForString(
- "ADVISOR_RELIGION"
- ):
- pTeam.changeResearchProgress(
- iTech,
- max(
- -pPreviousTeam.getResearchProgress(iTech), # type: ignore
- -pTeam.getResearchCost(iTech) / 5,
- ),
- iPlayer,
- )
- # Absinthe: Al-Azhar University end
-
- # Absinthe: Sistine Chapel start
- if city.getNumActiveBuilding(Wonder.SISTINE_CHAPEL):
- for loopCity in cities().owner(iPlayer).entities():
- if loopCity.getNumWorldWonders() > 0:
- loopCity.changeFreeSpecialistCount(
- gc.getInfoTypeForString("SPECIALIST_ARTIST"), -1
- )
- # Absinthe: Sistine Chapel end
-
- # Absinthe: Jasna Gora start
- if city.getNumActiveBuilding(Wonder.JASNA_GORA):
- for loopCity in cities().owner(iPlayer).entities():
- loopCity.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_CATHOLIC_TEMPLE"),
- CommerceTypes.COMMERCE_CULTURE,
- 0,
- )
- loopCity.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_ORTHODOX_TEMPLE"),
- CommerceTypes.COMMERCE_CULTURE,
- 0,
- )
- loopCity.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_PROTESTANT_TEMPLE"),
- CommerceTypes.COMMERCE_CULTURE,
- 0,
- )
- loopCity.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_ISLAMIC_TEMPLE"),
- CommerceTypes.COMMERCE_CULTURE,
- 0,
- )
- # Absinthe: Jasna Gora end
-
- # Absinthe: Kizil Kule start
- if city.getNumActiveBuilding(Wonder.KIZIL_KULE):
- for loopCity in cities().owner(iPlayer).entities():
- loopCity.setBuildingYieldChange(
- gc.getInfoTypeForString("BUILDINGCLASS_HARBOR"), YieldTypes.YIELD_COMMERCE, 0
- )
- # Absinthe: Kizil Kule end
-
- # Absinthe: Samogitian Alkas start
- if city.getNumActiveBuilding(Wonder.SAMOGITIAN_ALKAS):
- for loopCity in cities().owner(iPlayer).entities():
- loopCity.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_PAGAN_SHRINE"),
- CommerceTypes.COMMERCE_RESEARCH,
- 0,
- )
- # Absinthe: Samogitian Alkas end
-
- # Absinthe: Magna Carta start
- if city.getNumActiveBuilding(Wonder.MAGNA_CARTA):
- for loopCity in cities().owner(iPlayer).entities():
- loopCity.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_COURTHOUSE"),
- CommerceTypes.COMMERCE_CULTURE,
- 0,
- )
- # Absinthe: Magna Carta end
-
- # Absinthe: wonder destroyed message start
- if city.getNumWorldWonders() > 0:
- ConquerPlayer = gc.getPlayer(city.getOwner())
- ConquerTeam = ConquerPlayer.getTeam()
- if city.getPreviousOwner() != -1:
- PreviousPlayer = gc.getPlayer(city.getPreviousOwner())
- PreviousTeam = PreviousPlayer.getTeam()
- HumanTeam = team()
- if ConquerPlayer.isHuman() or (
- player().isExisting()
- and (HumanTeam.isHasMet(ConquerTeam) or HumanTeam.isHasMet(PreviousTeam))
- ):
- # Absinthe: collect all wonders, including shrines (even though cities with shrines can't be destroyed in the mod)
- lAllWonders = [w for w in Wonder]
- for iWonder in [
- Building.CATHOLIC_SHRINE,
- Building.ORTHODOX_SHRINE,
- Building.ISLAMIC_SHRINE,
- Building.PROTESTANT_SHRINE,
- ]:
- lAllWonders.append(iWonder)
- for iWonder in lAllWonders:
- if city.getNumBuilding(iWonder) > 0:
- sWonderName = gc.getBuildingInfo(iWonder).getDescription()
- if ConquerPlayer.isHuman():
- message(
- human(),
- text("TXT_KEY_MISC_WONDER_DESTROYED_1", sWonderName),
- event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
- button=gc.getBuildingInfo(iWonder).getButton(),
- color=MessageData.LIGHT_RED,
- location=city,
- )
- elif HumanTeam.isHasMet(ConquerTeam):
- ConquerName = ConquerPlayer.getCivilizationDescriptionKey()
- message(
- human(),
- text("TXT_KEY_MISC_WONDER_DESTROYED_2", ConquerName, sWonderName),
- event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
- button=gc.getBuildingInfo(iWonder).getButton(),
- color=MessageData.LIGHT_RED,
- location=city,
- )
- elif HumanTeam.isHasMet(PreviousTeam):
- PreviousName = PreviousPlayer.getCivilizationDescriptionKey()
- message(
- human(),
- text("TXT_KEY_MISC_WONDER_DESTROYED_3", PreviousName, sWonderName),
- event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
- button=gc.getBuildingInfo(iWonder).getButton(),
- color=MessageData.LIGHT_RED,
- location=city,
- )
- # Absinthe: wonder destroyed message end
-
- # Absinthe: Partisans! - not used currently
- # if city.getPopulation > 1 and iOwner != -1 and iPlayer != -1:
- # owner = gc.getPlayer(iOwner)
- # if not owner.isBarbarian() and owner.getNumCities() > 0:
- # if gc.getTeam(owner.getTeam()).isAtWar(gc.getPlayer(iPlayer).getTeam()):
- # if gc.getNumEventTriggerInfos() > 0: # prevents mods that don't have events from getting an error
- # iEvent = CvUtil.findInfoTypeNum(gc.getEventTriggerInfo, gc.getNumEventTriggerInfos(),'EVENTTRIGGER_PARTISANS')
- # if iEvent != -1 and gc.getGame().isEventActive(iEvent) and owner.getEventTriggerWeight(iEvent) < 0:
- # triggerData = owner.initTriggeredData(iEvent, True, -1, city.getX(), city.getY(), iPlayer, city.getID(), -1, -1, -1, -1)
- # Absinthe: end
-
def onCityAcquired(self, argsList):
- ## Platy Builder ##
- if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderScreen.bPython:
- return
- ## Platy Builder ##
"City Acquired"
iPreviousOwner, iNewOwner, pCity, bConquest, bTrade = argsList
- CvUtil.pyPrint("City Acquired Event: %s" % (pCity.getName()))
- pPreviousOwner = gc.getPlayer(iPreviousOwner)
- pNewOwner = gc.getPlayer(iNewOwner)
-
- # Absinthe: Al-Azhar University start
- if pCity.getNumActiveBuilding(Wonder.ALAZHAR):
- iPreviousTeam = pPreviousOwner.getTeam()
- pPreviousTeam = gc.getTeam(iPreviousTeam)
- iNewTeam = pNewOwner.getTeam()
- pNewTeam = gc.getTeam(iNewTeam)
- for iTech in xrange(gc.getNumTechInfos()): # type: ignore
- if gc.getTechInfo(iTech).getAdvisorType() == gc.getInfoTypeForString(
- "ADVISOR_RELIGION"
- ):
- if not pPreviousTeam.isHasTech(iTech):
- research_cost = pPreviousTeam.getResearchCost(iTech)
- pPreviousTeam.changeResearchProgress(
- iTech,
- max(-pPreviousTeam.getResearchProgress(iTech), -research_cost / 5),
- iPreviousOwner,
- )
- if not pNewTeam.isHasTech(iTech):
- research_cost = pNewTeam.getResearchCost(iTech)
- pNewTeam.changeResearchProgress(
- iTech,
- min(
- research_cost - pNewTeam.getResearchProgress(iTech),
- research_cost / 5,
- ),
- iNewOwner,
- )
- # Absinthe: Al-Azhar University end
-
- # Absinthe: Sistine Chapel start
- if pCity.getNumActiveBuilding(Wonder.SISTINE_CHAPEL):
- for loopCity in cities().owner(iPreviousOwner).entities():
- if loopCity.getNumWorldWonders() > 0:
- loopCity.changeFreeSpecialistCount(
- gc.getInfoTypeForString("SPECIALIST_ARTIST"), -1
- )
- for loopCity in cities().owner(iNewOwner).entities():
- if loopCity.getNumWorldWonders() > 0 and not loopCity.getNumActiveBuilding(
- Wonder.SISTINE_CHAPEL
- ):
- loopCity.changeFreeSpecialistCount(
- gc.getInfoTypeForString("SPECIALIST_ARTIST"), 1
- )
- elif pCity.getNumWorldWonders() > 0:
- if pPreviousOwner.countNumBuildings(Wonder.SISTINE_CHAPEL) > 0:
- pCity.changeFreeSpecialistCount(gc.getInfoTypeForString("SPECIALIST_ARTIST"), -1)
- elif pNewOwner.countNumBuildings(Wonder.SISTINE_CHAPEL) > 0:
- pCity.changeFreeSpecialistCount(gc.getInfoTypeForString("SPECIALIST_ARTIST"), 1)
- # Absinthe: Sistine Chapel end
-
- # Absinthe: Jasna Gora start
- if pCity.getNumActiveBuilding(Wonder.JASNA_GORA):
- for loopCity in cities().owner(iPreviousOwner).entities():
- loopCity.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_CATHOLIC_TEMPLE"),
- CommerceTypes.COMMERCE_CULTURE,
- 0,
- )
- loopCity.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_ORTHODOX_TEMPLE"),
- CommerceTypes.COMMERCE_CULTURE,
- 0,
- )
- loopCity.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_PROTESTANT_TEMPLE"),
- CommerceTypes.COMMERCE_CULTURE,
- 0,
- )
- loopCity.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_ISLAMIC_TEMPLE"),
- CommerceTypes.COMMERCE_CULTURE,
- 0,
- )
- for loopCity in cities().owner(iNewOwner).entities():
- loopCity.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_CATHOLIC_TEMPLE"),
- CommerceTypes.COMMERCE_CULTURE,
- 1,
- )
- loopCity.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_ORTHODOX_TEMPLE"),
- CommerceTypes.COMMERCE_CULTURE,
- 1,
- )
- loopCity.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_PROTESTANT_TEMPLE"),
- CommerceTypes.COMMERCE_CULTURE,
- 1,
- )
- loopCity.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_ISLAMIC_TEMPLE"),
- CommerceTypes.COMMERCE_CULTURE,
- 1,
- )
- elif pPreviousOwner.countNumBuildings(Wonder.JASNA_GORA) > 0:
- pCity.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_CATHOLIC_TEMPLE"),
- CommerceTypes.COMMERCE_CULTURE,
- 0,
- )
- pCity.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_ORTHODOX_TEMPLE"),
- CommerceTypes.COMMERCE_CULTURE,
- 0,
- )
- pCity.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_PROTESTANT_TEMPLE"),
- CommerceTypes.COMMERCE_CULTURE,
- 0,
- )
- pCity.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_ISLAMIC_TEMPLE"),
- CommerceTypes.COMMERCE_CULTURE,
- 0,
- )
- elif pNewOwner.countNumBuildings(Wonder.JASNA_GORA) > 0:
- pCity.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_CATHOLIC_TEMPLE"),
- CommerceTypes.COMMERCE_CULTURE,
- 1,
- )
- pCity.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_ORTHODOX_TEMPLE"),
- CommerceTypes.COMMERCE_CULTURE,
- 1,
- )
- pCity.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_PROTESTANT_TEMPLE"),
- CommerceTypes.COMMERCE_CULTURE,
- 1,
- )
- pCity.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_ISLAMIC_TEMPLE"),
- CommerceTypes.COMMERCE_CULTURE,
- 1,
- )
- # Absinthe: Jasna Gora end
-
- # Absinthe: Kizil Kule start
- if pCity.getNumActiveBuilding(Wonder.KIZIL_KULE):
- for loopCity in cities().owner(iPreviousOwner).entities():
- loopCity.setBuildingYieldChange(
- gc.getInfoTypeForString("BUILDINGCLASS_HARBOR"), YieldTypes.YIELD_COMMERCE, 0
- )
- for loopCity in cities().owner(iNewOwner).entities():
- loopCity.setBuildingYieldChange(
- gc.getInfoTypeForString("BUILDINGCLASS_HARBOR"), YieldTypes.YIELD_COMMERCE, 2
- )
- elif pPreviousOwner.countNumBuildings(Wonder.KIZIL_KULE) > 0:
- pCity.setBuildingYieldChange(
- gc.getInfoTypeForString("BUILDINGCLASS_HARBOR"), YieldTypes.YIELD_COMMERCE, 0
- )
- elif pNewOwner.countNumBuildings(Wonder.KIZIL_KULE) > 0:
- pCity.setBuildingYieldChange(
- gc.getInfoTypeForString("BUILDINGCLASS_HARBOR"), YieldTypes.YIELD_COMMERCE, 2
- )
- # Absinthe: Kizil Kule end
-
- # Absinthe: Samogitian Alkas start
- if pCity.getNumActiveBuilding(Wonder.SAMOGITIAN_ALKAS):
- for loopCity in cities().owner(iPreviousOwner).entities():
- loopCity.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_PAGAN_SHRINE"),
- CommerceTypes.COMMERCE_RESEARCH,
- 0,
- )
- for loopCity in cities().owner(iNewOwner).entities():
- loopCity.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_PAGAN_SHRINE"),
- CommerceTypes.COMMERCE_RESEARCH,
- 2,
- )
- elif pPreviousOwner.countNumBuildings(Wonder.SAMOGITIAN_ALKAS) > 0:
- pCity.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_PAGAN_SHRINE"),
- CommerceTypes.COMMERCE_RESEARCH,
- 0,
- )
- elif pNewOwner.countNumBuildings(Wonder.SAMOGITIAN_ALKAS) > 0:
- pCity.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_PAGAN_SHRINE"),
- CommerceTypes.COMMERCE_RESEARCH,
- 2,
- )
- # Absinthe: Samogitian Alkas end
-
- # Absinthe: Magna Carta start
- if pCity.getNumActiveBuilding(Wonder.MAGNA_CARTA):
- for loopCity in cities().owner(iPreviousOwner).entities():
- loopCity.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_COURTHOUSE"),
- CommerceTypes.COMMERCE_CULTURE,
- 0,
- )
- for loopCity in cities().owner(iNewOwner).entities():
- loopCity.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_COURTHOUSE"),
- CommerceTypes.COMMERCE_CULTURE,
- 2,
- )
- elif pPreviousOwner.countNumBuildings(Wonder.MAGNA_CARTA) > 0:
- pCity.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_COURTHOUSE"),
- CommerceTypes.COMMERCE_CULTURE,
- 0,
- )
- elif pNewOwner.countNumBuildings(Wonder.MAGNA_CARTA) > 0:
- pCity.setBuildingCommerceChange(
- gc.getInfoTypeForString("BUILDINGCLASS_COURTHOUSE"),
- CommerceTypes.COMMERCE_CULTURE,
- 2,
- )
- # Absinthe: Magna Carta end
def onCityAcquiredAndKept(self, argsList):
"City Acquired and Kept"
iOwner, pCity = argsList
- # Absinthe: wonder captured message start
- if pCity.getNumWorldWonders() > 0:
- ConquerPlayer = gc.getPlayer(pCity.getOwner())
- ConquerTeam = ConquerPlayer.getTeam()
- if pCity.getPreviousOwner() != -1:
- PreviousPlayer = gc.getPlayer(pCity.getPreviousOwner())
- PreviousTeam = PreviousPlayer.getTeam()
- HumanTeam = team()
- if ConquerPlayer.isHuman() or (
- player().isExisting()
- and (HumanTeam.isHasMet(ConquerTeam) or HumanTeam.isHasMet(PreviousTeam))
- ):
- # Absinthe: collect all wonders, including shrines
- lAllWonders = [w for w in Wonder] + [
- Building.CATHOLIC_SHRINE,
- Building.ORTHODOX_SHRINE,
- Building.ISLAMIC_SHRINE,
- Building.PROTESTANT_SHRINE,
- ]
- for iWonder in lAllWonders:
- if pCity.getNumBuilding(iWonder) > 0:
- sWonderName = gc.getBuildingInfo(iWonder).getDescription()
- if ConquerPlayer.isHuman():
- message(
- human(),
- text("TXT_KEY_MISC_WONDER_CAPTURED_1", sWonderName),
- event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
- button=gc.getBuildingInfo(iWonder).getButton(),
- color=MessageData.BLUE,
- location=pCity,
- )
- elif HumanTeam.isHasMet(ConquerTeam):
- ConquerName = ConquerPlayer.getCivilizationDescriptionKey()
- message(
- human(),
- text("TXT_KEY_MISC_WONDER_CAPTURED_2", ConquerName, sWonderName),
- event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
- button=gc.getBuildingInfo(iWonder).getButton(),
- color=MessageData.CYAN,
- location=pCity,
- )
- elif HumanTeam.isHasMet(PreviousTeam):
- PreviousName = PreviousPlayer.getCivilizationDescriptionKey()
- message(
- human(),
- text("TXT_KEY_MISC_WONDER_CAPTURED_3", PreviousName, sWonderName),
- event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
- button=gc.getBuildingInfo(iWonder).getButton(),
- color=MessageData.CYAN,
- location=pCity,
- )
- # Absinthe: wonder captured message end
-
- CvUtil.pyPrint("City Acquired and Kept Event: %s" % (pCity.getName()))
- CvUtil.pyPrint(
- "NewOwner: %s, PreviousOwner: %s"
- % (
- PyPlayer(pCity.getOwner()).getCivilizationName(),
- PyPlayer(pCity.getPreviousOwner()).getCivilizationName(),
- )
- )
-
def onCityLost(self, argsList):
"City Lost"
city = argsList[0]
- player = PyPlayer(city.getOwner())
- if not self.__LOG_CITYLOST:
- return
- CvUtil.pyPrint(
- "City %s was lost by Player %d Civilization %s"
- % (city.getName(), player.getID(), player.getCivilizationName())
- )
def onCultureExpansion(self, argsList):
## Platy Builder ##
- if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderScreen.bPython:
+ if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderSettings.bPython:
return
## Platy Builder ##
"City Culture Expansion"
@@ -2154,35 +508,19 @@ def onCityDoTurn(self, argsList):
pCity = argsList[0]
iPlayer = argsList[1]
- CvAdvisorUtils.cityAdvise(pCity, iPlayer)
-
def onCityBuildingUnit(self, argsList):
"City begins building a unit"
pCity = argsList[0]
iUnitType = argsList[1]
- if not self.__LOG_CITYBUILDING:
- return
- CvUtil.pyPrint(
- "%s has begun building a %s"
- % (pCity.getName(), gc.getUnitInfo(iUnitType).getDescription())
- )
def onCityBuildingBuilding(self, argsList):
"City begins building a Building"
pCity = argsList[0]
iBuildingType = argsList[1]
- if not self.__LOG_CITYBUILDING:
- return
- CvUtil.pyPrint(
- "%s has begun building a %s"
- % (pCity.getName(), gc.getBuildingInfo(iBuildingType).getDescription())
- )
def onCityRename(self, argsList):
"City is renamed"
pCity = argsList[0]
- if pCity.getOwner() == gc.getGame().getActivePlayer():
- self.__eventEditCityNameBegin(pCity, True)
def onCityHurry(self, argsList):
"City is renamed"
@@ -2192,39 +530,11 @@ def onCityHurry(self, argsList):
def onVictory(self, argsList):
"Victory"
iTeam, iVictory = argsList
- if iVictory >= 0 and iVictory < gc.getNumVictoryInfos():
- victoryInfo = gc.getVictoryInfo(int(iVictory))
- CvUtil.pyPrint(
- "Victory! Team %d achieves a %s victory" % (iTeam, victoryInfo.getDescription())
- )
def onVassalState(self, argsList):
"Vassal State"
iMaster, iVassal, bVassal = argsList
- if bVassal:
- # Absinthe: Imperial Diet start
- MasterTeam = gc.getTeam(iMaster)
- for iPlayer in civilizations().majors().ids():
- pPlayer = gc.getPlayer(iPlayer)
- if (
- pPlayer.getTeam() == iMaster
- and pPlayer.countNumBuildings(Wonder.IMPERIAL_DIET) > 0
- ):
- pPlayer.changeGoldenAgeTurns(3)
- if human() == iPlayer:
- message(
- iPlayer,
- text("TXT_KEY_BUILDING_IMPERIAL_DIET_EFFECT"),
- color=MessageData.LIGHT_BLUE,
- )
- # Absinthe: Imperial Diet end
- CvUtil.pyPrint("Team %d becomes a Vassal State of Team %d" % (iVassal, iMaster))
- else:
- CvUtil.pyPrint(
- "Team %d revolts and is no longer a Vassal State of Team %d" % (iVassal, iMaster)
- )
-
def onGameUpdate(self, argsList):
"sample generic event, called on each game turn slice"
genericArgs = argsList[0][0] # tuple of tuple of my args
@@ -2232,200 +542,4 @@ def onGameUpdate(self, argsList):
def onMouseEvent(self, argsList):
"mouse handler - returns 1 if the event was consumed"
- eventType, mx, my, px, py, interfaceConsumed, screens = argsList
- if px != -1 and py != -1:
- if eventType == self.EventLButtonDown:
- if (
- self.bAllowCheats
- and self.bCtrl
- and self.bAlt
- and CyMap().plot(px, py).isCity()
- and not interfaceConsumed
- ):
- # Launch Edit City Event
- self.beginEvent(CvUtil.EventEditCity, (px, py))
- return 1
-
- elif self.bAllowCheats and self.bCtrl and self.bShift and not interfaceConsumed:
- # Launch Place Object Event
- self.beginEvent(CvUtil.EventPlaceObject, (px, py))
- return 1
-
- if eventType == self.EventBack:
- return CvScreensInterface.handleBack(screens)
- elif eventType == self.EventForward:
- return CvScreensInterface.handleForward(screens)
-
return 0
-
- #################### TRIGGERED EVENTS ##################
-
- def __eventEditCityNameBegin(self, city, bRename):
- popup = PyPopup.PyPopup(CvUtil.EventEditCityName, EventContextTypes.EVENTCONTEXT_ALL)
- popup.setUserData((city.getID(), bRename))
- popup.setHeaderString(text("TXT_KEY_NAME_CITY"))
- popup.setBodyString(text("TXT_KEY_SETTLE_NEW_CITY_NAME"))
- # Absinthe: if not a rename, it should offer the CNM__eventEditCityBegin name as the default name
- if bRename:
- popup.createEditBox(city.getName())
- else:
- szName = get_data_from_upside_down_map(CITIES_MAP, city.getOwner(), city)
- if szName == "-1":
- popup.createEditBox(city.getName())
- else:
- szName = unicode(szName)
- popup.createEditBox(szName)
- # Absinthe: end
- popup.setEditBoxMaxCharCount(15)
- popup.launch()
-
- def __eventEditCityNameApply(self, playerID, userData, popupReturn):
- "Edit City Name Event"
- iCityID = userData[0]
- bRename = userData[1]
- player = gc.getPlayer(playerID)
- city = player.getCity(iCityID)
- cityName = popupReturn.getEditBoxString(0)
- if len(cityName) > 30:
- cityName = cityName[:30]
- city.setName(cityName, not bRename)
-
- def __eventEditCityBegin(self, argsList):
- "Edit City Event"
- px, py = argsList
- CvWBPopups.CvWBPopups().initEditCity(argsList)
-
- def __eventEditCityApply(self, playerID, userData, popupReturn):
- "Edit City Event Apply"
- if getChtLvl() > 0:
- CvWBPopups.CvWBPopups().applyEditCity((popupReturn, userData))
-
- def __eventPlaceObjectBegin(self, argsList):
- "Place Object Event"
- CvDebugTools.CvDebugTools().initUnitPicker(argsList)
-
- def __eventPlaceObjectApply(self, playerID, userData, popupReturn):
- "Place Object Event Apply"
- if getChtLvl() > 0:
- CvDebugTools.CvDebugTools().applyUnitPicker((popupReturn, userData))
-
- def __eventAwardTechsAndGoldBegin(self, argsList):
- "Award Techs & Gold Event"
- CvDebugTools.CvDebugTools().cheatTechs()
-
- def __eventAwardTechsAndGoldApply(self, playerID, netUserData, popupReturn):
- "Award Techs & Gold Event Apply"
- if getChtLvl() > 0:
- CvDebugTools.CvDebugTools().applyTechCheat((popupReturn))
-
- def __eventShowWonderBegin(self, argsList):
- "Show Wonder Event"
- CvDebugTools.CvDebugTools().wonderMovie()
-
- def __eventShowWonderApply(self, playerID, netUserData, popupReturn):
- "Wonder Movie Apply"
- if getChtLvl() > 0:
- CvDebugTools.CvDebugTools().applyWonderMovie((popupReturn))
-
- ## Platy Builder ##
- def __eventEditUnitNameBegin(self, argsList):
- pUnit = argsList
- popup = PyPopup.PyPopup(CvUtil.EventEditUnitName, EventContextTypes.EVENTCONTEXT_ALL)
- popup.setUserData((pUnit.getID(), CyGame().getActivePlayer()))
- popup.setBodyString(text("TXT_KEY_RENAME_UNIT"))
- popup.createEditBox(pUnit.getNameNoDesc())
- popup.setEditBoxMaxCharCount(25)
- popup.launch()
-
- def __eventEditUnitNameApply(self, playerID, userData, popupReturn):
- unit = gc.getPlayer(userData[1]).getUnit(userData[0])
- newName = popupReturn.getEditBoxString(0)
- unit.setName(newName)
- if CyGame().GetWorldBuilderMode():
- WBUnitScreen.WBUnitScreen(CvPlatyBuilderScreen.CvWorldBuilderScreen()).placeStats()
- WBUnitScreen.WBUnitScreen(
- CvPlatyBuilderScreen.CvWorldBuilderScreen()
- ).placeCurrentUnit()
-
- def __eventEditCityNameBegin(self, city, bRename):
- popup = PyPopup.PyPopup(CvUtil.EventEditCityName, EventContextTypes.EVENTCONTEXT_ALL)
- popup.setUserData((city.getID(), bRename, CyGame().getActivePlayer()))
- popup.setHeaderString(text("TXT_KEY_NAME_CITY"))
- popup.setBodyString(text("TXT_KEY_SETTLE_NEW_CITY_NAME"))
- # Absinthe: if not a rename, it should offer the CNM__eventEditCityBegin name as the default name
- if bRename:
- popup.createEditBox(city.getName())
- else:
- szName = get_data_from_upside_down_map(CITIES_MAP, city.getOwner(), city)
- if szName == "-1":
- popup.createEditBox(city.getName())
- else:
- szName = unicode(szName)
- popup.createEditBox(szName)
- # Absinthe: end
- popup.setEditBoxMaxCharCount(15)
- popup.launch()
-
- def __eventEditCityNameApply(self, playerID, userData, popupReturn):
- city = gc.getPlayer(userData[2]).getCity(userData[0])
- cityName = popupReturn.getEditBoxString(0)
- city.setName(cityName, not userData[1])
- if CyGame().GetWorldBuilderMode() and not CyGame().isInAdvancedStart():
- WBCityEditScreen.WBCityEditScreen().placeStats()
-
- def __eventWBUnitScriptPopupApply(self, playerID, userData, popupReturn):
- sScript = popupReturn.getEditBoxString(0)
- pUnit = gc.getPlayer(userData[0]).getUnit(userData[1])
- pUnit.setScriptData(CvUtil.convertToStr(sScript))
- WBUnitScreen.WBUnitScreen(CvPlatyBuilderScreen.CvWorldBuilderScreen()).placeScript()
- return
-
- def __eventWBPlayerScriptPopupApply(self, playerID, userData, popupReturn):
- sScript = popupReturn.getEditBoxString(0)
- gc.getPlayer(userData[0]).setScriptData(CvUtil.convertToStr(sScript))
- WBPlayerScreen.WBPlayerScreen().placeScript()
- return
-
- def __eventWBCityScriptPopupApply(self, playerID, userData, popupReturn):
- sScript = popupReturn.getEditBoxString(0)
- pCity = gc.getPlayer(userData[0]).getCity(userData[1])
- pCity.setScriptData(CvUtil.convertToStr(sScript))
- WBCityEditScreen.WBCityEditScreen().placeScript()
- return
-
- def __eventWBScriptPopupBegin(self):
- return
-
- def __eventWBGameScriptPopupApply(self, playerID, userData, popupReturn):
- sScript = popupReturn.getEditBoxString(0)
- CyGame().setScriptData(CvUtil.convertToStr(sScript))
- WBGameDataScreen.WBGameDataScreen(
- CvPlatyBuilderScreen.CvWorldBuilderScreen()
- ).placeScript()
- return
-
- def __eventWBPlotScriptPopupApply(self, playerID, userData, popupReturn):
- sScript = popupReturn.getEditBoxString(0)
- pPlot = CyMap().plot(userData[0], userData[1])
- pPlot.setScriptData(CvUtil.convertToStr(sScript))
- WBPlotScreen.WBPlotScreen(CvPlatyBuilderScreen.CvWorldBuilderScreen()).placeScript()
- return
-
- def __eventWBLandmarkPopupApply(self, playerID, userData, popupReturn):
- sScript = popupReturn.getEditBoxString(0)
- pPlot = CyMap().plot(userData[0], userData[1])
- iPlayer = userData[2]
- if userData[3] > -1:
- pSign = CyEngine().getSignByIndex(userData[3])
- iPlayer = pSign.getPlayerType()
- CyEngine().removeSign(pPlot, iPlayer)
- if len(sScript):
- if iPlayer == gc.getBARBARIAN_PLAYER():
- CyEngine().addLandmark(pPlot, CvUtil.convertToStr(sScript))
- else:
- CyEngine().addSign(pPlot, iPlayer, CvUtil.convertToStr(sScript))
- WBPlotScreen.iCounter = 10
- return
-
-
-## Platy Builder ##
diff --git a/Assets/Python/CvGameUtils.py b/Assets/Python/CvGameUtils.py
index 28d8da205..33e85ccd3 100644
--- a/Assets/Python/CvGameUtils.py
+++ b/Assets/Python/CvGameUtils.py
@@ -10,7 +10,6 @@
gc = CyGlobalContext()
PyPlayer = PyHelpers.PyPlayer # Absinthe
-sta = Stability.Stability() # Absinthe
class CvGameUtils:
@@ -1012,8 +1011,8 @@ def getWidgetHelp(self, argsList):
def doAnarchyInstability(self, argsList):
iPlayer = argsList[0]
pPlayer = gc.getPlayer(iPlayer)
- sta.recalcCivicCombos(iPlayer)
- sta.recalcEpansion(iPlayer)
+ Stability.recalcCivicCombos(iPlayer)
+ Stability.recalcEpansion(iPlayer)
iNumCities = pPlayer.getNumCities()
# anarchy instability should appear right on revolution / converting, not one turn later
if iPlayer != Civ.PRUSSIA: # Prussian UP
@@ -1022,7 +1021,7 @@ def doAnarchyInstability(self, argsList):
pPlayer.setStabilitySwing(pPlayer.getStabilitySwing() - 8)
pPlayer.setStabSwingAnarchy(
8
- ) # the value doesn't really matter, but has to remain > 0 after the first StabSwingAnarchy check of sta.updateBaseStability
+ ) # the value doesn't really matter, but has to remain > 0 after the first StabSwingAnarchy check of Stability.updateBaseStability
# anarchy base instability
pPlayer.changeStabilityBase(
StabilityCategory.CIVICS, min(0, max(-2, (-iNumCities + 4) / 7))
@@ -1033,7 +1032,7 @@ def doAnarchyInstability(self, argsList):
pPlayer.setStabilitySwing(pPlayer.getStabilitySwing() - 4) # reduced for the AI
pPlayer.setStabSwingAnarchy(
4
- ) # the value doesn't really matter, but has to remain > 0 after the first StabSwingAnarchy check of sta.updateBaseStability
+ ) # the value doesn't really matter, but has to remain > 0 after the first StabSwingAnarchy check of Stability.updateBaseStability
# anarchy base instability
pPlayer.changeStabilityBase(
StabilityCategory.CIVICS, min(0, max(-1, (-iNumCities + 6) / 7))
diff --git a/Assets/Python/CvRFCEventHandler.py b/Assets/Python/CvRFCEventHandler.py
deleted file mode 100644
index 230fe9955..000000000
--- a/Assets/Python/CvRFCEventHandler.py
+++ /dev/null
@@ -1,1009 +0,0 @@
-# Rhye's and Fall of Civilization: Europe - Event handler
-
-from CvPythonExtensions import *
-from Core import (
- get_scenario,
- civilization,
- civilizations,
- message,
- human,
- make_unit,
- make_units,
- player,
- show,
- text,
- turn,
- year,
- cities,
-)
-import CvUtil
-import CvEventManager
-import PyHelpers
-import CvMercenaryManager # Mercenaries
-import CvScreenEnums # Mercenaries
-from PyUtils import rand, percentage_chance
-
-from StoredData import data
-import RiseAndFall
-import Barbs
-import Religions
-import Resources
-import CityNameManager
-import UniquePowers
-import AIWars
-from RFCUtils import (
- forcedInvasion,
- getProvinceStabilityLevel,
- spreadMajorCulture,
- getUniqueBuilding,
-)
-
-import Victory
-import Stability
-import Plague
-import Crusades
-import Companies
-import Locations
-import Modifiers
-import Provinces
-import Civilizations
-import Mercenaries
-
-from Consts import MessageData
-from ProvinceMapData import PROVINCES_MAP
-from CoreTypes import (
- Building,
- Civ,
- City,
- Improvement,
- Religion,
- Scenario,
- UniquePower,
- StabilityCategory,
- Technology,
- Unit,
- Wonder,
-)
-from LocationsData import CITIES
-
-gc = CyGlobalContext()
-
-# Absinthe: Turn Randomization constants
-iLighthouseEarthQuake = 0
-iByzantiumVikingAttack = 1
-
-# Absinthe: all of this Mercenary stuff is unused
-# Mercenaries - start
-
-PyGame = PyHelpers.PyGame()
-PyInfo = PyHelpers.PyInfo
-
-# Set g_bGameTurnMercenaryCreation to True if mercenary creation should happen during the
-# onBeginGameTurn method, False if it should happen during the onBeginPlayerTurn method
-# Default value is True
-g_bGameTurnMercenaryCreation = True
-
-# Set g_bDisplayMercenaryManagerOnBeginPlayerTurn to True if the "Mercenary Manager"
-# screen should be displayed at the beginning of every player turn.
-# Default value is False
-g_bDisplayMercenaryManagerOnBeginPlayerTurn = False
-
-# This value also controls the "Mercenary Manager" button and when it should be displayed.
-# Default value is "ERA_ANCIENT"
-# Rhye - start (was causing an assert)
-# g_iStartingEra = gc.getInfoTypeForString("ERA_ANCIENT")
-g_iStartingEra = 0
-# Rhye - end
-
-# Change this to False if mercenaries should be removed from the global mercenary pool
-# at the beginning of the game turn. When set to True a number of mercenaries will
-# wander away from the global mercenary pool. This is another variable used to control
-# the load time for the "Mercenary Manager" screen.
-# Default valus is True
-g_bWanderlustMercenaries = True
-
-# Change this to increase the max number of mercenaries that may wander away from the
-# global mercenary pool.
-# Default valus is 3
-g_iWanderlustMercenariesMaximum = 7 # Rhye
-
-# Default valus is 0
-g_iWanderlustMercenariesMinimum = 2 # Rhye
-
-# Change this to False to supress the mercenary messages.
-# Default value is True
-g_bDisplayMercenaryMessages = False # Rhye
-
-# Set to True to print out debug messages in the logs
-g_bDebug = True
-
-# Default valus is 1
-g_bUpdatePeriod = 5 # Rhye
-
-# Default valus is 1
-g_bAIThinkPeriod = 6 # Rhye (5 in Warlords, 4 in vanilla)
-
-# globals
-
-# Mercenaries - end
-
-
-class CvRFCEventHandler:
-
- mercenaryManager = None # Mercenaries
-
- def __init__(self, eventManager):
-
- self.lastProvinceID = -1
- self.bStabilityOverlay = False
- self.EventKeyDown = 6
- self.EventKeyUp = 7
- self.eventManager = eventManager
-
- # initialize base class
- eventManager.addEventHandler("GameStart", self.onGameStart) # Stability
- eventManager.addEventHandler("BeginGameTurn", self.onBeginGameTurn) # Stability
- eventManager.addEventHandler("cityAcquired", self.onCityAcquired) # Stability
- eventManager.addEventHandler(
- "cityAcquiredAndKept", self.onCityAcquiredAndKept
- ) # Stability
- eventManager.addEventHandler("cityRazed", self.onCityRazed) # Stability
- eventManager.addEventHandler("cityBuilt", self.onCityBuilt) # Stability
- eventManager.addEventHandler("combatResult", self.onCombatResult) # Stability
- # eventManager.addEventHandler("changeWar", self.onChangeWar)
- eventManager.addEventHandler("religionFounded", self.onReligionFounded) # Victory
- eventManager.addEventHandler("buildingBuilt", self.onBuildingBuilt) # Victory
- eventManager.addEventHandler("projectBuilt", self.onProjectBuilt) # Victory
- eventManager.addEventHandler("BeginPlayerTurn", self.onBeginPlayerTurn) # Mercenaries
- # eventManager.addEventHandler("EndPlayerTurn", self.onEndPlayerTurn)
- eventManager.addEventHandler("EndGameTurn", self.onEndGameTurn) # Stability
- eventManager.addEventHandler(
- "kbdEvent", self.onKbdEvent
- ) # Mercenaries and Stability overlay
- eventManager.addEventHandler("unitLost", self.onUnitLost) # Mercenaries
- eventManager.addEventHandler("unitKilled", self.onUnitKilled) # Mercenaries
- eventManager.addEventHandler("OnPreSave", self.onPreSave) # edead: StoredData
- eventManager.addEventHandler("OnLoad", self.onLoadGame) # Mercenaries, StoredData
- eventManager.addEventHandler("unitPromoted", self.onUnitPromoted) # Mercenaries
- eventManager.addEventHandler("techAcquired", self.onTechAcquired) # Mercenaries #Stability
- # eventManager.addEventHandler("improvementDestroyed",self.onImprovementDestroyed) #Stability
- eventManager.addEventHandler("unitPillage", self.onUnitPillage) # Stability
- eventManager.addEventHandler("religionSpread", self.onReligionSpread) # Stability
- eventManager.addEventHandler("firstContact", self.onFirstContact)
- eventManager.addEventHandler(
- "playerChangeAllCivics", self.onPlayerChangeAllCivics
- ) # Absinthe: Python Event for civic changes
- eventManager.addEventHandler(
- "playerChangeSingleCivic", self.onPlayerChangeSingleCivic
- ) # Absinthe: Python Event for civic changes
- eventManager.addEventHandler("playerChangeStateReligion", self.onPlayerChangeStateReligion)
-
- self.eventManager = eventManager
-
- self.rnf = RiseAndFall.RiseAndFall()
- self.barb = Barbs.Barbs()
- self.rel = Religions.Religions()
- self.res = Resources.Resources()
- self.cnm = CityNameManager.CityNameManager()
- self.up = UniquePowers.UniquePowers()
- self.aiw = AIWars.AIWars()
- self.vic = Victory.Victory()
- self.sta = Stability.Stability()
- self.pla = Plague.Plague()
- self.crusade = Crusades.Crusades()
- self.provinces = Provinces.ProvinceManager()
- self.mercs = Mercenaries.MercenaryManager() # 3MiroMercs
- self.company = Companies.Companies() # Absinthe
-
- # Mercenaries - start
-
- self.mercenaryManager = CvMercenaryManager.CvMercenaryManager(
- CvScreenEnums.MERCENARY_MANAGER
- )
-
- global g_bGameTurnMercenaryCreation
- global g_bDisplayMercenaryManagerOnBeginPlayerTurn
- global g_iStartingEra
- global g_bWanderlustMercenaries
- global g_iWanderlustMercenariesMaximum
- global g_bDisplayMercenaryMessages
-
- def onGameStart(self, argsList):
- "Called at the start of the game"
- Locations.setup()
- Modifiers.setup()
- Civilizations.setup()
-
- data.setup()
- self.provinces.setup()
- self.rnf.setup()
- self.rel.setup()
- self.pla.setup()
- self.sta.setup()
- self.aiw.setup()
- self.company.setup() # Absinthe: initial company setup for the 1200AD scenario
-
- # 3Miro: WarOnSpawn
- self.rnf.setWarOnSpawn()
- self.vic.setup()
-
- # Absinthe: generate and store randomized turn modifiers
- data.lEventRandomness[iLighthouseEarthQuake] = rand(40)
- data.lEventRandomness[iByzantiumVikingAttack] = rand(10)
-
- # Absinthe: rename cities on the 1200AD scenario - the WB file cannot handle special chars and long names properly
- # some of the cities intentionally have different names though (compared to the CNM), for example some Kievan cities
- # thus it's only set for Hungary for now, we can add more civs/cities later on if there are naming issues
- if get_scenario() == Scenario.i1200AD:
- for city in cities().owner(Civ.HUNGARY).entities():
- self.cnm.renameCities(city, Civ.HUNGARY)
-
- # Absinthe: refresh Dynamic Civ Names for all civs on the initial turn of the given scenario
- for iPlayer in civilizations().majors().ids():
- gc.getPlayer(iPlayer).processCivNames()
-
- return 0
-
- def onPreSave(self, argsList):
- "called before a game is actually saved"
- data.save() # edead: pickle & save script data
-
- # This method creates a new instance of the MercenaryUtils class to be used later
- def onLoadGame(self, argsList):
- data.load() # edead: load & unpickle script data
- Locations.setup()
- Modifiers.setup()
- Civilizations.setup()
-
- def onCityAcquired(self, argsList):
- "City Acquired"
- owner, playerType, city, bConquest, bTrade = argsList
- # CvUtil.pyPrint('City Acquired Event: %s' %(city.getName()))
-
- self.rnf.onCityAcquired(owner, playerType, city, bConquest, bTrade)
- self.cnm.renameCities(city, playerType)
-
- tCity = (city.getX(), city.getY())
-
- # Absinthe: If Arabia doesn't found it's first city, but acquires it with a different method (conquest, flip, trade), it should found Islam there (otherwise no holy city at all)
- if playerType == Civ.ARABIA and not gc.getGame().isReligionFounded(Religion.ISLAM):
- # has to be done before the Arab UP is triggered
- gc.getPlayer(Civ.ARABIA).foundReligion(Religion.ISLAM, Religion.ISLAM, False)
- gc.getGame().getHolyCity(Religion.ISLAM).setNumRealBuilding(Building.ISLAMIC_SHRINE, 1)
-
- # 3Miro: Arab UP
- if gc.hasUP(playerType, UniquePower.SPREAD_STATE_RELIGION_TO_NEW_CITIES):
- self.up.faithUP(playerType, city)
-
- # Absinthe: Ottoman UP
- if gc.hasUP(playerType, UniquePower.FREE_UNITS_WITH_FOREIGN_RELIGIONS):
- self.up.janissaryNewCityUP(playerType, city, bConquest)
-
- # Absinthe: Scottish UP
- # against all players (including indies and barbs), but only on conquest
- if owner == Civ.SCOTLAND and bConquest: # playerType < civilizations().len()
- # only in cities with at least 20% Scottish culture
- iTotalCulture = city.countTotalCultureTimes100()
- if iTotalCulture == 0 or (city.getCulture(owner) * 10000) / iTotalCulture > 20:
- self.up.defianceUP(owner)
-
- # Absinthe: Aragonese UP
- # UP tile yields should be recalculated right away, in case the capital was conquered, or province number changed
- if owner == Civ.ARAGON:
- self.up.confederationUP(owner)
- if playerType == Civ.ARAGON:
- self.up.confederationUP(playerType)
-
- # Absinthe: If Protestantism has not been founded by the time the Dutch spawn, then the Dutch should found it with their first city
- if playerType == Civ.DUTCH and not gc.getGame().isReligionFounded(Religion.PROTESTANTISM):
- gc.getPlayer(Civ.DUTCH).foundReligion(
- Religion.PROTESTANTISM, Religion.PROTESTANTISM, False
- )
- gc.getGame().getHolyCity(Religion.PROTESTANTISM).setNumRealBuilding(
- Building.PROTESTANT_SHRINE, 1
- )
- self.rel.setReformationActive(True)
- self.rel.reformationchoice(Civ.DUTCH)
- self.rel.reformationOther(Civ.INDEPENDENT)
- self.rel.reformationOther(Civ.INDEPENDENT_2)
- self.rel.reformationOther(Civ.INDEPENDENT_3)
- self.rel.reformationOther(Civ.INDEPENDENT_4)
- self.rel.reformationOther(Civ.BARBARIAN)
- self.rel.setReformationHitMatrix(Civ.DUTCH, 2)
-
- for neighbour in civilization(Civ.DUTCH).location.reformation_neighbours:
- if self.rel.getReformationHitMatrix(neighbour) == 0:
- self.rel.setReformationHitMatrix(neighbour, 1)
-
- # Absinthe: Spread some culture to the newly acquired city - this is for nearby indy cities, so should be applied in all cases (conquest, flip, trade)
- if playerType < civilizations().majors().len():
- spreadMajorCulture(playerType, city.getX(), city.getY())
-
- self.sta.onCityAcquired(owner, playerType, city, bConquest, bTrade)
-
- # 3Miro: Jerusalem's Golden Age Incentive
- if tCity == CITIES[City.JERUSALEM]:
- pPlayer = gc.getPlayer(playerType)
- if pPlayer.getStateReligion() == Religion.CATHOLICISM:
- # Absinthe: interface message for the player
- if pPlayer.isHuman():
- CityName = city.getNameKey()
- message(
- human(),
- text("TXT_KEY_CRUSADE_JERUSALEM_SAFE", CityName),
- force=True,
- color=MessageData.GREEN,
- )
- # Absinthe: spread Catholicism if not present already
- if not city.isHasReligion(Religion.CATHOLICISM):
- self.rel.spreadReligion(tCity, Religion.CATHOLICISM)
- self.crusade.success(playerType)
-
- # Absinthe: acquiring Jerusalem, with any faith (but not Paganism) -> chance to find a relic
- # maybe only after a specific date? maybe only if there isn't any ongoing Crusades?
- if (
- percentage_chance(15, strict=True)
- and playerType in civilizations().majors().ids()
- and pPlayer.getStateReligion() != -1
- ):
- pPlayer.initUnit(
- Unit.HOLY_RELIC,
- CITIES[City.JERUSALEM][0],
- CITIES[City.JERUSALEM][1],
- UnitAITypes.NO_UNITAI,
- DirectionTypes.DIRECTION_SOUTH,
- )
-
- # Sedna17: code for Krak des Chevaliers
- if bConquest:
- iNewOwner = city.getOwner()
- pNewOwner = gc.getPlayer(iNewOwner)
- if pNewOwner.countNumBuildings(Wonder.KRAK_DES_CHEVALIERS) > 0:
- city.setHasRealBuilding(getUniqueBuilding(iNewOwner, Building.WALLS), True)
- # Absinthe: if the Castle building were built with the Krak, then it should add stability
- # the safety checks are probably unnecessary, as Castle buildings are destroyed on conquest (theoretically)
- if not (
- city.isHasBuilding(Building.SPANISH_CITADEL)
- or city.isHasBuilding(Building.MOSCOW_KREMLIN)
- or city.isHasBuilding(Building.HUNGARIAN_STRONGHOLD)
- or city.isHasBuilding(Building.CASTLE)
- ):
- city.setHasRealBuilding(getUniqueBuilding(iNewOwner, Building.CASTLE), True)
- pNewOwner.changeStabilityBase(StabilityCategory.EXPANSION, 1)
- # Sedna17, end
-
- self.pla.onCityAcquired(owner, playerType, city) # Plague
- self.vic.onCityAcquired(owner, playerType, city, bConquest, bTrade) # Victory
- self.company.onCityAcquired(owner, playerType, city)
-
- # Remove Silk resource near Constantinople if it is conquered
- if tCity == (81, 24):
- self.res.removeResource(80, 24)
-
- # Remove horse resource near Hadrianople in 1200 AD scenario if someone captures Hadrianople or Constantinople
- if get_scenario() == Scenario.i1200AD:
- if tCity == (76, 25) or tCity == (81, 24):
- self.res.removeResource(77, 24)
-
- return 0
-
- def onCityAcquiredAndKept(self, argsList):
- "City Acquired and Kept"
- iOwner, pCity = argsList
-
- self.mercs.onCityAcquiredAndKept(iOwner, pCity)
-
- def onCityRazed(self, argsList):
- "City Razed"
- city, iPlayer = argsList
-
- iPreviousOwner = city.getOwner()
- if iPreviousOwner == iPlayer and city.getPreviousOwner() != -1:
- iPreviousOwner = city.getPreviousOwner()
-
- self.rnf.onCityRazed(iPreviousOwner, iPlayer, city) # Rise and Fall
- self.sta.onCityRazed(iPreviousOwner, iPlayer, city) # Stability
- self.company.onCityRazed(iPreviousOwner, iPlayer, city)
- self.vic.onCityRazed(iPlayer, city) # Victory
- self.pla.onCityRazed(city, iPlayer) # Plague
-
- # Absinthe: Aragonese UP
- # UP tile yields should be recalculated if your new city is razed
- if iPlayer == Civ.ARAGON:
- self.up.confederationUP(iPlayer)
-
- def onCityBuilt(self, argsList):
- "City Built"
- city = argsList[0]
-
- iOwner = city.getOwner()
-
- self.rnf.onCityBuilt(iOwner, city)
- tCity = (city.getX(), city.getY())
-
- if iOwner < civilizations().majors().len():
- self.cnm.assignName(city)
-
- # Absinthe: merc notifications, after the city is named
- self.mercs.onCityBuilt(iOwner, city)
-
- # Absinthe: Aragonese UP
- # UP tile yields should be recalculated on city foundation
- if iOwner == Civ.ARAGON:
- self.up.confederationUP(iOwner)
-
- # Rhye - delete culture of barbs and minor civs to prevent weird unhappiness
- pCurrent = gc.getMap().plot(city.getX(), city.getY())
- for civ in civilizations().minors().ids():
- pCurrent.setCulture(civ, 0, True)
-
- if iOwner < civilizations().majors().len():
- spreadMajorCulture(iOwner, city.getX(), city.getY())
-
- if iOwner == Civ.PORTUGAL:
- self.vic.onCityBuilt(city, iOwner) # needed in Victory.py
-
- if gc.getTeam(gc.getPlayer(Civ.PORTUGAL).getTeam()).isHasTech(
- Technology.ASTRONOMY
- ):
- city.setHasRealBuilding(Building.PORTUGAL_FEITORIA, True)
-
- # Absinthe: Free buildings if city is built on a tile improvement
- # The problem is that the improvement is auto-destroyed before the city is founded, and totally separately from this function, thus a workaround is needed
- # Solution: getting the coordinates of the last destroyed improvement from a different file in a global variable
- # If the last destroyed improvement in the game is a fort, and it was in the same place as the city, then it's good enough for me
- # (only problem might be if currently there is no improvement on the city-founding tile, but the last destroyed improvement in the game
- # was a fort on the exact same plot some turns ago - but IMO that's not much of a stress of reality, there was a fort there after all)
- # Note that CvEventManager.iImpBeforeCity needs to have some initial value if a city is founded before the first destroyed improvement
- # adding an improvement in the scenario map to one of the preplaced Byzantine cities won't work perfectly:
- # while the improvement will be autorazed on the beginning of the 1st players turn when starting in 500AD, does nothing if you load a saved game
- iImpBeforeCityType = (CvEventManager.iImpBeforeCity / 10000) % 100
- iImpBeforeCityX = (CvEventManager.iImpBeforeCity / 100) % 100
- iImpBeforeCityY = CvEventManager.iImpBeforeCity % 100
- # Absinthe: free walls if built on fort
- if iImpBeforeCityType == Improvement.FORT and (iImpBeforeCityX, iImpBeforeCityY) == tCity:
- city.setHasRealBuilding(getUniqueBuilding(iOwner, Building.WALLS), True)
- # Absinthe: free granary if built on hamlet
- if (
- iImpBeforeCityType == Improvement.HAMLET
- and (iImpBeforeCityX, iImpBeforeCityY) == tCity
- ):
- city.setHasRealBuilding(getUniqueBuilding(iOwner, Building.GRANARY), True)
- # Absinthe: free granary and +1 population if built on village or town
- if iImpBeforeCityType in [Improvement.TOWN, Improvement.VILLAGE]:
- if (iImpBeforeCityX, iImpBeforeCityY) == tCity:
- city.changePopulation(1)
- city.setHasRealBuilding(getUniqueBuilding(iOwner, Building.GRANARY), True)
-
- # Absinthe: Some initial food for all cities on foundation
- # So Leon and Roskilde for example don't lose a population in the first couple turns
- # Nor the indy cities on spawn (they start with zero-sized culture, so they shrink without some food reserves)
- # Currently 1/5 of the treshold of the next population growth
- city.setFood(city.growthThreshold() / 5)
-
- # 3MiroUP: spread religion on city foundation
- if gc.hasUP(iOwner, UniquePower.SPREAD_STATE_RELIGION_TO_NEW_CITIES):
- self.up.faithUP(iOwner, city)
-
- # Absinthe: If Protestantism has not been founded by the time the Dutch spawn, then the Dutch should found it with their first city
- if iOwner == Civ.DUTCH and not gc.getGame().isReligionFounded(Religion.PROTESTANTISM):
- gc.getPlayer(Civ.DUTCH).foundReligion(
- Religion.PROTESTANTISM, Religion.PROTESTANTISM, False
- )
- gc.getGame().getHolyCity(Religion.PROTESTANTISM).setNumRealBuilding(
- Building.PROTESTANT_SHRINE, 1
- )
- self.rel.setReformationActive(True)
- self.rel.reformationchoice(Civ.DUTCH)
- self.rel.reformationOther(Civ.INDEPENDENT)
- self.rel.reformationOther(Civ.INDEPENDENT_2)
- self.rel.reformationOther(Civ.INDEPENDENT_3)
- self.rel.reformationOther(Civ.INDEPENDENT_4)
- self.rel.reformationOther(Civ.BARBARIAN)
- self.rel.setReformationHitMatrix(Civ.DUTCH, 2)
-
- for neighbour in civilization(Civ.DUTCH).location.reformation_neighbours:
- if self.rel.getReformationHitMatrix(neighbour) == 0:
- self.rel.setReformationHitMatrix(neighbour, 1)
-
- if iOwner < civilizations().majors().len():
- self.sta.onCityBuilt(iOwner, city.getX(), city.getY())
-
- def onCombatResult(self, argsList):
- self.vic.onCombatResult(argsList)
- self.sta.onCombatResult(argsList)
-
- def onReligionFounded(self, argsList):
- "Religion Founded"
- iReligion, iFounder = argsList
-
- if iReligion != Religion.JUDAISM:
- for city in cities().owner(iFounder).entities():
- if city.isHolyCityByType(
- iReligion
- ): # Sedna: Protestant Shrine is now starting point for consistency with Religion.xml, Judaism is special
- if iReligion == Religion.PROTESTANTISM:
- iTemple = Building.PROTESTANT_TEMPLE
- iShrine = Building.PROTESTANT_SHRINE
- elif iReligion == Religion.ISLAM:
- iTemple = Building.ISLAMIC_TEMPLE
- iShrine = Building.ISLAMIC_SHRINE
- elif iReligion == Religion.CATHOLICISM:
- iTemple = Building.CATHOLIC_TEMPLE
- iShrine = Building.CATHOLIC_SHRINE
- elif iReligion == Religion.ORTHODOXY:
- iTemple = Building.ORTHODOX_TEMPLE
- iShrine = Building.ORTHODOX_SHRINE
- if not city.isHasRealBuilding(iShrine):
- city.setHasRealBuilding(iShrine, True)
- if not city.isHasRealBuilding(iTemple):
- city.setHasRealBuilding(iTemple, True)
- break
-
- self.vic.onReligionFounded(iReligion, iFounder)
-
- if iFounder < civilizations().majors().len():
- self.sta.onReligionFounded(iFounder)
-
- # 3Miro: end Crusades for the Holy Land after the Reformation
- if iReligion == Religion.PROTESTANTISM:
- self.crusade.endCrusades()
-
- def onBuildingBuilt(self, argsList):
- city, iBuildingType = argsList
- iOwner = city.getOwner()
-
- self.vic.onBuildingBuilt(iOwner, iBuildingType)
- if city.getOwner() < civilizations().majors().len():
- self.sta.onBuildingBuilt(iOwner, iBuildingType)
- self.company.onBuildingBuilt(iOwner, iBuildingType)
- # Absinthe: Faith, Kazimierz, Mont Saint-Michel
- self.rel.onBuildingBuilt(iOwner, iBuildingType)
-
- # Absinthe: Aragonese UP
- # UP tile yields should be recalculated right away if a new Palace was built
- if iOwner == Civ.ARAGON and iBuildingType == Building.PALACE:
- self.up.confederationUP(iOwner)
-
- def onProjectBuilt(self, argsList):
- city, iProjectType = argsList
- self.vic.onProjectBuilt(city.getOwner(), iProjectType)
- if city.getOwner() < civilizations().majors().len():
- self.sta.onProjectBuilt(city.getOwner(), iProjectType)
-
- def onUnitPillage(self, argsList):
- pUnit, iImprovement, iRoute, iOwner = argsList
- iPlotX = pUnit.getX()
- iPlotY = pUnit.getY()
- pPlot = CyMap().plot(iPlotX, iPlotY)
- if pPlot.countTotalCulture() == 0:
- if iImprovement >= Improvement.COTTAGE and iImprovement <= Improvement.TOWN:
- self.barb.onImprovementDestroyed(iPlotX, iPlotY)
- iVictim = pPlot.getOwner()
- if iVictim > -1 and iVictim < civilizations().majors().len():
- self.sta.onImprovementDestroyed(iVictim)
-
- self.vic.onPillageImprovement(
- pUnit.getOwner(), iVictim, iImprovement, iRoute, iPlotX, iPlotY
- )
-
- def onBeginGameTurn(self, argsList):
- iGameTurn = argsList[0]
-
- # Absinthe: 868AD Viking attack on Constantinople
- if iGameTurn == year(860) + data.lEventRandomness[iByzantiumVikingAttack] - 2:
- if human() == Civ.BYZANTIUM:
- show(text("TXT_KEY_EVENT_VIKING_CONQUERERS_RUMOURS"))
-
- if iGameTurn == year(860) + data.lEventRandomness[iByzantiumVikingAttack]:
- if human() == Civ.BYZANTIUM:
- for unit, number in zip((Unit.DENMARK_HUSKARL, Unit.VIKING_BERSERKER), (3, 4)):
- self.barb.spawnUnits(
- Civ.BARBARIAN,
- (80, 24),
- (80, 25),
- unit,
- number,
- iGameTurn,
- 1,
- 0,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_VIKINGS"),
- )
- message(
- Civ.BYZANTIUM,
- text("TXT_KEY_EVENT_VIKING_CONQUERERS_ARRIVE"),
- color=MessageData.RED,
- )
-
- # Absinthe: Message for the human player about the Schism
- elif iGameTurn == year(1053):
- if player().isExisting():
- sText = text("TXT_KEY_GREAT_SCHISM")
- message(human(), sText, color=MessageData.DARK_PINK)
-
- # Absinthe: Remove the Great Lighthouse, message for the human player if the city is visible
- elif iGameTurn == year(1323) - 40 + data.lEventRandomness[iLighthouseEarthQuake]:
- for iPlayer in civilizations().drop(Civ.BARBARIAN).ids():
- bFound = 0
- for city in cities().owner(iPlayer).entities():
- if city.isHasBuilding(Wonder.GREAT_LIGHTHOUSE):
- city.setHasRealBuilding(Wonder.GREAT_LIGHTHOUSE, False)
- GLcity = city
- bFound = 1
- if bFound and human() == iPlayer:
- pPlayer = gc.getPlayer(iPlayer)
- iTeam = pPlayer.getTeam()
- if GLcity.isRevealed(iTeam, False):
- message(
- iPlayer,
- text("TXT_KEY_BUILDING_GREAT_LIGHTHOUSE_REMOVED"),
- color=MessageData.RED,
- )
-
- self.barb.checkTurn(iGameTurn)
- self.rnf.checkTurn(iGameTurn)
- self.rel.checkTurn(iGameTurn)
- self.res.checkTurn(iGameTurn)
- self.up.checkTurn(iGameTurn)
- self.aiw.checkTurn(iGameTurn)
- self.pla.checkTurn(iGameTurn)
- self.vic.checkTurn(iGameTurn)
- self.sta.checkTurn(iGameTurn)
- self.crusade.checkTurn(iGameTurn)
- self.provinces.checkTurn(iGameTurn)
- self.company.checkTurn(iGameTurn)
-
- return 0
-
- def onBeginPlayerTurn(self, argsList):
- iGameTurn, iPlayer = argsList
- iHuman = human()
- if self.rnf.getDeleteMode(0) != -1:
- self.rnf.deleteMode(iPlayer)
- # Absinthe: refresh Dynamic Civ Names
- if iPlayer < civilizations().majors().len():
- gc.getPlayer(iPlayer).processCivNames()
-
- # Absinthe: Byzantine conqueror army
- if iGameTurn == year(520):
- if iPlayer == Civ.BYZANTIUM:
- pByzantium = gc.getPlayer(Civ.BYZANTIUM)
- tStartingPlot = (59, 16)
- pByzantium.initUnit(
- Unit.GALLEY,
- tStartingPlot[0],
- tStartingPlot[1],
- UnitAITypes.UNITAI_ASSAULT_SEA,
- DirectionTypes.DIRECTION_SOUTH,
- )
- pByzantium.initUnit(
- Unit.GALLEY,
- tStartingPlot[0],
- tStartingPlot[1],
- UnitAITypes.UNITAI_ASSAULT_SEA,
- DirectionTypes.DIRECTION_SOUTH,
- )
- pByzantium.initUnit(
- Unit.GALLEY,
- tStartingPlot[0],
- tStartingPlot[1],
- UnitAITypes.UNITAI_ASSAULT_SEA,
- DirectionTypes.DIRECTION_SOUTH,
- )
- pByzantium.initUnit(
- Unit.GALLEY,
- tStartingPlot[0],
- tStartingPlot[1],
- UnitAITypes.UNITAI_ASSAULT_SEA,
- DirectionTypes.DIRECTION_SOUTH,
- )
- pByzantium.initUnit(
- Unit.GALLEY,
- tStartingPlot[0],
- tStartingPlot[1],
- UnitAITypes.UNITAI_ASSAULT_SEA,
- DirectionTypes.DIRECTION_SOUTH,
- )
- pByzantium.initUnit(
- Unit.GREAT_GENERAL,
- tStartingPlot[0],
- tStartingPlot[1],
- UnitAITypes.UNITAI_GENERAL,
- DirectionTypes.DIRECTION_SOUTH,
- )
- pPlot = CyMap().plot(tStartingPlot[0], tStartingPlot[1])
- for iUnitLoop in range(pPlot.getNumUnits()):
- pUnit = pPlot.getUnit(iUnitLoop)
- if pUnit.getUnitType() == CvUtil.findInfoTypeNum(
- gc.getUnitInfo, gc.getNumUnitInfos(), "UNIT_GREAT_GENERAL"
- ):
- pUnit.setName(text("TXT_KEY_GREAT_PERSON_BELISARIUS"))
- make_units(Civ.BYZANTIUM, Unit.SWORDSMAN, tStartingPlot, 4)
- make_units(Civ.BYZANTIUM, Unit.AXEMAN, tStartingPlot, 3)
- make_units(Civ.BYZANTIUM, Unit.ARCHER, tStartingPlot, 2)
- if iPlayer == iHuman:
- show(text("TXT_KEY_EVENT_CONQUEROR_BELISARIUS"))
-
- # Absinthe: popup message a couple turns before the Seljuk/Mongol/Timurid invasions
- if iPlayer == iHuman:
- # Seljuks
- if iGameTurn == year(1064) - 7:
- if iPlayer == Civ.BYZANTIUM:
- show(("TXT_KEY_EVENT_BARBARIAN_INVASION_START"))
- elif iGameTurn == year(1094) + 1:
- if iPlayer == Civ.BYZANTIUM:
- sText = "Seljuk"
- show(text("TXT_KEY_EVENT_BARBARIAN_INVASION_END", sText))
- # Mongols
- elif iGameTurn == year(1236) - 7:
- if iPlayer in [
- Civ.KIEV,
- Civ.HUNGARY,
- Civ.POLAND,
- Civ.BULGARIA,
- ]:
- show(text("TXT_KEY_EVENT_BARBARIAN_INVASION_START"))
- elif iGameTurn == year(1288) + 1:
- if iPlayer in [
- Civ.KIEV,
- Civ.HUNGARY,
- Civ.POLAND,
- Civ.BULGARIA,
- ]:
- sText = "Tatar"
- show(text("TXT_KEY_EVENT_BARBARIAN_INVASION_END", sText))
- # Timurids
- elif iGameTurn == year(1380) - 7:
- if iPlayer in [Civ.ARABIA, Civ.OTTOMAN, Civ.BYZANTIUM]:
- show(text("TXT_KEY_EVENT_TIMURID_INVASION_START"))
- elif iGameTurn == year(1431) + 1:
- if iPlayer in [Civ.ARABIA, Civ.OTTOMAN, Civ.BYZANTIUM]:
- sText = "Timurid"
- show(text("TXT_KEY_EVENT_BARBARIAN_INVASION_END", sText))
-
- # Absinthe: Denmark UP
- if iPlayer == Civ.DENMARK:
- self.up.soundUP(iPlayer)
-
- # Absinthe: Aragonese UP
- # safety check: probably redundant, calls from onBuildingBuilt, onCityBuilt, onCityAcquired and onCityRazed should be enough
- elif iPlayer == Civ.ARAGON:
- self.up.confederationUP(iPlayer)
-
- # Ottoman UP
- if gc.hasUP(iPlayer, UniquePower.FREE_UNITS_WITH_FOREIGN_RELIGIONS):
- self.up.janissaryDraftUP(iPlayer)
-
- self.pla.checkPlayerTurn(iGameTurn, iPlayer)
- self.vic.checkPlayerTurn(iGameTurn, iPlayer)
-
- if gc.getPlayer(iPlayer).isAlive() and iPlayer < civilizations().majors().len():
- if gc.getPlayer(iPlayer).getNumCities() > 0:
- self.sta.updateBaseStability(iGameTurn, iPlayer)
-
- # for the AI only, leader switch and cheats
- if iPlayer != iHuman:
- self.rnf.checkPlayerTurn(iGameTurn, iPlayer)
-
- # not really needed, we set it on collapse anyway
- # setLastTurnAlive( iPlayer, iGameTurn )
-
- self.crusade.checkPlayerTurn(iGameTurn, iPlayer)
-
- def onEndPlayerTurn(self, argsList):
- """Called at the end of a players turn"""
- # 3Miro does not get called
- iGameTurn, iPlayer = argsList
-
- def onEndGameTurn(self, argsList):
- iGameTurn = argsList[0]
- self.sta.checkImplosion(iGameTurn)
- self.mercs.doMercsTurn(iGameTurn)
-
- def onReligionSpread(self, argsList):
- iReligion, iOwner, pSpreadCity = argsList
- self.sta.onReligionSpread(iReligion, iOwner)
- self.rel.onReligionSpread(iReligion, iOwner)
-
- def onFirstContact(self, argsList):
-
- iTeamX, iHasMetTeamY = argsList
- self.rnf.onFirstContact(iTeamX, iHasMetTeamY)
-
- # Absinthe: Python Event for civic changes
- def onPlayerChangeAllCivics(self, argsList):
- # note that this only reports civic change if it happened via normal revolution
- "Player changes his civics"
- iPlayer = argsList[0]
- lNewCivics = [argsList[1], argsList[2], argsList[3], argsList[4], argsList[5], argsList[6]]
- lOldCivics = [
- argsList[7],
- argsList[8],
- argsList[9],
- argsList[10],
- argsList[11],
- argsList[12],
- ]
- if iPlayer < civilizations().majors().len():
- self.rel.onPlayerChangeAllCivics(iPlayer, lNewCivics, lOldCivics)
-
- def onPlayerChangeSingleCivic(self, argsList):
- # note that this reports all civic changes in single instances (so also reports force converts by diplomacy or with spies)
- "Civics are changed for a player"
- iPlayer, iNewCivic, iOldCivic = argsList
-
- def onPlayerChangeStateReligion(self, argsList):
- "Player changes his state religion"
- iPlayer, iNewReligion, iOldReligion = argsList
-
- if iPlayer < civilizations().majors().len():
- self.company.onPlayerChangeStateReligion(argsList)
-
- def onTechAcquired(self, argsList):
- iPlayer = argsList[2]
- self.vic.onTechAcquired(argsList[0], argsList[2])
-
- if (
- gc.getPlayer(iPlayer).isAlive()
- and turn() > civilization(iPlayer).date.birth
- and iPlayer < civilizations().majors().len()
- ):
- self.rel.onTechAcquired(argsList[0], argsList[2])
- self.sta.onTechAcquired(argsList[0], argsList[2])
-
- # This method will redraw the main interface once a unit is promoted. This way the
- # gold/turn information will be updated.
- def onUnitPromoted(self, argsList):
- "Unit Promoted"
-
- self.mercs.onUnitPromoted(argsList)
-
- # This method will remove a mercenary unit from the game if it is killed
- def onUnitKilled(self, argsList):
- "Unit Killed"
-
- self.mercs.onUnitKilled(argsList)
-
- # This method will remove a mercenary unit from the game if it is lost
- def onUnitLost(self, argsList):
- "Unit Lost"
-
- self.mercs.onUnitLost(argsList)
-
- # This method handles the key input and will bring up the mercenary manager screen if the
- # player has at least one city and presses 'ctrl' and the 'M' key.
- def onKbdEvent(self, argsList):
- "keypress handler - return 1 if the event was consumed"
-
- if player().isAlive():
- eventType, key, mx, my, px, py = argsList
- theKey = int(key)
-
- if (
- eventType == self.EventKeyDown
- and theKey == int(InputTypes.KB_M)
- and self.eventManager.bCtrl
- and gc.getActivePlayer().getNumCities() > 0
- ):
-
- self.mercenaryManager.interfaceScreen()
-
- # Rhye - start debug
- eventType, key, mx, my, px, py = argsList
-
- theKey = int(key)
-
- if (
- eventType == self.EventKeyDown
- and theKey == int(InputTypes.KB_B)
- and self.eventManager.bAlt
- ):
-
- iGameTurn = turn()
- pass
-
- if (
- eventType == self.EventKeyDown
- and theKey == int(InputTypes.KB_N)
- and self.eventManager.bAlt
- ):
- self.printPlotsDebug()
-
- if (
- eventType == self.EventKeyDown
- and theKey == int(InputTypes.KB_E)
- and self.eventManager.bAlt
- and self.eventManager.bShift
- ):
- # picks a dead civ so that autoplay can be started with game.AIplay xx
- iDebugDeadCiv = Civ.BURGUNDY # always dead in 500AD
- make_unit(iDebugDeadCiv, Unit.AXEMAN, (0, 0))
- gc.getGame().setActivePlayer(iDebugDeadCiv, False)
- gc.getPlayer(iDebugDeadCiv).setPlayable(True)
- # Rhye - end debug
-
- # Absinthe: province highlight - based on SoI
- if (
- eventType == self.EventKeyDown
- and px >= 0
- and py >= 0
- and int(key) == 45
- and self.eventManager.bCtrl
- and not self.eventManager.bAlt
- ):
-
- plot = gc.getMap().plot(px, py)
- iActivePlayer = gc.getGame().getActivePlayer()
- iActiveTeam = gc.getPlayer(iActivePlayer).getTeam()
- iProvinceID = PROVINCES_MAP[plot.getY()][plot.getX()]
-
- # do not show provinces of unrevealed tiles
- if not plot.isRevealed(iActiveTeam, False) and not gc.getGame().isDebugMode():
- return
-
- # do not redraw if already drawn
- if self.lastProvinceID == iProvinceID:
- return
-
- map = CyMap()
- engine = CyEngine()
-
- # clear the highlight
- engine.clearAreaBorderPlots(AreaBorderLayers.AREA_BORDER_LAYER_HIGHLIGHT_PLOT)
-
- # cache the plot's coords
- self.lastProvinceID = PROVINCES_MAP[plot.getY()][plot.getX()]
-
- # select an appropriate color
- if PROVINCES_MAP[plot.getY()][plot.getX()] == -1: # ocean and non-province tiles
- return
- else:
- iLevel = getProvinceStabilityLevel(human(), iProvinceID)
- if iLevel == 4:
- color = gc.getColorInfo(
- gc.getInfoTypeForString("COLOR_HIGHLIGHT_CORE")
- ).getColor()
- elif iLevel == 3:
- color = gc.getColorInfo(
- gc.getInfoTypeForString("COLOR_HIGHLIGHT_NATURAL")
- ).getColor()
- elif iLevel == 2:
- color = gc.getColorInfo(
- gc.getInfoTypeForString("COLOR_HIGHLIGHT_POTENTIAL")
- ).getColor()
- elif iLevel == 1:
- color = gc.getColorInfo(
- gc.getInfoTypeForString("COLOR_HIGHLIGHT_BORDER")
- ).getColor()
- else:
- color = gc.getColorInfo(
- gc.getInfoTypeForString("COLOR_HIGHLIGHT_FOREIGN")
- ).getColor()
-
- # apply the highlight
- for i in range(map.numPlots()):
- plot = map.plotByIndex(i)
- if PROVINCES_MAP[plot.getY()][plot.getX()] == iProvinceID and (
- gc.getGame().isDebugMode() or plot.isRevealed(iActiveTeam, False)
- ):
- engine.fillAreaBorderPlot(
- plot.getX(),
- plot.getY(),
- color,
- AreaBorderLayers.AREA_BORDER_LAYER_HIGHLIGHT_PLOT,
- )
-
- return
-
- # clear all highlights
- if (eventType == self.EventKeyUp and self.eventManager.bCtrl) or (
- eventType == self.EventKeyDown
- ):
- CyEngine().clearAreaBorderPlots(AreaBorderLayers.AREA_BORDER_LAYER_HIGHLIGHT_PLOT)
- self.lastProvinceID = -1
- # Absinthe: end
-
- def printPlotsDebug(self):
- pass
diff --git a/Assets/Python/CvRFCEventManager.py b/Assets/Python/CvRFCEventManager.py
deleted file mode 100644
index 981322576..000000000
--- a/Assets/Python/CvRFCEventManager.py
+++ /dev/null
@@ -1,315 +0,0 @@
-import CvEventManager
-import CvRFCEventHandler
-import RiseAndFall
-import Crusades
-import Religions
-import Barbs
-
-
-class CvRFCEventManager(CvEventManager.CvEventManager, object):
-
- """Extends the standard event manager by adding support for multiple
- handlers for each event.
-
- Methods exist for both adding and removing event handlers. A set method
- also exists to override the default handlers. Clients should not depend
- on event handlers being called in a particular order.
-
- This approach works best with mods that have implemented the design
- pattern suggested on Apolyton by dsplaisted.
-
- http://apolyton.net/forums/showthread.php?s=658a68df728b2719e9ebfe842d784002&threadid=142916
-
- The example given in the 8th post in the thread would be handled by adding
- the following lines to the CvCustomEventManager constructor. The RealFort,
- TechConquest, and CulturalDecay classes can remain unmodified.
-
- self.addEventHandler("unitMove", rf.onUnitMove)
- self.addEventHandler("improvementBuilt", rf.onImprovementBuilt)
- self.addEventHandler("techAcquired", rf.onTechAcquired)
- self.addEventHandler("cityAcquired", tc.onCityAcquired)
- self.addEventHandler("EndGameTurn", cd.onEndGameTurn)
-
- Note that the naming conventions for the event type strings vary from event
- to event. Some use initial capitalization, some do not; some eliminate the
- "on..." prefix used in the event handler function name, some do not. Look
- at the unmodified CvEventManager.py source code to determine the correct
- name for a particular event.
-
- Take care with event handlers that also extend CvEventManager. Since
- this event manager handles invocation of the base class handler function,
- additional handlers should not also call the base class function themselves.
-
- """
-
- def __init__(self, *args, **kwargs):
- super(CvRFCEventManager, self).__init__(*args, **kwargs)
- # map the initial EventHandlerMap values into the new data structure
-
- for eventType, eventHandler in self.EventHandlerMap.iteritems():
- self.setEventHandler(eventType, eventHandler)
-
- self.CustomEvents = {
- 7614: ("RiseAndFallPopupEvent", self.rnfEventApply7614, self.rnfEventBegin7614),
- 7615: ("FlipPopupEvent", self.rnfEventApply7615, self.rnfEventBegin7615),
- 7616: ("CrusadeInitVoteEvent", self.crusadeApply7616, self.crusadeBegin7616),
- 7617: ("InformForLeaderPopup", self.crusadeApply7617, self.crusadeBegin7617),
- 7618: ("HumanVotePopup", self.crusadeApply7618, self.crusadeBegin7618),
- 7619: ("HumanDeviate", self.crusadeApply7619, self.crusadeBegin7619),
- 7620: ("ChoseNewCrusadeTarget", self.crusadeApply7620, self.crusadeBegin7620),
- 7621: ("Under Attack", self.crusadeApply7621, self.crusadeBegin7621),
- 7622: ("ResurrectionEvent", self.rnfEventApply7622, self.rnfEventBegin7622),
- 7624: ("ReformationEvent", self.relEventApply7624, self.relEventBegin7624),
- 7625: ("DefensiveCrusadeEvent", self.crusadeApply7625, self.crusadeBegin7625),
- 7626: ("CounterReformationEvent", self.relEventApply7626, self.relEventBegin7626),
- 7627: ("CounterReformationEvent", self.barbEventApply7627, self.barbEventBegin7627),
- 7628: ("Religious Persecution", self.relEventApply7628, self.relEventBegin7628),
- 7629: ("Free Religious Revolution", self.relEventApply7629, self.relEventBegin7629),
- }
-
- # --> INSERT EVENT HANDLER INITIALIZATION HERE <--
- CvRFCEventHandler.CvRFCEventHandler(self)
- self.rnf = RiseAndFall.RiseAndFall()
- self.crus = Crusades.Crusades()
- self.rel = Religions.Religions()
- self.barb = Barbs.Barbs()
-
- def setPopupHandler(self, eventType, handler):
- """Removes all previously installed popup handlers for the given
- event type and installs a new pair of handlers.
-
- The eventType should be an integer. It must be unique with respect
- to the integers assigned to built in events. The popupHandler should
- be a list made up of (name, applyFunction, beginFunction). The name
- is used in debugging output. The begin and apply functions are invoked
- by beginEvent and applyEvent, respectively, to manage a popup dialog
- in response to the event.
- """
-
- self.Events[eventType] = handler
-
- def setPopupHandlers(self, eventType, name, beginFunction, applyFunction):
- """Builds a handler tuple to pass to setPopupHandler()."""
-
- self.setPopupHandler(eventType, (name, applyFunction, beginFunction))
-
- def removePopupHandler(self, eventType):
- """Removes all previously installed popup handlers for the given
- event type.
-
- The eventType should be an integer. It is an error to fire this
- eventType after removing its handlers.
- """
-
- if eventType in self.Events:
- del self.Events[eventType]
-
- def addEventHandler(self, eventType, eventHandler):
- """Adds a handler for the given event type.
-
- A list of supported event types can be found in the initialization
- of EventHandlerMap in the CvEventManager class.
-
- """
- self.EventHandlerMap[eventType].append(eventHandler)
-
- def removeEventHandler(self, eventType, eventHandler):
- """Removes a handler for the given event type.
-
- A list of supported event types can be found in the initialization
- of EventHandlerMap in the CvEventManager class. It is an error if
- the given handler is not found in the list of installed handlers.
-
- """
- self.EventHandlerMap[eventType].remove(eventHandler)
-
- def setEventHandler(self, eventType, eventHandler):
- """Removes all previously installed event handlers for the given
- event type and installs a new handler .
-
- A list of supported event types can be found in the initialization
- of EventHandlerMap in the CvEventManager class. This method is
- primarily useful for overriding, rather than extending, the default
- event handler functionality.
-
- """
- self.EventHandlerMap[eventType] = [eventHandler]
-
- def handleEvent(self, argsList):
- """Handles events by calling all installed handlers."""
- self.origArgsList = argsList
- flagsIndex = len(argsList) - 6
- (
- self.bDbg,
- self.bMultiPlayer,
- self.bAlt,
- self.bCtrl,
- self.bShift,
- self.bAllowCheats,
- ) = argsList[flagsIndex:]
- eventType = argsList[0]
- return {
- "kbdEvent": self._handleConsumableEvent,
- "mouseEvent": self._handleConsumableEvent,
- "OnSave": self._handleOnSaveEvent,
- "OnLoad": self._handleOnLoadEvent,
- }.get(eventType, self._handleDefaultEvent)(eventType, argsList[1:])
-
- def _handleDefaultEvent(self, eventType, argsList):
- if self.EventHandlerMap.has_key(eventType):
- for eventHandler in self.EventHandlerMap[eventType]:
- # the last 6 arguments are for internal use by handleEvent
- eventHandler(argsList[: len(argsList) - 6])
-
- def _handleConsumableEvent(self, eventType, argsList):
- """Handles events that can be consumed by the handlers, such as
- keyboard or mouse events.
-
- If a handler returns non-zero, processing is terminated, and no
- subsequent handlers are invoked.
-
- """
- if self.EventHandlerMap.has_key(eventType):
- for eventHandler in self.EventHandlerMap[eventType]:
- # the last 6 arguments are for internal use by handleEvent
- result = eventHandler(argsList[: len(argsList) - 6])
- if result > 0:
- return result
- return 0
-
- # TODO: this probably needs to be more complex
- def _handleOnSaveEvent(self, eventType, argsList):
- """Handles OnSave events by concatenating the results obtained
- from each handler to form an overall consolidated save string.
-
- """
- result = ""
- if self.EventHandlerMap.has_key(eventType):
- for eventHandler in self.EventHandlerMap[eventType]:
- # the last 6 arguments are for internal use by handleEvent
- result = result + eventHandler(argsList[: len(argsList) - 6])
- return result
-
- # TODO: this probably needs to be more complex
- def _handleOnLoadEvent(self, eventType, argsList):
- """Handles OnLoad events."""
- return self._handleDefaultEvent(eventType, argsList)
-
- # popup event handlers
- def beginEvent(self, context, argsList=-1):
- """Begin Event"""
- if self.CustomEvents.has_key(context):
- return self.CustomEvents[context][2](argsList)
- else:
- super(CvRFCEventManager, self).beginEvent(context, argsList)
-
- def applyEvent(self, argsList):
- """Apply the effects of an event"""
- context, playerID, netUserData, popupReturn = argsList
-
- if self.CustomEvents.has_key(context):
- entry = self.CustomEvents[context]
- # the apply function
- return entry[1](playerID, netUserData, popupReturn)
- else:
- return super(CvRFCEventManager, self).applyEvent(argsList)
-
- # popup events
- def rnfEventBegin7614(self):
- pass
-
- def rnfEventApply7614(self, playerID, netUserData, popupReturn):
- self.rnf.eventApply7614(popupReturn)
-
- def rnfEventBegin7615(self):
- pass
-
- def rnfEventApply7615(self, playerID, netUserData, popupReturn): # 3Miro: flip
- self.rnf.eventApply7615(popupReturn)
-
- def crusadeBegin7616(self):
- pass
-
- def crusadeApply7616(self, playerID, netUserData, popupReturn):
- self.crus.eventApply7616(popupReturn)
-
- def crusadeBegin7617(self):
- pass
-
- def crusadeApply7617(self, playerID, netUserData, popupReturn):
- pass
-
- def crusadeBegin7618(self):
- pass
-
- def crusadeApply7618(self, playerID, netUserData, popupReturn):
- self.crus.eventApply7618(popupReturn)
-
- def crusadeBegin7619(self):
- pass
-
- def crusadeApply7619(self, playerID, netUserData, popupReturn):
- self.crus.eventApply7619(popupReturn)
-
- def crusadeBegin7620(self):
- pass
-
- def crusadeApply7620(self, playerID, netUserData, popupReturn):
- self.crus.eventApply7620(popupReturn)
-
- def crusadeBegin7621(self):
- pass
-
- def crusadeApply7621(self, playerID, netUserData, popupReturn):
- pass
-
- def rnfEventBegin7622(self):
- pass
-
- def rnfEventApply7622(self, playerID, netUserData, popupReturn): # 3Miro: rebel
- self.rnf.eventApply7622(popupReturn)
-
- ### Begin Reformation ###
- def relEventBegin7624(self):
- pass
-
- def relEventApply7624(self, playerID, netUserData, popupReturn):
- self.rel.eventApply7624(popupReturn)
-
- def relEventBegin7626(self):
- pass
-
- def relEventApply7626(self, playerID, netUserData, popupReturn):
- self.rel.eventApply7626(popupReturn)
-
- ### End Reformation ###
-
- def crusadeBegin7625(self):
- pass
-
- def crusadeApply7625(self, playerID, netUserData, popupReturn):
- self.crus.eventApply7625(popupReturn)
-
- def barbEventBegin7627(self):
- pass
-
- def barbEventApply7627(self, playerID, netUserData, popupReturn):
- self.barb.eventApply7627(popupReturn)
-
- # Absinthe: persecution popup
- def relEventBegin7628(self):
- pass
-
- def relEventApply7628(self, playerID, netUserData, popupReturn):
- self.rel.eventApply7628(popupReturn)
-
- # Absinthe: end
-
- # Absinthe: free religion change
- def relEventBegin7629(self):
- pass
-
- def relEventApply7629(self, playerID, netUserData, popupReturn):
- self.rel.eventApply7629(playerID, popupReturn)
-
- # Absinthe: end
diff --git a/Assets/Python/DynamicCivs.py b/Assets/Python/DynamicCivs.py
new file mode 100644
index 000000000..953379757
--- /dev/null
+++ b/Assets/Python/DynamicCivs.py
@@ -0,0 +1,8 @@
+from Core import civilizations, player
+from Events import handler
+
+
+@handler("BeginPlayerTurn")
+def refresh_civ_name(iGameTurn, iPlayer):
+ if iPlayer < civilizations().majors().len():
+ player(iPlayer).processCivNames()
diff --git a/Assets/Python/EntryPoints/CvEventInterface.py b/Assets/Python/EntryPoints/CvEventInterface.py
index 36502f790..39a33f35a 100644
--- a/Assets/Python/EntryPoints/CvEventInterface.py
+++ b/Assets/Python/EntryPoints/CvEventInterface.py
@@ -9,12 +9,12 @@
#
# No other modules should import this
#
-import CvRFCEventManager
import BugEventManager
from CvPythonExtensions import *
+from Init import init
-normalEventManager = CvRFCEventManager.CvRFCEventManager()
eventManager = BugEventManager.BugEventManager()
+init()
import Handlers # noqa: E402, F401
diff --git a/Assets/Python/Events.py b/Assets/Python/Events.py
new file mode 100644
index 000000000..5eff32e8a
--- /dev/null
+++ b/Assets/Python/Events.py
@@ -0,0 +1,31 @@
+from BugEventManager import g_eventManager as events
+import inspect
+
+
+def handler(event):
+ def handler_decorator(func):
+ arg_names = inspect.getargspec(func)[0]
+
+ def handler_func(args):
+ return func(*args[: len(arg_names)])
+
+ handler_func.__name__ = func.__name__
+ handler_func.__module__ = func.__module__
+ handler_func.func_name = func.func_name
+
+ events.addEventHandler(event, handler_func)
+ return handler_func
+
+ return handler_decorator
+
+
+def noop(*args, **kwargs):
+ pass
+
+
+def popup_handler(event_id):
+ def handler_decorator(func):
+ events.addCustomEvent(event_id, func.__name__, func, noop)
+ return func
+
+ return handler_decorator
diff --git a/Assets/Python/Handlers.py b/Assets/Python/Handlers.py
index 984785f0c..69544c104 100644
--- a/Assets/Python/Handlers.py
+++ b/Assets/Python/Handlers.py
@@ -1,54 +1,30 @@
# ruff: noqa: F401
+import ScreenHandler
-import StoredData
-import Locations
-
-import LocationsData
-import CityMapData
-import ProvinceMapData
-import SettlerMapData
-import WarMapData
import CityNameManager
import Civilizations
+import History
+import Messages
import Modifiers
-
-# import AIParameters
-
-# import Scenarios
-# import ScreensHandler
+import Rules
+import Setup
+import Shortcuts
+import StoredData
import AIWars
import Barbs
-
-# import Civics
-# import Collapse
-# import Communications
+import Collapse
import Companies
import Crusades
import Mercenaries
-
-# import DynamicCivs
-# import EventSigns
-# import GreatPeople
-import History
-
-# import Logging
-# import Messages
-# import Periods
import Plague
+import Provinces
import Religions
import Resources
-
-# import Resurrection
-# import Rise
+import Resurrection
import RiseAndFall
-
-# import Rules
-# import Shortcuts
+import Secession
import Stability
import UniquePowers
-
-# import Victories
-# import Wonders
-
-Locations.init()
+import Victory
+import Wonders
diff --git a/Assets/Python/History.py b/Assets/Python/History.py
index e12147eb1..982892c90 100644
--- a/Assets/Python/History.py
+++ b/Assets/Python/History.py
@@ -1,5 +1,160 @@
-from Core import make_units
-from CoreTypes import Unit
+from CvPythonExtensions import *
+import Barbs
+from Consts import MessageData
+from Core import (
+ civilization,
+ civilizations,
+ human,
+ make_units,
+ cities,
+ message,
+ message_if_human,
+ player,
+ show,
+ show_if_human,
+ text,
+ year,
+)
+from CoreTypes import Building, City, Civ, Religion, StabilityCategory, Unit
+import Crusades
+from Events import handler
+from LocationsData import CITIES, CIV_CAPITAL_LOCATIONS
+from PyUtils import percentage_chance
+from RFCUtils import forcedInvasion
+from StoredData import data
+import Religions
+from Consts import iByzantiumVikingAttack
+
+gc = CyGlobalContext()
+
+
+@handler("cityAcquired")
+def move_ottoman_capital(owner, iPlayer, city, bConquest, bTrade):
+ # Constantinople -> Istanbul
+ if iPlayer == Civ.OTTOMAN:
+ cityList = cities.owner(iPlayer).entities()
+ if (city.getX(), city.getY()) == CIV_CAPITAL_LOCATIONS[Civ.BYZANTIUM]:
+ for loopCity in cityList:
+ if loopCity != city:
+ loopCity.setHasRealBuilding((Building.PALACE), False)
+ city.setHasRealBuilding(Building.PALACE, True)
+ if civilization(Civ.OTTOMAN).has_state_religion(Religion.ISLAM):
+ city.setHasReligion(Religion.ISLAM, True, True, False)
+ # some stability boost and flavour message
+ player(Civ.OTTOMAN).changeStabilityBase(StabilityCategory.EXPANSION, 6)
+ message_if_human(
+ iPlayer,
+ text("TXT_KEY_GLORY_ON_CONQUEST"),
+ force=True,
+ color=MessageData.GREEN,
+ )
+ # Absinthe: Edirne becomes capital if conquered before Constantinople
+ else:
+ if (city.getX(), city.getY()) == (76, 25):
+ bHasIstanbul = False
+ IstanbulPlot = gc.getMap().plot(*CIV_CAPITAL_LOCATIONS[Civ.BYZANTIUM])
+ if IstanbulPlot.isCity():
+ if IstanbulPlot.getPlotCity().getOwner() == iPlayer:
+ bHasIstanbul = True
+ if not bHasIstanbul:
+ gc.getPlayer(iPlayer).getCapitalCity().setHasRealBuilding(
+ Building.PALACE, False
+ )
+ city.setHasRealBuilding(Building.PALACE, True)
+ if civilization(Civ.OTTOMAN).has_state_religion(Religion.ISLAM):
+ city.setHasReligion(Religion.ISLAM, True, True, False)
+
+
+@handler("cityAcquired")
+def jerusalem_incentive(owner, player, city, bConquest, bTrade):
+ # 3Miro: Jerusalem's Golden Age Incentive
+
+ tCity = (city.getX(), city.getY())
+ if tCity == CITIES[City.JERUSALEM]:
+ pPlayer = gc.getPlayer(player)
+ if pPlayer.getStateReligion() == Religion.CATHOLICISM:
+ # Absinthe: spread Catholicism if not present already
+ if not city.isHasReligion(Religion.CATHOLICISM):
+ Religions.spreadReligion(tCity, Religion.CATHOLICISM)
+ Crusades.success(player)
+ message_if_human(
+ human(),
+ text("TXT_KEY_CRUSADE_JERUSALEM_SAFE", city.getNameKey()),
+ force=True,
+ color=MessageData.GREEN,
+ )
+
+ # Absinthe: acquiring Jerusalem, with any faith (but not Paganism) -> chance to find a relic
+ # maybe only after a specific date? maybe only if there isn't any ongoing Crusades?
+ if (
+ percentage_chance(15, strict=True)
+ and player in civilizations().majors().ids()
+ and pPlayer.getStateReligion() != -1
+ ):
+ pPlayer.initUnit(
+ Unit.HOLY_RELIC,
+ CITIES[City.JERUSALEM][0],
+ CITIES[City.JERUSALEM][1],
+ UnitAITypes.NO_UNITAI,
+ DirectionTypes.DIRECTION_SOUTH,
+ )
+
+
+@handler("BeginGameTurn")
+def viking_attack_on_constantinople(iGameTurn):
+ # Absinthe: 868AD Viking attack on Constantinople
+ if iGameTurn == year(860) + data.lEventRandomness[iByzantiumVikingAttack] - 2:
+ if human() == Civ.BYZANTIUM:
+ show(text("TXT_KEY_EVENT_VIKING_CONQUERERS_RUMOURS"))
+
+ if iGameTurn == year(860) + data.lEventRandomness[iByzantiumVikingAttack]:
+ if human() == Civ.BYZANTIUM:
+ for unit, number in zip((Unit.DENMARK_HUSKARL, Unit.VIKING_BERSERKER), (3, 4)):
+ Barbs.spawnUnits(
+ Civ.BARBARIAN,
+ (80, 24),
+ (80, 25),
+ unit,
+ number,
+ iGameTurn,
+ 1,
+ 0,
+ forcedInvasion,
+ UnitAITypes.UNITAI_ATTACK,
+ text("TXT_KEY_BARBARIAN_NAMES_VIKINGS"),
+ )
+ message(
+ Civ.BYZANTIUM,
+ text("TXT_KEY_EVENT_VIKING_CONQUERERS_ARRIVE"),
+ color=MessageData.RED,
+ )
+
+
+@handler("BeginPlayerTurn")
+def byzantine_conqueror_army(iGameTurn, iPlayer):
+ if iGameTurn == year(520) and iPlayer == Civ.BYZANTIUM:
+ pByzantium = gc.getPlayer(Civ.BYZANTIUM)
+ tStartingPlot = (59, 16)
+ for _ in range(5):
+ pByzantium.initUnit(
+ Unit.GALLEY,
+ tStartingPlot[0],
+ tStartingPlot[1],
+ UnitAITypes.UNITAI_ASSAULT_SEA,
+ DirectionTypes.DIRECTION_SOUTH,
+ )
+ great_general = pByzantium.initUnit(
+ Unit.GREAT_GENERAL,
+ tStartingPlot[0],
+ tStartingPlot[1],
+ UnitAITypes.UNITAI_GENERAL,
+ DirectionTypes.DIRECTION_SOUTH,
+ )
+ great_general.setName(text("TXT_KEY_GREAT_PERSON_BELISARIUS"))
+ make_units(Civ.BYZANTIUM, Unit.SWORDSMAN, tStartingPlot, 4)
+ make_units(Civ.BYZANTIUM, Unit.AXEMAN, tStartingPlot, 3)
+ make_units(Civ.BYZANTIUM, Unit.ARCHER, tStartingPlot, 2)
+ show_if_human(iPlayer, text("TXT_KEY_EVENT_CONQUEROR_BELISARIUS"))
def ottoman_invasion(iCiv, tPlot):
diff --git a/Assets/Python/Init.py b/Assets/Python/Init.py
new file mode 100644
index 000000000..0d3165632
--- /dev/null
+++ b/Assets/Python/Init.py
@@ -0,0 +1,46 @@
+from CvPythonExtensions import CyGlobalContext
+from Consts import WORLD_HEIGHT, WORLD_WIDTH
+from Core import civilizations, log
+from CoreTypes import Civ, PlagueType, ProvinceType, Religion, Technology
+from ProvinceMapData import PROVINCES_MAP
+
+gc = CyGlobalContext()
+
+
+def init():
+ init_player_variables()
+ init_provinces()
+ set_province_type_parameters()
+ log("RFCE: Init.init()")
+
+
+def init_player_variables():
+ gc.setSizeNPlayers(
+ WORLD_WIDTH,
+ WORLD_HEIGHT,
+ civilizations().majors().len(),
+ civilizations().drop(Civ.BARBARIAN).len(),
+ len(Technology),
+ PlagueType.BUILDING_PLAGUE,
+ len(Religion),
+ )
+ # set the Number of Provinces, call this before you set any AI or culture modifiers
+ gc.setProvinceTypeNumber(len(ProvinceType))
+
+
+def init_provinces():
+ # for plot in plots.all().filter(lambda p: get_data_from_province_map(p) > -1).entities():
+ for y in range(WORLD_HEIGHT):
+ for x in range(WORLD_WIDTH):
+ if PROVINCES_MAP[y][x] > -1:
+ gc.setProvince(x, y, PROVINCES_MAP[y][x])
+ gc.createProvinceCrossreferenceList()
+
+
+def set_province_type_parameters():
+ # How much culture should we get into a province of this type, ignore the war and settler values (0,0)
+ gc.setProvinceTypeParams(ProvinceType.NONE, 0, 0, 1, 3) # 1/3 culture
+ gc.setProvinceTypeParams(ProvinceType.CONTESTED, 0, 0, 1, 1) # no change to culture
+ gc.setProvinceTypeParams(ProvinceType.POTENTIAL, 0, 0, 1, 1) # same as outer culture
+ gc.setProvinceTypeParams(ProvinceType.HISTORICAL, 0, 0, 2, 1) # double-culture
+ gc.setProvinceTypeParams(ProvinceType.CORE, 0, 0, 3, 1) # triple-culture
diff --git a/Assets/Python/components/Mercenaries.py b/Assets/Python/Mercenaries.py
similarity index 70%
rename from Assets/Python/components/Mercenaries.py
rename to Assets/Python/Mercenaries.py
index f686a6ae0..2abb06da0 100644
--- a/Assets/Python/components/Mercenaries.py
+++ b/Assets/Python/Mercenaries.py
@@ -1,12 +1,20 @@
from CvPythonExtensions import *
-from Core import civilization, civilizations, message, human, text, turn, cities, units
+from Core import (
+ civilization,
+ civilizations,
+ message,
+ human,
+ message_if_human,
+ text,
+ turn,
+ cities,
+ units,
+)
from CoreTypes import Civ, Region, SpecialParameter, Religion, Promotion, Unit, Province
+from Events import handler
from LocationsData import REGIONS
from PyUtils import percentage_chance, rand, choice
-
-# import cPickle as pickle
from StoredData import data
-
from Consts import MessageData
gc = CyGlobalContext()
@@ -2718,92 +2726,138 @@
)
-class MercenaryManager:
- def __init__(self):
- self.lGlobalPool = []
- self.lHiredBy = []
- self.GMU = GlobalMercenaryUtils()
- pass
-
- def getMercLists(self):
- self.lGlobalPool = data.lMercGlobalPool
- self.lHiredBy = data.lMercsHiredBy
-
- def setMercLists(self):
- data.lMercGlobalPool = self.lGlobalPool
- data.lMercsHiredBy = self.lHiredBy
-
- def rendomizeMercProvinces(self, iGameTurn):
- if iGameTurn % 2 == rand(2):
- iHuman = gc.getGame().getActivePlayer()
- lHumanProvinces = self.GMU.getOwnedProvinces(iHuman)
- iMercsLeft = 0
- for lMerc in self.lGlobalPool:
- if percentage_chance(lMercList[lMerc[0]][6] / 2, strict=True):
- self.lGlobalPool.remove(lMerc)
- if lMerc[4] in lHumanProvinces:
- message(
- iHuman, text("TXT_KEY_MERC_NEW_MERC_MOVING"), color=MessageData.LIME
- )
- iMercsLeft += 1
- if iMercsLeft > 1:
- # don't let too many mercs leave the pool
- return
-
- def setPrereqConsistentPromotions(self, lPromotions):
- bPass = False
- while not bPass:
- bPass = True
- for iPromotion in lPromotions:
- pPromotionInfo = gc.getPromotionInfo(iPromotion)
- iPrereq = pPromotionInfo.getPrereqOrPromotion1()
- if iPrereq != -1 and iPrereq not in lPromotions:
- lPromotions.append(iPrereq)
- bPass = False
- iPrereq = pPromotionInfo.getPrereqOrPromotion2()
- if iPrereq != -1 and iPrereq not in lPromotions:
- lPromotions.append(iPrereq)
- bPass = False
- return lPromotions
-
- def addNewMerc(self, iMerc):
- # this processes the available promotions
- lMercInfo = lMercList[iMerc]
- iMercType = lMercInfo[0]
-
- # get the promotions
- iNumPromotions = 0
- lPromotions = []
- iIterations = (
- 0 # limit the number of iterations so we can have mercs with only a few promotions
- )
- while iNumPromotions < iNumPromotionsSoftCap and iIterations < iNumPromotionIterations:
- iPromotion = rand(iNumTotalMercPromotions)
- if isPromotionValid(iPromotion, iMercType, False):
- if iPromotion not in lPromotions and percentage_chance(
- lPromotionOdds[iPromotion], strict=True
- ):
- lPromotions.append(iPromotion)
- lPromotions = self.setPrereqConsistentPromotions(lPromotions)
- iNumPromotions = len(lPromotions)
- iIterations += 1
- # add the default (free) promotions for the given unit type
- for iPromotion in range(len(Promotion) - 1):
- if gc.getUnitInfo(iMercType).getFreePromotions(iPromotion):
- if iPromotion not in lPromotions:
- lPromotions.append(iPromotion)
+lGlobalPool = []
+lHiredBy = []
+
+
+def getMercLists():
+ global lGlobalPool
+ global lHiredBy
+ lGlobalPool = data.lMercGlobalPool
+ lHiredBy = data.lMercsHiredBy
+
+
+def setMercLists():
+ data.lMercGlobalPool = lGlobalPool
+ data.lMercsHiredBy = lHiredBy
+
+
+def getMercGlobalPool():
+ return data.lMercGlobalPool
- (iPurchaseCost, iUpkeepCost) = self.GMU.getCost(iMerc, lPromotions)
- iCurrentProvince = choice(lMercInfo[4])
- # Absinthe: different message for the human player for the various cases
+def setMercGlobalPool(lNewPool):
+ data.lMercGlobalPool = lNewPool
+
+
+def getMercHiredBy():
+ return data.lMercsHiredBy
+
+
+def setMercHiredBy(lNewList):
+ data.lMercsHiredBy = lNewList
+
+
+def rendomizeMercProvinces(iGameTurn):
+ if iGameTurn % 2 == rand(2):
iHuman = gc.getGame().getActivePlayer()
- pHuman = gc.getPlayer(iHuman)
- ProvMessage = False
- if pHuman.getProvinceCityCount(iCurrentProvince) > 0:
- # Absinthe: different message if the mercenaries don't like the player's state religion
- iStateReligion = pHuman.getStateReligion()
- if iStateReligion in lMercList[iMerc][5]:
+ lHumanProvinces = getOwnedProvinces(iHuman)
+ iMercsLeft = 0
+ for lMerc in lGlobalPool:
+ if percentage_chance(lMercList[lMerc[0]][6] / 2, strict=True):
+ lGlobalPool.remove(lMerc)
+ if lMerc[4] in lHumanProvinces:
+ message(iHuman, text("TXT_KEY_MERC_NEW_MERC_MOVING"), color=MessageData.LIME)
+ iMercsLeft += 1
+ if iMercsLeft > 1:
+ # don't let too many mercs leave the pool
+ return
+
+
+def setPrereqConsistentPromotions(lPromotions):
+ bPass = False
+ while not bPass:
+ bPass = True
+ for iPromotion in lPromotions:
+ pPromotionInfo = gc.getPromotionInfo(iPromotion)
+ iPrereq = pPromotionInfo.getPrereqOrPromotion1()
+ if iPrereq != -1 and iPrereq not in lPromotions:
+ lPromotions.append(iPrereq)
+ bPass = False
+ iPrereq = pPromotionInfo.getPrereqOrPromotion2()
+ if iPrereq != -1 and iPrereq not in lPromotions:
+ lPromotions.append(iPrereq)
+ bPass = False
+ return lPromotions
+
+
+def addNewMerc(iMerc):
+ # this processes the available promotions
+ lMercInfo = lMercList[iMerc]
+ iMercType = lMercInfo[0]
+
+ # get the promotions
+ iNumPromotions = 0
+ lPromotions = []
+ iIterations = (
+ 0 # limit the number of iterations so we can have mercs with only a few promotions
+ )
+ while iNumPromotions < iNumPromotionsSoftCap and iIterations < iNumPromotionIterations:
+ iPromotion = rand(iNumTotalMercPromotions)
+ if isPromotionValid(iPromotion, iMercType, False):
+ if iPromotion not in lPromotions and percentage_chance(
+ lPromotionOdds[iPromotion], strict=True
+ ):
+ lPromotions.append(iPromotion)
+ lPromotions = setPrereqConsistentPromotions(lPromotions)
+ iNumPromotions = len(lPromotions)
+ iIterations += 1
+ # add the default (free) promotions for the given unit type
+ for iPromotion in range(len(Promotion) - 1):
+ if gc.getUnitInfo(iMercType).getFreePromotions(iPromotion):
+ if iPromotion not in lPromotions:
+ lPromotions.append(iPromotion)
+
+ (iPurchaseCost, iUpkeepCost) = getCost(iMerc, lPromotions)
+ iCurrentProvince = choice(lMercInfo[4])
+
+ # Absinthe: different message for the human player for the various cases
+ iHuman = gc.getGame().getActivePlayer()
+ pHuman = gc.getPlayer(iHuman)
+ ProvMessage = False
+ if pHuman.getProvinceCityCount(iCurrentProvince) > 0:
+ # Absinthe: different message if the mercenaries don't like the player's state religion
+ iStateReligion = pHuman.getStateReligion()
+ if iStateReligion in lMercList[iMerc][5]:
+ szProvName = "TXT_KEY_PROVINCE_NAME_%i" % iCurrentProvince
+ szCurrentProvince = text(szProvName)
+ message(
+ iHuman,
+ text("TXT_KEY_MERC_NEW_MERC_AVAILABLE")
+ + " "
+ + szCurrentProvince
+ + text("TXT_KEY_MERC_NEW_MERC_RELIGION"),
+ color=MessageData.LIME,
+ )
+ else:
+ # Absinthe: normal message
+ for city in cities.owner(iHuman).entities():
+ if city.getProvince() == iCurrentProvince:
+ if city.getCultureLevel() >= 2:
+ szProvName = "TXT_KEY_PROVINCE_NAME_%i" % iCurrentProvince
+ szCurrentProvince = text(szProvName)
+ message(
+ iHuman,
+ text("TXT_KEY_MERC_NEW_MERC_AVAILABLE")
+ + " "
+ + szCurrentProvince
+ + "!",
+ color=MessageData.LIME,
+ )
+ ProvMessage = True
+ break
+ # Absinthe: different message if the player doesn't have enough culture in the province
+ if not ProvMessage:
szProvName = "TXT_KEY_PROVINCE_NAME_%i" % iCurrentProvince
szCurrentProvince = text(szProvName)
message(
@@ -2811,566 +2865,512 @@ def addNewMerc(self, iMerc):
text("TXT_KEY_MERC_NEW_MERC_AVAILABLE")
+ " "
+ szCurrentProvince
- + text("TXT_KEY_MERC_NEW_MERC_RELIGION"),
+ + text("TXT_KEY_MERC_NEW_MERC_CULTURE"),
color=MessageData.LIME,
)
- else:
- # Absinthe: normal message
- for city in cities().owner(iHuman).entities():
- if city.getProvince() == iCurrentProvince:
- if city.getCultureLevel() >= 2:
- szProvName = "TXT_KEY_PROVINCE_NAME_%i" % iCurrentProvince
- szCurrentProvince = text(szProvName)
- message(
- iHuman,
- text("TXT_KEY_MERC_NEW_MERC_AVAILABLE")
- + " "
- + szCurrentProvince
- + "!",
- color=MessageData.LIME,
- )
- ProvMessage = True
- break
- # Absinthe: different message if the player doesn't have enough culture in the province
- if not ProvMessage:
- szProvName = "TXT_KEY_PROVINCE_NAME_%i" % iCurrentProvince
- szCurrentProvince = text(szProvName)
- message(
- iHuman,
- text("TXT_KEY_MERC_NEW_MERC_AVAILABLE")
- + " "
- + szCurrentProvince
- + text("TXT_KEY_MERC_NEW_MERC_CULTURE"),
- color=MessageData.LIME,
- )
-
- # add the merc, keep the merc index, costs and promotions
- self.lGlobalPool.append([iMerc, lPromotions, iPurchaseCost, iUpkeepCost, iCurrentProvince])
-
- def processNewMercs(self, iGameTurn):
- # add new mercs to the pool
-
- potentialMercs = []
- alreadyAvailableMercs = []
- for iI in range(len(self.lGlobalPool)):
- alreadyAvailableMercs.append(self.lGlobalPool[iI][0])
-
- for iMerc in range(len(lMercList)):
- if (
- self.lHiredBy[iMerc] == -1
- and iMerc not in alreadyAvailableMercs
- and iGameTurn >= lMercList[iMerc][2]
- and iGameTurn <= lMercList[iMerc][3]
- ):
- potentialMercs.append(iMerc)
-
- iNumPotentialMercs = len(potentialMercs)
- if iNumPotentialMercs == 0:
- return
- # if there are mercs to be potentially added
- iStart = rand(iNumPotentialMercs)
- for iOffset in range(iNumPotentialMercs):
- iMerc = potentialMercs[(iOffset + iStart) % iNumPotentialMercs]
- if percentage_chance(lMercList[iMerc][6], strict=True):
- self.addNewMerc(iMerc)
-
- def doMercsTurn(self, iGameTurn):
- # this is called at the end of the game turn
- # thus the AI gets the advantage to make the Merc "decision" with the most up-to-date political data and they can get the mercs instantly
- # the Human gets the advantage to get the first pick at the available mercs
-
- self.getMercLists() # load the current mercenary pool
- iHuman = gc.getGame().getActivePlayer()
-
- # for lMerc in self.lGlobalPool:
-
- # Go through each of the players and deduct their mercenary maintenance amount from their gold (round up)
- for iPlayer in civilizations().main().ids():
- pPlayer = gc.getPlayer(iPlayer)
- if pPlayer.isAlive():
- if (
- pPlayer.getCommercePercent(CommerceTypes.COMMERCE_GOLD) == 100
- and pPlayer.getGold()
- < (
- pPlayer.getPicklefreeParameter(SpecialParameter.MERCENARY_COST_PER_TURN)
- + 99
- )
- / 100
- ):
- # not enough gold to pay the mercs, they will randomly desert you
- self.desertMercs(iPlayer)
-
- # Absinthe: added the subtraction directly in the inflated cost calculations in the .dll, so this is now redundant
- # pPlayer.setGold(pPlayer.getGold()-(pPlayer.getPicklefreeParameter( iMercCostPerTurn )+99)/100 )
- # TODO: AI
- if iPlayer != iHuman:
- self.processMercAI(iPlayer)
-
- self.rendomizeMercProvinces(iGameTurn) # some mercs may leave
-
- self.processNewMercs(iGameTurn) # add new Merc to the pool
- self.processNewMercs(iGameTurn) # can add up to 2 mercs per turn
-
- ### DEBUG - start
- # self.addNewMerc( 12 )
- # self.addNewMerc( 76 )
- ### DEBUG - end
-
- self.setMercLists() # save the potentially modified merc list (this allows for pickle read/write only once per turn)
-
- # self.GMU.hireMerc( self.lGlobalPool[0], Civ.FRANCE )
-
- def desertMercs(self, iPlayer):
- pPlayer = gc.getPlayer(iPlayer)
- if iPlayer == human():
- message(iPlayer, text("TXT_KEY_MERC_NEW_MERC_DESERTERS"), color=MessageData.LIGHT_RED)
-
- while True:
- lHiredMercs = units().owner(iPlayer).mercenaries().entities()
-
- if lHiredMercs:
- self.GMU.fireMerc(choice(lHiredMercs))
- else:
- break
- def onCityAcquiredAndKept(self, iCiv, pCity):
- # Absinthe: if there are mercs available in the new city's province, interface message about it to the human player
- iProvince = pCity.getProvince()
- self.getMercLists() # load the current mercenary pool
- for lMerc in self.lGlobalPool:
- if lMerc[4] == iProvince:
- if iCiv == human():
- message(
- iCiv,
- text("TXT_KEY_MERC_AVAILABLE_NEAR_NEW_CITY", pCity.getName()),
- button=ArtFileMgr.getInterfaceArtInfo(
- "INTERFACE_MERCENARY_ICON"
- ).getPath(),
- color=MessageData.LIME,
- location=pCity,
- )
- break
-
- def onCityBuilt(self, iCiv, pCity):
- # Absinthe: if there are mercs available in the new city's province, interface message about it to the human player
- iProvince = pCity.getProvince()
- self.getMercLists() # load the current mercenary pool
- for lMerc in self.lGlobalPool:
- if lMerc[4] == iProvince:
- if iCiv == human():
- message(
- iCiv,
- text("TXT_KEY_MERC_AVAILABLE_NEAR_NEW_CITY", pCity.getName()),
- button=ArtFileMgr.getInterfaceArtInfo(
- "INTERFACE_MERCENARY_ICON"
- ).getPath(),
- color=MessageData.LIME,
- location=pCity,
- )
- break
-
- def onUnitPromoted(self, argsList):
- pUnit, iNewPromotion = argsList
- iMerc = pUnit.getMercID()
- if iMerc > -1:
- # redraw the main screen to update the upkeep info
- CyInterface().setDirty(InterfaceDirtyBits.GameData_DIRTY_BIT, True)
-
- lPromotionList = []
- # almost all promotions are available through experience, so this is not only for the otherwise used iNumTotalMercPromotions
- for iPromotion in range(len(Promotion) - 1):
- if pUnit.isHasPromotion(iPromotion):
- lPromotionList.append(iPromotion)
- if iNewPromotion not in lPromotionList:
- lPromotionList.append(iNewPromotion)
-
- # get the new cost for this unit
- iOwner = pUnit.getOwner()
- iOldUpkeep = pUnit.getMercUpkeep()
- dummy, iNewUpkeep = self.GMU.getCost(iMerc, lPromotionList)
- iNewUpkeep = self.GMU.getModifiedCostPerPlayer(iNewUpkeep, iOwner)
-
- pUnit.setMercUpkeep(iNewUpkeep)
-
- pPlayer = gc.getPlayer(iOwner)
- pPlayer.setPicklefreeParameter(
- SpecialParameter.MERCENARY_COST_PER_TURN,
- max(
- 0,
- pPlayer.getPicklefreeParameter(SpecialParameter.MERCENARY_COST_PER_TURN)
- - iOldUpkeep
- + iNewUpkeep,
- ),
- )
- # self.GMU.playerMakeUpkeepSane( iOwner )
+ # add the merc, keep the merc index, costs and promotions
+ lGlobalPool.append([iMerc, lPromotions, iPurchaseCost, iUpkeepCost, iCurrentProvince])
- def onUnitKilled(self, argsList):
- pUnit, iAttacker = argsList
- iMerc = pUnit.getMercID()
+def processNewMercs(iGameTurn):
+ # add new mercs to the pool
- if iMerc > -1:
- lHiredByList = self.GMU.getMercHiredBy()
- if lHiredByList[iMerc] == -1: # merc was fired, then don't remove permanently
- return
- # unit is gone
- pPlayer = gc.getPlayer(pUnit.getOwner())
- pPlayer.setPicklefreeParameter(
- SpecialParameter.MERCENARY_COST_PER_TURN,
- max(
- 0,
- pPlayer.getPicklefreeParameter(SpecialParameter.MERCENARY_COST_PER_TURN)
- - pUnit.getMercUpkeep(),
- ),
- )
+ potentialMercs = []
+ alreadyAvailableMercs = []
+ for iI in range(len(lGlobalPool)):
+ alreadyAvailableMercs.append(lGlobalPool[iI][0])
- lHiredByList = self.GMU.getMercHiredBy()
- # remove the merc permanently
- lHiredByList[iMerc] = -2
- self.GMU.setMercHiredBy(lHiredByList)
-
- def onUnitLost(self, argsList):
- # this gets called on lost and on upgrade, check to remove the merc if it has not been upgraded?
- pUnit = argsList[0]
- iMerc = pUnit.getMercID()
-
- if iMerc > -1:
- # is a merc, check to see if it has just been killed
- lHiredByList = self.GMU.getMercHiredBy()
- if lHiredByList[iMerc] < 0:
- # unit has just been killed and onUnitKilled has been called or fired (-1 and -2)
- return
+ for iMerc in range(len(lMercList)):
+ if (
+ lHiredBy[iMerc] == -1
+ and iMerc not in alreadyAvailableMercs
+ and iGameTurn >= lMercList[iMerc][2]
+ and iGameTurn <= lMercList[iMerc][3]
+ ):
+ potentialMercs.append(iMerc)
- # check to see if it has been replaced by an upgraded (promoted) version of itself
- # Get the list of units for the player
- iPlayer = pUnit.getOwner()
-
- # unit is gone
- pPlayer = gc.getPlayer(iPlayer)
- pPlayer.setPicklefreeParameter(
- SpecialParameter.MERCENARY_COST_PER_TURN,
- max(
- 0,
- pPlayer.getPicklefreeParameter(SpecialParameter.MERCENARY_COST_PER_TURN)
- - pUnit.getMercUpkeep(),
- ),
- )
+ iNumPotentialMercs = len(potentialMercs)
+ if iNumPotentialMercs == 0:
+ return
+ # if there are mercs to be potentially added
+ iStart = rand(iNumPotentialMercs)
+ for iOffset in range(iNumPotentialMercs):
+ iMerc = potentialMercs[(iOffset + iStart) % iNumPotentialMercs]
+ if percentage_chance(lMercList[iMerc][6], strict=True):
+ addNewMerc(iMerc)
- # remove the merc (presumably disbanded here)
- lHiredByList[iMerc] = -1
- self.GMU.setMercHiredBy(lHiredByList)
- def processMercAI(self, iPlayer):
- pPlayer = gc.getPlayer(iPlayer)
- if pPlayer.isHuman() or pPlayer.isBarbarian() or iPlayer == Civ.POPE:
- return
+@handler("EndGameTurn")
+def doMercsTurn(iGameTurn):
+ # this is called at the end of the game turn
+ # thus the AI gets the advantage to make the Merc "decision" with the most up-to-date political data and they can get the mercs instantly
+ # the Human gets the advantage to get the first pick at the available mercs
- iWarValue = 0 # compute the total number of wars being fought at the moment
-
- teamPlayer = gc.getTeam(pPlayer.getTeam())
- for iOponent in civilizations().drop(Civ.BARBARIAN).ids():
- if teamPlayer.isAtWar(gc.getPlayer(iOponent).getTeam()):
- iWarValue += 1
- if iOponent <= Civ.POPE:
- iWarValue += 3
-
- # decide to hire or fire mercs
- # if we are at peace or have only a small war, then we can keep the merc if the expense is trivial
- # otherwise we should get rid of some mercs
- # we should also fire mercs if we spend too much
-
- bFire = False
-
- iGold = pPlayer.getGold()
- iUpkeep = pPlayer.getPicklefreeParameter(SpecialParameter.MERCENARY_COST_PER_TURN)
-
- if 100 * iGold < iUpkeep:
- # can't afford mercs, fire someone
- bFire = True
- elif iWarValue < 4 and 50 * iGold < iUpkeep:
- # mercs cost > 1/2 of our gold
- bFire = True
- elif iWarValue < 2 and 20 * iGold < iUpkeep:
- bFire = True
-
- if bFire:
- # the AI fires a Merc
- self.FireMercAI(iPlayer)
-
- # make sure we can affort the mercs that we keep
- while pPlayer.getPicklefreeParameter(
- SpecialParameter.MERCENARY_COST_PER_TURN
- ) > 0 and 100 * pPlayer.getGold() < pPlayer.getPicklefreeParameter(
- SpecialParameter.MERCENARY_COST_PER_TURN
- ):
- self.GMU.playerMakeUpkeepSane(pPlayer.getID())
- self.FireMercAI(iPlayer)
- return
+ getMercLists() # load the current mercenary pool
+ iHuman = gc.getGame().getActivePlayer()
- if iWarValue > 0:
- # we have to be at war to hire
- iOdds = civilization(iPlayer).misc.hire_mercenary_threshold
- if iWarValue < 2:
- iOdds *= 2 # small wars are hardly worth the trouble
- elif iWarValue > 4: # large war
- iOdds /= 2
-
- if percentage_chance(iOdds, strict=True, reverse=True):
- self.HireMercAI(iPlayer)
-
- def FireMercAI(self, iPlayer):
- iGameTurn = turn()
- lMercs = units().owner(iPlayer).mercenaries().entities()
-
- if lMercs:
- # we have mercs, so fire someone
- lMercValue = [] # estimate how "valuable" the merc is (high value is bad)
- for pUnit in lMercs:
- iValue = pUnit.getMercUpkeep()
- pPlot = gc.getMap().plot(pUnit.getX(), pUnit.getY())
- if pPlot.isCity():
- if pPlot.getPlotCity().getOwner() == iPlayer:
- # keep the city defenders
- iDefenders = self.getNumDefendersAtPlot(pPlot)
- if iDefenders < 2:
- iValue /= 100
- elif iDefenders < 4:
- iValue /= 2
-
- if iGameTurn > lMercList[pUnit.getMercID()][3]:
- # obsolete units
- iValue *= 2
- if iGameTurn > lMercList[pUnit.getMercID()][3] + 100:
- # really obsolete units
- iValue *= 5
- lMercValue.append(iValue)
-
- iSum = 0
- for iTempValue in lMercValue:
- iSum += iTempValue
-
- iFireRand = rand(iSum)
- for iI in range(len(lMercValue)):
- iFireRand -= lMercValue[iI]
- if iFireRand < 0:
- self.GMU.fireMerc(lMercs[iI])
- return
+ # for lMerc in lGlobalPool:
- def HireMercAI(self, iPlayer):
- # decide which mercenary to hire
- lCanHireMercs = []
+ # Go through each of the players and deduct their mercenary maintenance amount from their gold (round up)
+ for iPlayer in civilizations().main().ids():
pPlayer = gc.getPlayer(iPlayer)
- lPlayerProvinces = self.GMU.getCulturedProvinces(iPlayer)
- iGold = pPlayer.getGold()
- iStateReligion = pPlayer.getStateReligion()
- for lMerc in self.lGlobalPool:
- iMercTotalCost = self.GMU.getModifiedCostPerPlayer(
- lMerc[2] + (lMerc[3] + 99) / 100, iPlayer
- )
+ if pPlayer.isAlive():
if (
- iGold > iMercTotalCost
- and iStateReligion not in lMercList[lMerc[0]][5]
- and lMerc[4] in lPlayerProvinces
+ pPlayer.getCommercePercent(CommerceTypes.COMMERCE_GOLD) == 100
+ and pPlayer.getGold()
+ < (pPlayer.getPicklefreeParameter(SpecialParameter.MERCENARY_COST_PER_TURN) + 99)
+ / 100
):
- lCanHireMercs.append(lMerc)
-
- if lCanHireMercs:
- self.GMU.hireMerc(choice(lCanHireMercs), iPlayer)
- self.getMercLists()
-
- def getNumDefendersAtPlot(self, pPlot):
- iOwner = pPlot.getOwner()
- if iOwner < 0:
- return 0
- iNumUnits = pPlot.getNumUnits()
- iDefenders = 0
- for i in range(iNumUnits):
- if pPlot.getUnit(i).getOwner() == iOwner:
- iDefenders += 1
- return iDefenders
-
-
-class GlobalMercenaryUtils:
- # the idea of this class is to provide ways to manipulate the mercenaries without the need to make a separate instance of the MercenaryManager
- # the MercManager provides event driven functions and those should be called from the event interface
- # the Utils class should be used for interface commands (like for the Human UI)
-
- def getMercGlobalPool(self):
- return data.lMercGlobalPool
-
- def setMercGlobalPool(self, lNewPool):
- data.lMercGlobalPool = lNewPool
-
- def getMercHiredBy(self):
- return data.lMercsHiredBy
-
- def setMercHiredBy(self, lNewList):
- data.lMercsHiredBy = lNewList
-
- def getOwnedProvinces(self, iPlayer):
- lProvList = [] # all available cities that the Merc can appear in
- for city in cities().owner(iPlayer).entities():
- iProvince = city.getProvince()
- if iProvince not in lProvList:
- lProvList.append(iProvince)
- return lProvList
-
- def getCulturedProvinces(self, iPlayer):
- lProvList = [] # all available cities that the Merc can appear in
- for city in cities().owner(iPlayer).entities():
- iProvince = city.getProvince()
- if iProvince not in lProvList and city.getCultureLevel() >= 2:
- lProvList.append(iProvince)
- return lProvList
-
- def playerMakeUpkeepSane(self, iPlayer):
- pPlayer = gc.getPlayer(iPlayer)
- lMercs = units().owner(iPlayer).mercenaries().entities()
+ # not enough gold to pay the mercs, they will randomly desert you
+ desertMercs(iPlayer)
- iTotalUpkeep = 0
- for pUnit in lMercs:
- # iTotalUpkeep += self.getModifiedCostPerPlayer( pUnit.getMercUpkeep(), iPlayer )
- iTotalUpkeep += pUnit.getMercUpkeep()
-
- iSavedUpkeep = pPlayer.getPicklefreeParameter(SpecialParameter.MERCENARY_COST_PER_TURN)
- if iSavedUpkeep != iTotalUpkeep:
- pPlayer.setPicklefreeParameter(SpecialParameter.MERCENARY_COST_PER_TURN, iTotalUpkeep)
- return False
- return True
-
- def getCost(self, iMerc, lPromotions):
- # note that the upkeep is in the units of 100, i.e. iUpkeepCost = 100 means 1 gold
- lMercInfo = lMercList[iMerc]
-
- # compute cost
- iBaseCost = (
- 30 + (85 * gc.getUnitInfo(lMercInfo[0]).getProductionCost()) / 100
- ) # note that this is the base production cost (between 30 and 200), without the civ-specific modifiers
- iPercentage = 0
- for iPromotion in lPromotions:
- iPercentage += lPromotionCost[iPromotion]
- iPromotionModifier = 100 + (iPercentage * 3) / 5 # in percentage
- iPurchaseCost = (iBaseCost * iPromotionModifier) / 100
-
- # 1 gold of upkeep for each 55 hammers in the unit's production cost
- # the minimum amount is 1,4 gold, the maximum is 4,5 gold for the base upkeep
- iUpkeepBaseCost = 85 + max(
- 55, min((100 * gc.getUnitInfo(lMercInfo[0]).getProductionCost()) / 55, 365)
- ) # note that this is the base production cost (between 30 and 200), without the civ-specific modifiers
- iUpkeepPromotionModifier = 100 + (iPercentage * 2) / 5 # in percentage
- iUpkeepCost = (iUpkeepBaseCost * iUpkeepPromotionModifier) / 100
-
- return (iPurchaseCost, iUpkeepCost)
-
- def getModifiedCostPerPlayer(self, iCost, iPlayer):
- # Absinthe: we need to make it sure this is modified only once for each mercenary on the mercenary screen
- # handled on the screen separately, this should be fine the way it is now
- # 3MiroUP: this function gets called:
- # - every time a merc is hired (pPlayer.initUnit) to set the upkeep
- # - every time a merc cost is considered
- # - every time a merc cost is to be displayed (in the merc screen)
- return (iCost * lMercCostModifier[iPlayer]) / 100
-
- def hireMerc(self, lMerc, iPlayer):
- # the player would hire a merc
- lGlobalPool = self.getMercGlobalPool()
- lHiredByList = self.getMercHiredBy()
- iCost = self.getModifiedCostPerPlayer(lMerc[2], iPlayer)
- iUpkeep = self.getModifiedCostPerPlayer(lMerc[3], iPlayer)
- pPlayer = gc.getPlayer(iPlayer)
- if pPlayer.getGold() < iCost:
- return
+ # Absinthe: added the subtraction directly in the inflated cost calculations in the .dll, so this is now redundant
+ # pPlayer.setGold(pPlayer.getGold()-(pPlayer.getPicklefreeParameter( iMercCostPerTurn )+99)/100 )
+ # TODO: AI
+ if iPlayer != iHuman:
+ processMercAI(iPlayer)
- lCityList = [] # all available cities that the Merc can appear in
- for city in cities().owner(iPlayer).entities():
- if city.getProvince() == lMerc[4]:
- # Absinthe: note that naval mercs can appear in all coastal cities if we have enough culture in the province (at least one cultured enough city)
- iMercType = lMercList[lMerc[0]][0]
- if gc.getUnitInfo(iMercType).getDomainType() == 0:
- if city.isCoastal(1):
- lCityList.append(city)
- # Absinthe: otherwise only in cities with enough culture
- else:
- if city.getCultureLevel() >= 2:
- lCityList.append(city)
+ rendomizeMercProvinces(iGameTurn) # some mercs may leave
- if not lCityList:
- return
+ processNewMercs(iGameTurn) # add new Merc to the pool
+ processNewMercs(iGameTurn) # can add up to 2 mercs per turn
- pCity = choice(lCityList)
+ ### DEBUG - start
+ # addNewMerc( 12 )
+ # addNewMerc( 76 )
+ ### DEBUG - end
- iX = pCity.getX()
- iY = pCity.getY()
+ setMercLists() # save the potentially modified merc list (this allows for pickle read/write only once per turn)
- # do the Gold
- pPlayer.setGold(pPlayer.getGold() - iCost)
- pPlayer.setPicklefreeParameter(
- SpecialParameter.MERCENARY_COST_PER_TURN,
- pPlayer.getPicklefreeParameter(SpecialParameter.MERCENARY_COST_PER_TURN) + iUpkeep,
- )
- # remove the merc from the global pool and set the "hired by" index
- lGlobalPool.remove(lMerc)
- lHiredByList[lMerc[0]] = iPlayer
+def desertMercs(iPlayer):
+ message_if_human(iPlayer, text("TXT_KEY_MERC_NEW_MERC_DESERTERS"), color=MessageData.LIGHT_RED)
- self.setMercGlobalPool(lGlobalPool)
- self.setMercHiredBy(lHiredByList)
+ while True:
+ lHiredMercs = units.owner(iPlayer).mercenaries().entities()
+ if lHiredMercs:
+ fireMerc(choice(lHiredMercs))
+ else:
+ break
- # message for the human player if another civ hired a merc which was also available for him/her
- iHuman = human()
- if iPlayer != iHuman:
- lHumanProvList = self.getOwnedProvinces(iHuman)
- if lMerc[4] in lHumanProvList:
- szProvName = "TXT_KEY_PROVINCE_NAME_%i" % lMerc[4]
- szCurrentProvince = text(szProvName)
+
+@handler("cityBuilt")
+def onCityBuilt(pCity):
+ # Absinthe: if there are mercs available in the new city's province, interface message about it to the human player
+ iCiv = pCity.getOwner()
+ iProvince = pCity.getProvince()
+ getMercLists() # load the current mercenary pool
+ for lMerc in lGlobalPool:
+ if lMerc[4] == iProvince:
+ if iCiv == human():
message(
- iHuman,
- text("TXT_KEY_MERC_HIRED_BY_SOMEONE", szCurrentProvince),
+ iCiv,
+ text("TXT_KEY_MERC_AVAILABLE_NEAR_NEW_CITY", pCity.getName()),
+ button=ArtFileMgr.getInterfaceArtInfo("INTERFACE_MERCENARY_ICON").getPath(),
color=MessageData.LIME,
+ location=pCity,
)
+ break
- # make the unit:
- pUnit = pPlayer.initUnit(
- lMercList[lMerc[0]][0], iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH
+
+@handler("unitPromoted")
+def onUnitPromoted(pUnit, iNewPromotion):
+ # This method will redraw the main interface once a unit is promoted. This way the
+ # gold/turn information will be updated.
+ iMerc = pUnit.getMercID()
+ if iMerc > -1:
+ # redraw the main screen to update the upkeep info
+ CyInterface().setDirty(InterfaceDirtyBits.GameData_DIRTY_BIT, True)
+
+ lPromotionList = []
+ # almost all promotions are available through experience, so this is not only for the otherwise used iNumTotalMercPromotions
+ for iPromotion in range(len(Promotion) - 1):
+ if pUnit.isHasPromotion(iPromotion):
+ lPromotionList.append(iPromotion)
+ if iNewPromotion not in lPromotionList:
+ lPromotionList.append(iNewPromotion)
+
+ # get the new cost for this unit
+ iOwner = pUnit.getOwner()
+ iOldUpkeep = pUnit.getMercUpkeep()
+ dummy, iNewUpkeep = getCost(iMerc, lPromotionList)
+ iNewUpkeep = getModifiedCostPerPlayer(iNewUpkeep, iOwner)
+
+ pUnit.setMercUpkeep(iNewUpkeep)
+
+ pPlayer = gc.getPlayer(iOwner)
+ pPlayer.setPicklefreeParameter(
+ SpecialParameter.MERCENARY_COST_PER_TURN,
+ max(
+ 0,
+ pPlayer.getPicklefreeParameter(SpecialParameter.MERCENARY_COST_PER_TURN)
+ - iOldUpkeep
+ + iNewUpkeep,
+ ),
)
- if lMercList[lMerc[0]][1] != "TXT_KEY_MERC_GENERIC":
- pUnit.setName(text(lMercList[lMerc[0]][1]))
- # add the promotions
- for iPromotion in lMerc[1]:
- pUnit.setHasPromotion(iPromotion, True)
- if not pUnit.isHasPromotion(Promotion.MERC):
- pUnit.setHasPromotion(Promotion.MERC, True)
+@handler("unitKilled")
+def onUnitKilled(pUnit, iAttacker):
+ # This method will remove a mercenary unit from the game if it is killed
+ iMerc = pUnit.getMercID()
+
+ if iMerc > -1:
+ lHiredByList = getMercHiredBy()
+ if lHiredByList[iMerc] == -1: # merc was fired, then don't remove permanently
+ return
+ # unit is gone
+ pPlayer = gc.getPlayer(pUnit.getOwner())
+ pPlayer.setPicklefreeParameter(
+ SpecialParameter.MERCENARY_COST_PER_TURN,
+ max(
+ 0,
+ pPlayer.getPicklefreeParameter(SpecialParameter.MERCENARY_COST_PER_TURN)
+ - pUnit.getMercUpkeep(),
+ ),
+ )
- # set the MercID
- pUnit.setMercID(lMerc[0])
+ lHiredByList = getMercHiredBy()
+ # remove the merc permanently
+ lHiredByList[iMerc] = -2
+ setMercHiredBy(lHiredByList)
- # set the Upkeep
- pUnit.setMercUpkeep(iUpkeep)
- def fireMerc(self, pMerc):
- # fires the merc unit pMerc (pointer to CyUnit)
- lHiredByList = self.getMercHiredBy()
+@handler("unitLost")
+def onUnitLost(pUnit):
+ # This method will remove a mercenary unit from the game if it is lost
+ # this gets called on lost and on upgrade, check to remove the merc if it has not been upgraded?
+ iMerc = pUnit.getMercID()
- # get the Merc info
- iMerc = pMerc.getMercID()
- iUpkeep = pMerc.getMercUpkeep()
- if iMerc < 0:
+ if iMerc > -1:
+ # is a merc, check to see if it has just been killed
+ lHiredByList = getMercHiredBy()
+ if lHiredByList[iMerc] < 0:
+ # unit has just been killed and onUnitKilled has been called or fired (-1 and -2)
return
- # free the Merc for a new contract
- lHiredByList[iMerc] = -1
- self.setMercHiredBy(lHiredByList)
+ # check to see if it has been replaced by an upgraded (promoted) version of it
+ # Get the list of units for the player
+ iPlayer = pUnit.getOwner()
- # lower the upkeep
- pPlayer = gc.getPlayer(pMerc.getOwner())
+ # unit is gone
+ pPlayer = gc.getPlayer(iPlayer)
pPlayer.setPicklefreeParameter(
SpecialParameter.MERCENARY_COST_PER_TURN,
max(
0,
- pPlayer.getPicklefreeParameter(SpecialParameter.MERCENARY_COST_PER_TURN) - iUpkeep,
+ pPlayer.getPicklefreeParameter(SpecialParameter.MERCENARY_COST_PER_TURN)
+ - pUnit.getMercUpkeep(),
),
)
- pMerc.kill(0, -1)
+ # remove the merc (presumably disbanded here)
+ lHiredByList[iMerc] = -1
+ setMercHiredBy(lHiredByList)
+
+
+def processMercAI(iPlayer):
+ pPlayer = gc.getPlayer(iPlayer)
+ if pPlayer.isHuman() or pPlayer.isBarbarian() or iPlayer == Civ.POPE:
+ return
+
+ iWarValue = 0 # compute the total number of wars being fought at the moment
+
+ teamPlayer = gc.getTeam(pPlayer.getTeam())
+ for iOponent in civilizations().drop(Civ.BARBARIAN).ids():
+ if teamPlayer.isAtWar(gc.getPlayer(iOponent).getTeam()):
+ iWarValue += 1
+ if iOponent <= Civ.POPE:
+ iWarValue += 3
+
+ # decide to hire or fire mercs
+ # if we are at peace or have only a small war, then we can keep the merc if the expense is trivial
+ # otherwise we should get rid of some mercs
+ # we should also fire mercs if we spend too much
+
+ bFire = False
+
+ iGold = pPlayer.getGold()
+ iUpkeep = pPlayer.getPicklefreeParameter(SpecialParameter.MERCENARY_COST_PER_TURN)
+
+ if 100 * iGold < iUpkeep:
+ # can't afford mercs, fire someone
+ bFire = True
+ elif iWarValue < 4 and 50 * iGold < iUpkeep:
+ # mercs cost > 1/2 of our gold
+ bFire = True
+ elif iWarValue < 2 and 20 * iGold < iUpkeep:
+ bFire = True
+
+ if bFire:
+ # the AI fires a Merc
+ FireMercAI(iPlayer)
+
+ # make sure we can affort the mercs that we keep
+ while pPlayer.getPicklefreeParameter(
+ SpecialParameter.MERCENARY_COST_PER_TURN
+ ) > 0 and 100 * pPlayer.getGold() < pPlayer.getPicklefreeParameter(
+ SpecialParameter.MERCENARY_COST_PER_TURN
+ ):
+ playerMakeUpkeepSane(pPlayer.getID())
+ FireMercAI(iPlayer)
+ return
+
+ if iWarValue > 0:
+ # we have to be at war to hire
+ iOdds = civilization(iPlayer).misc.hire_mercenary_threshold
+ if iWarValue < 2:
+ iOdds *= 2 # small wars are hardly worth the trouble
+ elif iWarValue > 4: # large war
+ iOdds /= 2
+
+ if percentage_chance(iOdds, strict=True, reverse=True):
+ HireMercAI(iPlayer)
+
+
+def FireMercAI(iPlayer):
+ iGameTurn = turn()
+ lMercs = units.owner(iPlayer).mercenaries().entities()
+
+ if lMercs:
+ # we have mercs, so fire someone
+ lMercValue = [] # estimate how "valuable" the merc is (high value is bad)
+ for pUnit in lMercs:
+ iValue = pUnit.getMercUpkeep()
+ pPlot = gc.getMap().plot(pUnit.getX(), pUnit.getY())
+ if pPlot.isCity():
+ if pPlot.getPlotCity().getOwner() == iPlayer:
+ # keep the city defenders
+ iDefenders = getNumDefendersAtPlot(pPlot)
+ if iDefenders < 2:
+ iValue /= 100
+ elif iDefenders < 4:
+ iValue /= 2
+
+ if iGameTurn > lMercList[pUnit.getMercID()][3]:
+ # obsolete units
+ iValue *= 2
+ if iGameTurn > lMercList[pUnit.getMercID()][3] + 100:
+ # really obsolete units
+ iValue *= 5
+ lMercValue.append(iValue)
+
+ iSum = 0
+ for iTempValue in lMercValue:
+ iSum += iTempValue
+
+ iFireRand = rand(iSum)
+ for iI in range(len(lMercValue)):
+ iFireRand -= lMercValue[iI]
+ if iFireRand < 0:
+ fireMerc(lMercs[iI])
+ return
+
+
+def HireMercAI(iPlayer):
+ # decide which mercenary to hire
+ lCanHireMercs = []
+ pPlayer = gc.getPlayer(iPlayer)
+ lPlayerProvinces = getCulturedProvinces(iPlayer)
+ iGold = pPlayer.getGold()
+ iStateReligion = pPlayer.getStateReligion()
+ for lMerc in lGlobalPool:
+ iMercTotalCost = getModifiedCostPerPlayer(lMerc[2] + (lMerc[3] + 99) / 100, iPlayer)
+ if (
+ iGold > iMercTotalCost
+ and iStateReligion not in lMercList[lMerc[0]][5]
+ and lMerc[4] in lPlayerProvinces
+ ):
+ lCanHireMercs.append(lMerc)
+
+ if lCanHireMercs:
+ hireMerc(choice(lCanHireMercs), iPlayer)
+ getMercLists()
+
+
+def getNumDefendersAtPlot(pPlot):
+ iOwner = pPlot.getOwner()
+ if iOwner < 0:
+ return 0
+ iNumUnits = pPlot.getNumUnits()
+ iDefenders = 0
+ for i in range(iNumUnits):
+ if pPlot.getUnit(i).getOwner() == iOwner:
+ iDefenders += 1
+ return iDefenders
+
+
+def getOwnedProvinces(iPlayer):
+ lProvList = [] # all available cities that the Merc can appear in
+ for city in cities.owner(iPlayer).entities():
+ iProvince = city.getProvince()
+ if iProvince not in lProvList:
+ lProvList.append(iProvince)
+ return lProvList
+
+
+def getCulturedProvinces(iPlayer):
+ lProvList = [] # all available cities that the Merc can appear in
+ for city in cities.owner(iPlayer).entities():
+ iProvince = city.getProvince()
+ if iProvince not in lProvList and city.getCultureLevel() >= 2:
+ lProvList.append(iProvince)
+ return lProvList
+
+
+def playerMakeUpkeepSane(iPlayer):
+ pPlayer = gc.getPlayer(iPlayer)
+ lMercs = units.owner(iPlayer).mercenaries().entities()
+
+ iTotalUpkeep = 0
+ for pUnit in lMercs:
+ # iTotalUpkeep += getModifiedCostPerPlayer( pUnit.getMercUpkeep(), iPlayer )
+ iTotalUpkeep += pUnit.getMercUpkeep()
+
+ iSavedUpkeep = pPlayer.getPicklefreeParameter(SpecialParameter.MERCENARY_COST_PER_TURN)
+ if iSavedUpkeep != iTotalUpkeep:
+ pPlayer.setPicklefreeParameter(SpecialParameter.MERCENARY_COST_PER_TURN, iTotalUpkeep)
+ return False
+ return True
+
+
+def getCost(iMerc, lPromotions):
+ # note that the upkeep is in the units of 100, i.e. iUpkeepCost = 100 means 1 gold
+ lMercInfo = lMercList[iMerc]
+
+ # compute cost
+ iBaseCost = (
+ 30 + (85 * gc.getUnitInfo(lMercInfo[0]).getProductionCost()) / 100
+ ) # note that this is the base production cost (between 30 and 200), without the civ-specific modifiers
+ iPercentage = 0
+ for iPromotion in lPromotions:
+ iPercentage += lPromotionCost[iPromotion]
+ iPromotionModifier = 100 + (iPercentage * 3) / 5 # in percentage
+ iPurchaseCost = (iBaseCost * iPromotionModifier) / 100
+
+ # 1 gold of upkeep for each 55 hammers in the unit's production cost
+ # the minimum amount is 1,4 gold, the maximum is 4,5 gold for the base upkeep
+ iUpkeepBaseCost = 85 + max(
+ 55, min((100 * gc.getUnitInfo(lMercInfo[0]).getProductionCost()) / 55, 365)
+ ) # note that this is the base production cost (between 30 and 200), without the civ-specific modifiers
+ iUpkeepPromotionModifier = 100 + (iPercentage * 2) / 5 # in percentage
+ iUpkeepCost = (iUpkeepBaseCost * iUpkeepPromotionModifier) / 100
+
+ return (iPurchaseCost, iUpkeepCost)
+
+
+def getModifiedCostPerPlayer(iCost, iPlayer):
+ # Absinthe: we need to make it sure this is modified only once for each mercenary on the mercenary screen
+ # handled on the screen separately, this should be fine the way it is now
+ # 3MiroUP: this function gets called:
+ # - every time a merc is hired (pPlayer.initUnit) to set the upkeep
+ # - every time a merc cost is considered
+ # - every time a merc cost is to be displayed (in the merc screen)
+ return (iCost * lMercCostModifier[iPlayer]) / 100
+
+
+def hireMerc(lMerc, iPlayer):
+ # the player would hire a merc
+ lGlobalPool = getMercGlobalPool()
+ lHiredByList = getMercHiredBy()
+ iCost = getModifiedCostPerPlayer(lMerc[2], iPlayer)
+ iUpkeep = getModifiedCostPerPlayer(lMerc[3], iPlayer)
+ pPlayer = gc.getPlayer(iPlayer)
+ if pPlayer.getGold() < iCost:
+ return
+
+ lCityList = [] # all available cities that the Merc can appear in
+ for city in cities.owner(iPlayer).entities():
+ if city.getProvince() == lMerc[4]:
+ # Absinthe: note that naval mercs can appear in all coastal cities if we have enough culture in the province (at least one cultured enough city)
+ iMercType = lMercList[lMerc[0]][0]
+ if gc.getUnitInfo(iMercType).getDomainType() == 0:
+ if city.isCoastal(1):
+ lCityList.append(city)
+ # Absinthe: otherwise only in cities with enough culture
+ else:
+ if city.getCultureLevel() >= 2:
+ lCityList.append(city)
+
+ if not lCityList:
+ return
+
+ pCity = choice(lCityList)
+
+ iX = pCity.getX()
+ iY = pCity.getY()
+
+ # do the Gold
+ pPlayer.setGold(pPlayer.getGold() - iCost)
+ pPlayer.setPicklefreeParameter(
+ SpecialParameter.MERCENARY_COST_PER_TURN,
+ pPlayer.getPicklefreeParameter(SpecialParameter.MERCENARY_COST_PER_TURN) + iUpkeep,
+ )
+
+ # remove the merc from the global pool and set the "hired by" index
+ lGlobalPool.remove(lMerc)
+ lHiredByList[lMerc[0]] = iPlayer
+
+ setMercGlobalPool(lGlobalPool)
+ setMercHiredBy(lHiredByList)
+
+ # message for the human player if another civ hired a merc which was also available for him/her
+ iHuman = human()
+ if iPlayer != iHuman:
+ lHumanProvList = getOwnedProvinces(iHuman)
+ if lMerc[4] in lHumanProvList:
+ szProvName = "TXT_KEY_PROVINCE_NAME_%i" % lMerc[4]
+ szCurrentProvince = text(szProvName)
+ message(
+ iHuman,
+ text("TXT_KEY_MERC_HIRED_BY_SOMEONE", szCurrentProvince),
+ color=MessageData.LIME,
+ )
+
+ # make the unit:
+ pUnit = pPlayer.initUnit(
+ lMercList[lMerc[0]][0], iX, iY, UnitAITypes.NO_UNITAI, DirectionTypes.DIRECTION_SOUTH
+ )
+ if lMercList[lMerc[0]][1] != "TXT_KEY_MERC_GENERIC":
+ pUnit.setName(text(lMercList[lMerc[0]][1]))
+
+ # add the promotions
+ for iPromotion in lMerc[1]:
+ pUnit.setHasPromotion(iPromotion, True)
+
+ if not pUnit.isHasPromotion(Promotion.MERC):
+ pUnit.setHasPromotion(Promotion.MERC, True)
+
+ # set the MercID
+ pUnit.setMercID(lMerc[0])
+
+ # set the Upkeep
+ pUnit.setMercUpkeep(iUpkeep)
+
+
+def fireMerc(pMerc):
+ # fires the merc unit pMerc (pointer to CyUnit)
+ lHiredByList = getMercHiredBy()
+
+ # get the Merc info
+ iMerc = pMerc.getMercID()
+ iUpkeep = pMerc.getMercUpkeep()
+ if iMerc < 0:
+ return
+
+ # free the Merc for a new contract
+ lHiredByList[iMerc] = -1
+ setMercHiredBy(lHiredByList)
+
+ # lower the upkeep
+ pPlayer = gc.getPlayer(pMerc.getOwner())
+ pPlayer.setPicklefreeParameter(
+ SpecialParameter.MERCENARY_COST_PER_TURN,
+ max(
+ 0,
+ pPlayer.getPicklefreeParameter(SpecialParameter.MERCENARY_COST_PER_TURN) - iUpkeep,
+ ),
+ )
+
+ pMerc.kill(0, -1)
diff --git a/Assets/Python/Messages.py b/Assets/Python/Messages.py
new file mode 100644
index 000000000..e19072e99
--- /dev/null
+++ b/Assets/Python/Messages.py
@@ -0,0 +1,207 @@
+from CvPythonExtensions import CyArtFileMgr, CyGlobalContext, InterfaceMessageTypes
+from Consts import MessageData
+from Core import human, message, player, show, team, text, year
+from CoreTypes import Building, Civ, Wonder
+from Events import handler
+import Mercenaries
+
+ArtFileMgr = CyArtFileMgr()
+gc = CyGlobalContext()
+
+
+@handler("cityAcquiredAndKept")
+def announce_wonder_captered_when_city_acquired_and_kept(iPlayer, city):
+ if city.getNumWorldWonders() > 0:
+ ConquerPlayer = gc.getPlayer(city.getOwner())
+ ConquerTeam = ConquerPlayer.getTeam()
+ if city.getPreviousOwner() != -1:
+ PreviousPlayer = gc.getPlayer(city.getPreviousOwner())
+ PreviousTeam = PreviousPlayer.getTeam()
+ HumanTeam = team()
+ if ConquerPlayer.isHuman() or (
+ player().isExisting()
+ and (HumanTeam.isHasMet(ConquerTeam) or HumanTeam.isHasMet(PreviousTeam))
+ ):
+ # Absinthe: collect all wonders, including shrines
+ lAllWonders = [w for w in Wonder] + [
+ Building.CATHOLIC_SHRINE,
+ Building.ORTHODOX_SHRINE,
+ Building.ISLAMIC_SHRINE,
+ Building.PROTESTANT_SHRINE,
+ ]
+ for iWonder in lAllWonders:
+ if city.getNumBuilding(iWonder) > 0:
+ sWonderName = gc.getBuildingInfo(iWonder).getDescription()
+ if ConquerPlayer.isHuman():
+ message(
+ human(),
+ text("TXT_KEY_MISC_WONDER_CAPTURED_1", sWonderName),
+ event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
+ button=gc.getBuildingInfo(iWonder).getButton(),
+ color=MessageData.BLUE,
+ location=city,
+ )
+ elif HumanTeam.isHasMet(ConquerTeam):
+ ConquerName = ConquerPlayer.getCivilizationDescriptionKey()
+ message(
+ human(),
+ text("TXT_KEY_MISC_WONDER_CAPTURED_2", ConquerName, sWonderName),
+ event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
+ button=gc.getBuildingInfo(iWonder).getButton(),
+ color=MessageData.CYAN,
+ location=city,
+ )
+ elif HumanTeam.isHasMet(PreviousTeam):
+ PreviousName = PreviousPlayer.getCivilizationDescriptionKey()
+ message(
+ human(),
+ text("TXT_KEY_MISC_WONDER_CAPTURED_3", PreviousName, sWonderName),
+ event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
+ button=gc.getBuildingInfo(iWonder).getButton(),
+ color=MessageData.CYAN,
+ location=city,
+ )
+
+
+@handler("cityRazed")
+def announce_wonder_destroyed_when_city_razed(city, iPlayer):
+ if city.getNumWorldWonders() > 0:
+ ConquerPlayer = gc.getPlayer(city.getOwner())
+ ConquerTeam = ConquerPlayer.getTeam()
+ if city.getPreviousOwner() != -1:
+ PreviousPlayer = gc.getPlayer(city.getPreviousOwner())
+ PreviousTeam = PreviousPlayer.getTeam()
+ HumanTeam = team()
+ if ConquerPlayer.isHuman() or (
+ player().isExisting()
+ and (HumanTeam.isHasMet(ConquerTeam) or HumanTeam.isHasMet(PreviousTeam))
+ ):
+ # Absinthe: collect all wonders, including shrines (even though cities with shrines can't be destroyed in the mod)
+ lAllWonders = [w for w in Wonder]
+ for iWonder in [
+ Building.CATHOLIC_SHRINE,
+ Building.ORTHODOX_SHRINE,
+ Building.ISLAMIC_SHRINE,
+ Building.PROTESTANT_SHRINE,
+ ]:
+ lAllWonders.append(iWonder)
+ for iWonder in lAllWonders:
+ if city.getNumBuilding(iWonder) > 0:
+ sWonderName = gc.getBuildingInfo(iWonder).getDescription()
+ if ConquerPlayer.isHuman():
+ message(
+ human(),
+ text("TXT_KEY_MISC_WONDER_DESTROYED_1", sWonderName),
+ event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
+ button=gc.getBuildingInfo(iWonder).getButton(),
+ color=MessageData.LIGHT_RED,
+ location=city,
+ )
+ elif HumanTeam.isHasMet(ConquerTeam):
+ ConquerName = ConquerPlayer.getCivilizationDescriptionKey()
+ message(
+ human(),
+ text("TXT_KEY_MISC_WONDER_DESTROYED_2", ConquerName, sWonderName),
+ event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
+ button=gc.getBuildingInfo(iWonder).getButton(),
+ color=MessageData.LIGHT_RED,
+ location=city,
+ )
+ elif HumanTeam.isHasMet(PreviousTeam):
+ PreviousName = PreviousPlayer.getCivilizationDescriptionKey()
+ message(
+ human(),
+ text("TXT_KEY_MISC_WONDER_DESTROYED_3", PreviousName, sWonderName),
+ event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
+ button=gc.getBuildingInfo(iWonder).getButton(),
+ color=MessageData.LIGHT_RED,
+ location=city,
+ )
+
+
+@handler("cityAcquired")
+def announce_last_conquered_city(owner, player_id, city, is_conquest, is_trade):
+ # Absinthe: Message for the human player, if the last city of a known civ is conquered
+ # all collapses operate with flips, so if the last city was conquered,
+ # we are good to go (this message won't come after a collapse message)
+ previous_owner = player(owner)
+ if (
+ not previous_owner.isHuman()
+ and previous_owner.getNumCities() == 0
+ and is_conquest
+ and player().canContact(owner)
+ ):
+ message(
+ human(),
+ previous_owner.getCivilizationDescription(0)
+ + " "
+ + text("TXT_KEY_STABILITY_CONQUEST_LAST_CITY"),
+ color=MessageData.RED,
+ )
+
+
+@handler("cityAcquiredAndKept")
+def announce_available_mercs_in_new_city(iCiv, pCity):
+ # Absinthe: if there are mercs available in the new city's province,
+ # interface message about it to the human player
+ iProvince = pCity.getProvince()
+ Mercenaries.getMercLists() # load the current mercenary pool
+ for lMerc in Mercenaries.lGlobalPool:
+ if lMerc[4] == iProvince:
+ if iCiv == human():
+ message(
+ iCiv,
+ text("TXT_KEY_MERC_AVAILABLE_NEAR_NEW_CITY", pCity.getName()),
+ button=ArtFileMgr.getInterfaceArtInfo("INTERFACE_MERCENARY_ICON").getPath(),
+ color=MessageData.LIME,
+ location=pCity,
+ )
+ break
+
+
+@handler("BeginGameTurn")
+def announce_schism(iGameTurn):
+ # Absinthe: Message for the human player about the Schism
+ if iGameTurn == year(1053):
+ if player().isExisting():
+ sText = text("TXT_KEY_GREAT_SCHISM")
+ message(human(), sText, color=MessageData.DARK_PINK)
+
+
+@handler("BeginPlayerTurn")
+def announce_invaders(iGameTurn, iPlayer):
+ if iPlayer == human():
+ # Seljuks
+ if iGameTurn == year(1064) - 7:
+ if iPlayer == Civ.BYZANTIUM:
+ show(("TXT_KEY_EVENT_BARBARIAN_INVASION_START"))
+ elif iGameTurn == year(1094) + 1:
+ if iPlayer == Civ.BYZANTIUM:
+ sText = "Seljuk"
+ show(text("TXT_KEY_EVENT_BARBARIAN_INVASION_END", sText))
+ # Mongols
+ elif iGameTurn == year(1236) - 7:
+ if iPlayer in [
+ Civ.KIEV,
+ Civ.HUNGARY,
+ Civ.POLAND,
+ Civ.BULGARIA,
+ ]:
+ show(text("TXT_KEY_EVENT_BARBARIAN_INVASION_START"))
+ elif iGameTurn == year(1288) + 1:
+ if iPlayer in [
+ Civ.KIEV,
+ Civ.HUNGARY,
+ Civ.POLAND,
+ Civ.BULGARIA,
+ ]:
+ sText = "Tatar"
+ show(text("TXT_KEY_EVENT_BARBARIAN_INVASION_END", sText))
+ # Timurids
+ elif iGameTurn == year(1380) - 7:
+ if iPlayer in [Civ.ARABIA, Civ.OTTOMAN, Civ.BYZANTIUM]:
+ show(text("TXT_KEY_EVENT_TIMURID_INVASION_START"))
+ elif iGameTurn == year(1431) + 1:
+ if iPlayer in [Civ.ARABIA, Civ.OTTOMAN, Civ.BYZANTIUM]:
+ sText = "Timurid"
+ show(text("TXT_KEY_EVENT_BARBARIAN_INVASION_END", sText))
diff --git a/Assets/Python/Modifiers.py b/Assets/Python/Modifiers.py
index c84a34795..77689b9a0 100644
--- a/Assets/Python/Modifiers.py
+++ b/Assets/Python/Modifiers.py
@@ -1,5 +1,5 @@
from CvPythonExtensions import *
-from Core import civilization, civilizations, year
+from Core import civilization, civilizations, log
from CoreTypes import (
Modifier,
Building,
@@ -25,7 +25,7 @@
GREAT_PROPHET_FAITH_POINT_BONUS,
PROSECUTOR_UNITCLASS,
)
-from TimelineData import TIMELINE_TECH_MODIFIER, DateTurn
+from TimelineData import DateTurn
from LocationsData import CITIES
gc = CyGlobalContext()
@@ -43,7 +43,7 @@ def setup():
set_religion_benefit()
set_historical_enemies()
set_other_parameters()
- set_tech_timeline_date()
+ log("RFCE: Modifiers.setup()")
def set_modifiers():
@@ -147,11 +147,6 @@ def set_tech_timeline_modifier():
# iCost *= 100 - topBuff * iHistoric * iAhistoric / BotBuff, iCost /= 100
-def set_tech_timeline_date():
- for tech, turn in TIMELINE_TECH_MODIFIER:
- gc.setTimelineTechDateForTech(tech, year(turn))
-
-
def set_initial_building():
# gc.setInitialBuilding( iCiv, iBuilding, True\False ), if ( True) give iCiv, building iBuildings else don't Default is False
# we can change True <-> False with the onTechAquire event
diff --git a/Assets/Python/Plague.py b/Assets/Python/Plague.py
new file mode 100644
index 000000000..a6ed8463a
--- /dev/null
+++ b/Assets/Python/Plague.py
@@ -0,0 +1,635 @@
+# Rhye's and Fall of Civilization: Europe - Plague
+
+from CvPythonExtensions import *
+from Consts import MessageData
+from Core import (
+ civilization,
+ civilizations,
+ message,
+ location,
+ owner,
+ text,
+ human,
+ player,
+ turn,
+ year,
+ city as _city,
+ plot as _plot,
+ cities,
+ plots,
+)
+from CoreTypes import PlagueType, Improvement, Civ
+from PyUtils import percentage, percentage_chance, rand
+from RFCUtils import calculateDistance, getPlagueCountdown, isMortalUnit, setPlagueCountdown
+from StoredData import data
+from MiscData import PLAGUE_IMMUNITY
+from Events import handler
+import random
+
+gc = CyGlobalContext()
+
+
+# Absinthe: Black Death is more severe, while the Plague of Justinian is less severe than the others plagues
+iBaseHumanDuration = 10
+iBaseAIDuration = 6
+iNumPlagues = 5
+iConstantinople = 0
+iBlackDeath = 1
+
+
+@handler("GameStart")
+def setup():
+ for i in civilizations().majors().ids():
+ setPlagueCountdown(i, -PLAGUE_IMMUNITY)
+
+ # Sedna17: Set number of GenericPlagues in StoredData
+ # 3Miro: Plague 0 strikes France too hard, make it less random and force it to pick Byzantium as starting land
+ setGenericPlagueDates(0, 28 + rand(5) - 10) # Plagues of Constantinople
+ setGenericPlagueDates(1, 247 + rand(40) - 20) # 1341 Black Death
+ setGenericPlagueDates(2, 300 + rand(40) - 20) # Generic recurrence of plague
+ setGenericPlagueDates(3, 375 + rand(40) - 30) # 1650 Great Plague
+ setGenericPlagueDates(4, 440 + rand(40) - 30) # 1740 Small Pox
+
+
+def setGenericPlagueDates(i, iNewValue):
+ data.lGenericPlagueDates[i] = iNewValue
+
+
+def getGenericPlagueDates(i):
+ return data.lGenericPlagueDates[i]
+
+
+def getBadPlague():
+ return data.bBadPlague
+
+
+def setBadPlague(bBad):
+ data.bBadPlague = bBad
+
+
+def getFirstPlague():
+ return data.bFirstPlague
+
+
+def setFirstPlague(bFirst):
+ data.bFirstPlague = bFirst
+
+
+@handler("BeginGameTurn")
+def checkTurn(iGameTurn):
+
+ for iPlayer in civilizations().ids():
+ if gc.getPlayer(iPlayer).isAlive():
+ if getPlagueCountdown(iPlayer) > 0:
+ setPlagueCountdown(iPlayer, getPlagueCountdown(iPlayer) - 1)
+ iPlagueCountDown = getPlagueCountdown(iPlayer)
+ if iPlagueCountDown == 2:
+ preStopPlague(iPlayer, iPlagueCountDown)
+ elif iPlagueCountDown == 1:
+ preStopPlague(iPlayer, iPlagueCountDown)
+ elif iPlagueCountDown == 0:
+ stopPlague(iPlayer)
+ elif getPlagueCountdown(iPlayer) < 0:
+ setPlagueCountdown(iPlayer, getPlagueCountdown(iPlayer) + 1)
+
+ for iPlague in range(iNumPlagues):
+ if iGameTurn == getGenericPlagueDates(iPlague):
+ startPlague(iPlague)
+
+ # if the plague has stopped too quickly, restart
+ if iGameTurn == getGenericPlagueDates(iPlague) + 4:
+ # not on the first one, that's mostly for one civ anyway
+ bFirstPlague = getFirstPlague()
+ if not bFirstPlague:
+ iInfectedCounter = 0
+ for iPlayer in civilizations().ids():
+ if gc.getPlayer(iPlayer).isAlive() and getPlagueCountdown(iPlayer) > 0:
+ iInfectedCounter += 1
+ if iInfectedCounter <= 1:
+ startPlague(iPlague)
+
+
+def startPlague(iPlagueCount):
+ iWorstCiv = -1
+ iWorstHealth = 100
+
+ # Absinthe: specific plagues
+ # Plague of Constantinople (that started at Alexandria)
+ if iPlagueCount == iConstantinople:
+ iWorstCiv = Civ.BYZANTIUM
+ setFirstPlague(True)
+ setBadPlague(False)
+ # Black Death in the 14th century
+ elif iPlagueCount == iBlackDeath:
+ setFirstPlague(False)
+ setBadPlague(True)
+ # all the others
+ else:
+ setFirstPlague(False)
+ setBadPlague(False)
+
+ # try to find the most unhealthy civ
+ if iWorstCiv == -1:
+ for iPlayer in civilizations().majors().ids():
+ pPlayer = gc.getPlayer(iPlayer)
+ if pPlayer.isAlive():
+ if isVulnerable(iPlayer):
+ iHealth = calcHealth(iPlayer) - rand(10)
+ if iHealth < iWorstHealth:
+ iWorstCiv = iPlayer
+ iWorstHealth = iHealth
+
+ # choose a random civ if we didn't find it
+ if iWorstCiv == -1:
+ iWorstCiv = civilizations().majors().alive().random().unwrap().id
+
+ city = cities.owner(iWorstCiv).random_entry()
+ if city is not None:
+ spreadPlague(iWorstCiv, city)
+ infectCity(city)
+
+
+def calcHealth(iPlayer):
+ pPlayer = gc.getPlayer(iPlayer)
+ iTCH = pPlayer.calculateTotalCityHealthiness()
+ iTCU = pPlayer.calculateTotalCityUnhealthiness()
+ # Absinthe: use average city health instead
+ iNumCities = pPlayer.getNumCities()
+ if iNumCities == 0:
+ return 0 # Avoid zero division error
+ iAverageCityHealth = int((10 * (iTCH - iTCU)) / iNumCities) # 10x the average health actually
+ return iAverageCityHealth
+
+
+def isVulnerable(iPlayer):
+ # Absinthe: based on recent infections and the average city healthiness (also tech immunity should go here if it's ever added to the mod)
+ if iPlayer >= civilizations().majors().len():
+ if getPlagueCountdown(iPlayer) == 0:
+ return True
+ else:
+ if getPlagueCountdown(iPlayer) == 0:
+ # Absinthe: health doesn't matter for the Black Death, everyone is vulnerable
+ if getBadPlague():
+ return True
+ else:
+ iHealth = calcHealth(iPlayer)
+ if (
+ iHealth < 42
+ ): # won't spread at all if the average surplus health in the cities is at least 4.2
+ return True
+ return False
+
+
+def spreadPlague(iPlayer, city):
+ # Absinthe: the Plague of Justinian shouldn't spread to Italy and France, even if it was as deadly as the Black Death
+ if iPlayer in [Civ.FRANCE, Civ.POPE] and turn() <= year(632):
+ return
+
+ # Absinthe: message about the spread
+ iHuman = human()
+ iHumanTeam = gc.getPlayer(iHuman).getTeam()
+ if gc.getPlayer(iHuman).canContact(iPlayer) and iHuman != iPlayer:
+ if city != -1 and city.isRevealed(iHumanTeam, False):
+ message(
+ iHuman,
+ text("TXT_KEY_PLAGUE_SPREAD_CITY")
+ + " "
+ + city.getName()
+ + " ("
+ + gc.getPlayer(city.getOwner()).getCivilizationAdjective(0)
+ + ")!",
+ force=True,
+ sound="AS2D_PLAGUE",
+ button=gc.getBuildingInfo(PlagueType.PLAGUE).getButton(),
+ color=MessageData.LIME,
+ location=city,
+ )
+ elif city != -1:
+ pCiv = gc.getPlayer(city.getOwner())
+ message(
+ iHuman,
+ text("TXT_KEY_PLAGUE_SPREAD_CIV") + " " + pCiv.getCivilizationDescription(0) + "!",
+ force=True,
+ sound="AS2D_PLAGUE",
+ color=MessageData.LIME,
+ )
+
+ # Absinthe: this is where the duration is handled for each civ
+ # number of cities should be a significant factor, so plague isn't way more deadly for smaller civs
+ iHealth = calcHealth(iPlayer)
+ iHealthDuration = max(min((iHealth / 14), 3), -4) # between -4 and +3
+ iCityDuration = min(
+ (gc.getPlayer(iPlayer).getNumCities() + 2) / 3, 10
+ ) # between 1 and 10 from cities
+ if iPlayer == iHuman:
+ # Overall duration for the plague is between 4 and 12 (usually between 6-8)
+ iValue = (iBaseHumanDuration + iCityDuration - iHealthDuration) / 2
+ else:
+ # Overall duration for the plague is between 2 and 10 (usually around 5-6)
+ iValue = max(((iBaseAIDuration + iCityDuration - iHealthDuration) / 2), 4) # at least 4
+ setPlagueCountdown(iPlayer, iValue)
+
+
+def infectCity(city):
+ # Absinthe: the Plague of Justinian shouldn't spread to Italy and France, even if it was as deadly as the Black Death
+ if city.getOwner() in [Civ.FRANCE, Civ.POPE] and turn() <= year(632):
+ return
+
+ city.setHasRealBuilding(PlagueType.PLAGUE, True)
+ if player(city).isHuman():
+ message(
+ city.getOwner(),
+ text("TXT_KEY_PLAGUE_SPREAD_CITY") + " " + city.getName() + "!",
+ force=True,
+ sound="AS2D_PLAGUE",
+ button=gc.getBuildingInfo(PlagueType.PLAGUE).getButton(),
+ color=MessageData.LIME,
+ location=location(city),
+ )
+
+ for plot in plots.surrounding(city, radius=2).entities():
+ iImprovement = plot.getImprovementType()
+ # Absinthe: chance for reducing the improvement vs. only resetting the process towards the next level to 0
+ if iImprovement == Improvement.TOWN: # 100% chance to reduce towns
+ plot.setImprovementType(Improvement.VILLAGE)
+ elif iImprovement == Improvement.VILLAGE:
+ if percentage_chance(75, strict=True):
+ plot.setImprovementType(Improvement.HAMLET)
+ else:
+ plot.setUpgradeProgress(0)
+ elif iImprovement == Improvement.HAMLET:
+ if percentage_chance(50, strict=True):
+ plot.setImprovementType(Improvement.COTTAGE)
+ else:
+ plot.setUpgradeProgress(0)
+ elif iImprovement == Improvement.COTTAGE:
+ if percentage_chance(25, strict=True):
+ plot.setImprovementType(-1)
+ else:
+ plot.setUpgradeProgress(0)
+
+ # Absinthe: one population is killed by default
+ if city.getPopulation() > 1:
+ city.changePopulation(-1)
+
+ # Absinthe: plagues won't kill units instantly on spread anymore
+ # Plague of Justinian deals even less initial damage
+ bFirstPlague = getFirstPlague()
+ if bFirstPlague:
+ killUnitsByPlague(city, _plot(city), 0, 80, 0)
+ else:
+ killUnitsByPlague(city, _plot(city), 0, 90, 0)
+
+
+def killUnitsByPlague(city, plot, iThreshold, iDamage, iPreserveDefenders):
+ iCityOwner = city.getOwner()
+ pCityOwner = gc.getPlayer(iCityOwner)
+ teamCityOwner = gc.getTeam(pCityOwner.getTeam())
+
+ iNumUnitsInAPlot = plot.getNumUnits()
+ iHuman = human()
+ iCityHealthRate = city.healthRate(False, 0)
+
+ if iNumUnitsInAPlot > 0:
+ # Absinthe: if we mix up the order of the units, health will be much less static for the chosen defender units
+ bOrderChange = percentage_chance(25)
+ for j in range(iNumUnitsInAPlot):
+ if bOrderChange:
+ i = j # we are counting from the strongest unit
+ else:
+ i = iNumUnitsInAPlot - j - 1 # count back from the weakest unit
+ unit = plot.getUnit(i)
+ if isMortalUnit(unit) and percentage_chance(
+ iThreshold + 5 * iCityHealthRate, strict=True, reverse=True
+ ):
+ iUnitDamage = unit.getDamage()
+ # if some defenders are set to be preserved for some reason, they won't get more damage if they are already under 50%
+ if (
+ unit.getOwner() == iCityOwner
+ and iPreserveDefenders > 0
+ and unit.getDomainType() != 0
+ and unit.baseCombatStr() > 0
+ ): # only units which can really defend
+ iPreserveDefenders -= 1
+ unit.setDamage(
+ max(
+ iUnitDamage,
+ min(
+ 50,
+ iUnitDamage
+ + iDamage
+ - unit.getExperience() / 10
+ - 3 * unit.baseCombatStr() / 7,
+ ),
+ ),
+ Civ.BARBARIAN,
+ )
+ else:
+ if unit.baseCombatStr() > 0:
+ if (
+ unit.getDomainType() == DomainTypes.DOMAIN_SEA
+ ): # naval units get less damage, won't be killed unless they were very badly damaged originally
+ iShipDamage = iDamage * 93 / 100
+ iUnitDamage = max(
+ iUnitDamage,
+ unit.getDamage()
+ + iShipDamage
+ - unit.getExperience() / 10
+ - 3 * unit.baseCombatStr() / 7,
+ )
+ else:
+ iUnitDamage = max(
+ iUnitDamage,
+ unit.getDamage()
+ + iDamage
+ - unit.getExperience() / 10
+ - 3 * unit.baseCombatStr() / 7,
+ )
+ else: # less damage for civilian units - workers, settlers, missionaries, etc.
+ iCivilDamage = (
+ iDamage * 96 / 100
+ ) # workers will be killed with any value here if they are automated (thus moving instead of healing)
+ iUnitDamage = max(iUnitDamage, unit.getDamage() + iCivilDamage)
+ # kill the unit if necessary
+ if iUnitDamage >= 100:
+ unit.kill(False, Civ.BARBARIAN)
+ if unit.getOwner() == iHuman:
+ message(
+ iHuman,
+ text("TXT_KEY_PLAGUE_PROCESS_UNIT", unit.getName())
+ + " "
+ + city.getName()
+ + "!",
+ force=False,
+ sound="AS2D_PLAGUE",
+ button=gc.getBuildingInfo(PlagueType.PLAGUE).getButton(),
+ color=MessageData.LIME,
+ location=plot,
+ )
+ else:
+ unit.setDamage(iUnitDamage, Civ.BARBARIAN)
+ # if we have many units in the same plot, decrease the damage for every other unit
+ iDamage *= 7
+ iDamage /= 8
+
+
+@handler("BeginPlayerTurn")
+def processPlague(iPlayer):
+ if iPlayer < civilizations().len():
+ if getPlagueCountdown(iPlayer) > 0:
+ bBadPlague = getBadPlague()
+ bFirstPlague = getFirstPlague()
+ pPlayer = gc.getPlayer(iPlayer)
+ iHuman = human()
+
+ lInfectedCities = cities.owner(iPlayer).building(PlagueType.PLAGUE).entities()
+ lNotInfectedCities = cities.owner(iPlayer).not_building(PlagueType.PLAGUE).entities()
+
+ # first spread to close locations
+ for city in lInfectedCities:
+ # kill citizens
+ if city.getPopulation() > 1:
+ # the plague it also greatly contributes to unhealth, so the health rate will almost always be negative
+ iHealthRate = city.goodHealth() - city.badHealth(False)
+ # always between -5 and +5
+ iHealthRate = max(-5, min(5, iHealthRate))
+
+ iRandom = percentage()
+ iPopSize = city.getPopulation()
+ if bBadPlague: # if it's the Black Death, bigger chance for population loss
+ bKill = iRandom < 10 + 10 * (iPopSize - 4) - 5 * iHealthRate
+ elif (
+ bFirstPlague
+ ): # if it's the Plague of Justinian, smaller chance for population loss
+ bKill = iRandom < 10 * (iPopSize - 4) - 5 * iHealthRate
+ else:
+ # in "normal" plagues the range for a given pop size is from 10*(size-6) to 10*(size-1)
+ # so with size 2: from -40 to 10, size 5: -10 to 40, size 8: 20 to 70, size 12: 60 to 110, size 15: 90 to 140
+ bKill = iRandom < 5 + 10 * (iPopSize - 4) - 5 * iHealthRate
+ if bKill:
+ city.changePopulation(-1)
+ if iPlayer == iHuman:
+ message(
+ iHuman,
+ text("TXT_KEY_PLAGUE_PROCESS_CITY", city.getName())
+ + " "
+ + city.getName()
+ + "!",
+ force=False,
+ sound="AS2D_PLAGUE",
+ button=gc.getBuildingInfo(PlagueType.PLAGUE).getButton(),
+ color=MessageData.LIME,
+ location=city,
+ )
+
+ # infect vassals
+ if getPlagueCountdown(iPlayer) > 2: # don't spread in the last turns
+ if city.isCapital():
+ for iLoopCiv in civilizations().majors().ids():
+ if gc.getTeam(pPlayer.getTeam()).isVassal(iLoopCiv) or gc.getTeam(
+ gc.getPlayer(iLoopCiv).getTeam()
+ ).isVassal(iPlayer):
+ if (
+ gc.getPlayer(iLoopCiv).getNumCities() > 0
+ ): # this check is needed, otherwise game crashes
+ if isVulnerable(iLoopCiv):
+ capital = gc.getPlayer(iLoopCiv).getCapitalCity()
+ spreadPlague(iLoopCiv, capital)
+ infectCity(capital)
+
+ # spread plague in 2 distance around the city
+ if getPlagueCountdown(iPlayer) > 2: # don't spread in the last turns
+ for plot in (
+ plots.surrounding(city, radius=2)
+ .filter(lambda p: p.isOwned())
+ .without(city)
+ .entities()
+ ):
+ if (
+ owner(plot, iPlayer)
+ and plot.isCity()
+ and not _city(plot).isHasRealBuilding(PlagueType.PLAGUE)
+ ):
+ infectCity(_city(plot))
+ else:
+ if isVulnerable(plot.getOwner()):
+ spreadPlague(plot.getOwner(), -1)
+ infectCitiesNear(plot.getOwner(), *location(plot))
+ # kill units around the city
+ for plot in plots.surrounding(city, radius=3).entities():
+ iDistance = calculateDistance(city.getX(), city.getY(), *location(plot))
+ if iDistance == 0: # City
+ killUnitsByPlague(city, plot, 20, 40, 2)
+ elif not plot.isCity():
+ if iDistance == 1:
+ if plot.isRoute():
+ killUnitsByPlague(city, plot, 20, 30, 0)
+ else:
+ killUnitsByPlague(city, plot, 30, 30, 0)
+ elif iDistance == 2:
+ if plot.isRoute():
+ killUnitsByPlague(city, plot, 30, 30, 0)
+ else:
+ killUnitsByPlague(city, plot, 40, 30, 0)
+ else:
+ if plot.getOwner() == iPlayer or not plot.isOwned():
+ if plot.isRoute() or plot.isWater():
+ killUnitsByPlague(city, plot, 40, 30, 0)
+
+ # spread by the trade routes
+ if getPlagueCountdown(iPlayer) > 2: # don't spread in the last turns
+ for iTradeRoute in range(city.getTradeRoutes()):
+ loopCity = city.getTradeCity(iTradeRoute)
+ if not loopCity.isNone():
+ if not loopCity.isHasRealBuilding(PlagueType.PLAGUE):
+ iOwner = loopCity.getOwner()
+ if iOwner == iPlayer:
+ infectCity(loopCity)
+ if isVulnerable(iOwner):
+ spreadPlague(iOwner, loopCity)
+ infectCity(loopCity)
+
+ # Absinthe: spread to a couple cities which are not too far from already infected ones
+ # cities are chosen randomly from the possible targets
+ # the maximum number of infections is based on the size of the empire
+ if (
+ getPlagueCountdown(iPlayer) > 2
+ ): # don't spread in the last turns, when preStopPlague is active
+ if lNotInfectedCities:
+ iTotalCities = pPlayer.getNumCities()
+ if iTotalCities > 21:
+ iMaxNumInfections = 4
+ elif iTotalCities > 14:
+ iMaxNumInfections = 3
+ elif iTotalCities > 7:
+ iMaxNumInfections = 2
+ else:
+ iMaxNumInfections = 1
+
+ # plagues are rather short, always spread at least once
+ iNumSpreads = min(1, len(lNotInfectedCities), rand(iMaxNumInfections))
+
+ iInfections = 0
+ random.shuffle(lNotInfectedCities)
+ for targetCity in lNotInfectedCities:
+ if [
+ city
+ for city in lInfectedCities
+ if targetCity.isConnectedTo(city)
+ and calculateDistance(
+ targetCity.getX(), targetCity.getY(), city.getX(), city.getY()
+ )
+ <= 10
+ ]:
+ if not targetCity.isHasRealBuilding(PlagueType.PLAGUE):
+ # might have changed since the beginning of the function
+ infectCity(targetCity)
+ iInfections += 1
+ if iInfections >= iNumSpreads:
+ break
+
+ # if there are no cities with plague (gifted away, razed on conquest), but the civ it has plague
+ # there is a chance that it will spread to some of your cities
+ # the civ would be immune otherwise, basically
+ if len(lInfectedCities) == 0:
+ if (
+ getPlagueCountdown(iPlayer) > 2
+ ): # don't spread in the last turns, when preStopPlague is active
+ iTotalCities = pPlayer.getNumCities()
+ if iTotalCities > 21:
+ iMaxNumInfections = 4
+ elif iTotalCities > 14:
+ iMaxNumInfections = 3
+ elif iTotalCities > 7:
+ iMaxNumInfections = 2
+ else:
+ iMaxNumInfections = 1
+ iInfections = 0
+ _cities = cities.owner(iPlayer).not_building(PlagueType.PLAGUE).entities()
+ # TODO fix shuffle
+ random.shuffle(_cities)
+ for city in _cities:
+ if percentage_chance(20, strict=True):
+ infectCity(city)
+ iInfections += 1
+ if iInfections >= iMaxNumInfections:
+ break
+
+
+def infectCitiesNear(iPlayer, startingX, startingY):
+ for city in cities.owner(iPlayer).not_building(PlagueType.PLAGUE).entities():
+ if calculateDistance(city.getX(), city.getY(), startingX, startingY) <= 3:
+ infectCity(city)
+
+
+def preStopPlague(iPlayer, iPlagueCountDown):
+ cityList = cities.owner(iPlayer).building(PlagueType.PLAGUE).entities()
+ if cityList:
+ iRemoveModifier = 0
+ iTimeModifier = iPlagueCountDown * 15
+ iPopModifier = 0
+ iHealthModifier = 0
+ # small cities should have a good chance to be chosen
+ for city in cityList:
+ # iPopModifier: -28, -21, -14, -7, 0, 7, 14, 21, 28, 35, etc.
+ iPopModifier = 7 * city.getPopulation() - 35
+ iHealthModifier = 5 * city.healthRate(False, 0)
+ if percentage_chance(
+ 100 - iTimeModifier - iPopModifier + iHealthModifier - iRemoveModifier,
+ strict=True,
+ ):
+ city.setHasRealBuilding(PlagueType.PLAGUE, False)
+ iRemoveModifier += 5 # less chance for each city which already quit
+
+
+def stopPlague(iPlayer):
+ setPlagueCountdown(iPlayer, -PLAGUE_IMMUNITY)
+ for city in cities.owner(iPlayer).entities():
+ city.setHasRealBuilding(PlagueType.PLAGUE, False)
+
+
+@handler("cityAcquired")
+def onCityAcquired(iOldOwner, iNewOwner, city):
+ if city.isHasRealBuilding(PlagueType.PLAGUE):
+ # TODO when plague will not kill units anymore, remove this
+ # Absinthe: the Plague of Justinian shouldn't spread to Italy and France, even if it was as deadly as the Black Death
+ if city.getOwner() in [Civ.FRANCE, Civ.POPE] and turn() <= year(632):
+ city.setHasRealBuilding(PlagueType.PLAGUE, False)
+ return
+
+ # only if it's not a recently born civ
+ if turn() > civilization(iNewOwner).date.birth + PLAGUE_IMMUNITY:
+ # reinfect the human player if conquering plagued cities
+ if iNewOwner == human():
+ # if > 0 do nothing, if < 0 skip immunity and restart the plague, if == 0 start the plague
+ if getPlagueCountdown(iNewOwner) <= 0:
+ spreadPlague(iNewOwner, -1)
+ for cityNear in cities.owner(iNewOwner).entities():
+ if not cityNear.isHasRealBuilding(PlagueType.PLAGUE):
+ if (
+ calculateDistance(
+ city.getX(), city.getY(), cityNear.getX(), cityNear.getY()
+ )
+ <= 3
+ ):
+ if percentage_chance(50, strict=True):
+ infectCity(cityNear)
+ # no reinfect for the AI, only infect
+ else:
+ # if > 0 do nothing, if < 0 keep immunity and remove plague from the city, if == 0 start the plague
+ if getPlagueCountdown(iNewOwner) == 0:
+ spreadPlague(iNewOwner, -1)
+ for cityNear in cities.owner(iNewOwner).entities():
+ if not cityNear.isHasRealBuilding(PlagueType.PLAGUE):
+ if (
+ calculateDistance(
+ city.getX(), city.getY(), cityNear.getX(), cityNear.getY()
+ )
+ <= 3
+ ):
+ if percentage_chance(50, strict=True):
+ infectCity(cityNear)
+ elif getPlagueCountdown(iNewOwner) < 0:
+ city.setHasRealBuilding(PlagueType.PLAGUE, False)
+ else:
+ city.setHasRealBuilding(PlagueType.PLAGUE, False)
diff --git a/Assets/Python/Provinces.py b/Assets/Python/Provinces.py
new file mode 100644
index 000000000..d5a728cdd
--- /dev/null
+++ b/Assets/Python/Provinces.py
@@ -0,0 +1,95 @@
+from Core import get_scenario, civilization, civilizations, player, year, cities
+from RFCUtils import refreshStabilityOverlay
+from ProvinceMapData import PROVINCES_MAP
+from CoreTypes import Province, Event, Scenario, ProvinceType
+from Events import handler
+
+
+@handler("GameStart")
+def setup():
+ # set the initial situation for all players
+ for civ in civilizations().main():
+ for type, provinces in civ.location.provinces.items():
+ for province in provinces:
+ civ.player.setProvinceType(province, type)
+ # update provinces for the 1200 AD Scenario
+ if get_scenario() == Scenario.i1200AD:
+ for civ in civilizations().main():
+ if civ.date.birth < year(1200):
+ onSpawn(civ.id)
+
+
+def onSpawn(iPlayer):
+ # when a new nations spawns, old nations in the region should lose some of their provinces
+ events = civilization(iPlayer).event.provinces.get(Event.ON_SPAWN)
+ if events is not None:
+ for civ, province, province_type in events:
+ player(civ).setProvinceType(province, province_type)
+
+ refreshStabilityOverlay()
+
+
+@handler("BeginGameTurn")
+def checkTurn(iGameTurn):
+ for civ in civilizations():
+ events = civ.event.provinces.get(Event.ON_DATETURN)
+ if events is not None:
+ for dateturn, provinces in events.items():
+ if iGameTurn == year(dateturn):
+ for province, province_type in provinces:
+ civ.player.setProvinceType(province, province_type)
+
+
+def onCityBuilt(iPlayer, x, y):
+ if iPlayer not in civilizations().main().ids():
+ return
+ civ = civilization(iPlayer)
+ province = PROVINCES_MAP[y][x]
+ if civ.player.getProvinceType(province) == ProvinceType.POTENTIAL:
+ civ.player.setProvinceType(province, ProvinceType.HISTORICAL)
+ refreshStabilityOverlay()
+
+
+@handler("cityAcquired")
+def onCityAcquired(owner, iPlayer, city, bConquest, bTrade):
+ if iPlayer not in civilizations().main().ids():
+ return
+ civ = civilization(iPlayer)
+ province = city.getProvince()
+ if civ.player.getProvinceType(province) == ProvinceType.POTENTIAL:
+ civ.player.setProvinceType(province, ProvinceType.HISTORICAL)
+ refreshStabilityOverlay()
+
+
+def updatePotential(iPlayer):
+ civ = civilization(iPlayer)
+ for city in cities.owner(iPlayer).entities():
+ province = city.getProvince()
+ if civ.player.getProvinceType(province) == ProvinceType.POTENTIAL:
+ civ.player.setProvinceType(province, ProvinceType.HISTORICAL)
+ refreshStabilityOverlay()
+
+
+def onRespawn(iPlayer):
+ # Absinthe: reset the original potential provinces, but only if they wasn't changed to something entirely different later on
+ civ = civilization(iPlayer)
+ for province in civ.location.provinces[ProvinceType.HISTORICAL]:
+ if civ.player.getProvinceType(province) == ProvinceType.HISTORICAL:
+ civ.player.setProvinceType(province, ProvinceType.POTENTIAL)
+
+ # Absinthe: special respawn conditions
+ events = civ.event.provinces.get(Event.ON_RESPAWN)
+ if events is not None:
+ for province, province_type in events:
+ civ.player.setProvinceType(province, province_type)
+
+
+def resetProvinces(iPlayer):
+ # Absinthe: keep in mind that this will reset all to the initial status, so won't take later province changes into account
+ civ = civilization(iPlayer)
+ for province in Province:
+ civ.player.setProvinceType(province, ProvinceType.NONE)
+
+ for type, provinces in civ.location.provinces.items():
+ for province in provinces:
+ civ.player.setProvinceType(province, type)
diff --git a/Assets/Python/RFCUtils.py b/Assets/Python/RFCUtils.py
index 4be71e47d..b1c0214f8 100644
--- a/Assets/Python/RFCUtils.py
+++ b/Assets/Python/RFCUtils.py
@@ -2,6 +2,7 @@
from CvPythonExtensions import *
from Core import (
+ event_popup,
get_scenario,
city,
civilization,
@@ -44,7 +45,6 @@
import CvUtil
import CvScreenEnums
from LocationsData import CITIES
-import Popup
from PyUtils import percentage, percentage_chance, rand
from ReligionData import RELIGION_PERSECUTION_ORDER
from SettlerMapData import SETTLERS_MAP
@@ -145,7 +145,7 @@ def isMortalUnit(unit):
# AIWars
def checkUnitsInEnemyTerritory(iCiv1, iCiv2):
- unitList = units().owner(iCiv1).entities()
+ unitList = units.owner(iCiv1).entities()
if unitList:
for unit in unitList:
iX = unit.getX()
@@ -200,7 +200,7 @@ def restorePeaceHuman(iMinorCiv):
# AIWars
def minorWars(iMinorCiv, iGameTurn):
teamMinor = gc.getTeam(gc.getPlayer(iMinorCiv).getTeam())
- for city in cities().owner(iMinorCiv).entities():
+ for city in cities.owner(iMinorCiv).entities():
x = city.getX()
y = city.getY()
for iActiveCiv in civilizations().majors().ids():
@@ -229,7 +229,7 @@ def minorWars(iMinorCiv, iGameTurn):
# Absinthe: declare war sooner / more frequently if an Indy city has huge value on the civ's war map
def minorCoreWars(iMinorCiv, iGameTurn):
teamMinor = gc.getTeam(gc.getPlayer(iMinorCiv).getTeam())
- for city in cities().owner(iMinorCiv).entities():
+ for city in cities.owner(iMinorCiv).entities():
x = city.getX()
y = city.getY()
for iActiveCiv in civilizations().majors().ids():
@@ -383,7 +383,7 @@ def flipUnitsInCityAfter(tCityPlot, iCiv):
def killAllUnitsInArea(tTopLeft, tBottomRight):
- for plot in plots().rectangle(tTopLeft, tBottomRight).entities():
+ for plot in plots.rectangle(tTopLeft, tBottomRight).entities():
iNumUnitsInAPlot = plot.getNumUnits()
if iNumUnitsInAPlot > 0:
for i in range(iNumUnitsInAPlot):
@@ -419,7 +419,7 @@ def flipUnitsInArea(tTopLeft, tBottomRight, iNewOwner, iOldOwner, bSkipPlotCity,
for i in range(iNumUnitsInAPlot):
unit = killPlot.getUnit(0)
unit.kill(False, Civ.BARBARIAN)
- for plot in plots().rectangle(tTopLeft, tBottomRight).entities():
+ for plot in plots.rectangle(tTopLeft, tBottomRight).entities():
iNumUnitsInAPlot = plot.getNumUnits()
if iNumUnitsInAPlot > 0:
bRevealedZero = False
@@ -528,7 +528,7 @@ def flipCity(tCityPlot, bConquest, bKillUnits, iNewOwner, lOldOwners):
if not lOldOwners or iOldOwner in lOldOwners:
if bKillUnits:
- for unit in units().at(x, y).filter(lambda unit: not unit.isCargo()).entities():
+ for unit in units.at(x, y).filter(lambda unit: not unit.isCargo()).entities():
unit.kill(False, iNewOwner)
pNewOwner.acquireCity(flipCity, bConquest, not bConquest)
@@ -599,7 +599,7 @@ def cultureManager(
# halve barbarian culture in a broader area
if bBarbarian2x2Decay or bBarbarian2x2Conversion:
if iNewOwner not in MINOR_CIVS:
- for plot in plots().surrounding(tCityPlot, radius=2).entities():
+ for plot in plots.surrounding(tCityPlot, radius=2).entities():
for iMinor in MINOR_CIVS:
iPlotMinorCulture = plot.getCulture(iMinor)
if iPlotMinorCulture > 0:
@@ -612,7 +612,7 @@ def cultureManager(
plot.changeCulture(iNewOwner, iPlotMinorCulture, True)
# plot
- for plot in plots().surrounding(tCityPlot).entities():
+ for plot in plots.surrounding(tCityPlot).entities():
iCurrentPlotCulture = plot.getCulture(iOldOwner)
if plot.isCity():
@@ -641,7 +641,7 @@ def cultureManager(
# RFCEventHandler
def spreadMajorCulture(iMajorCiv, iX, iY):
# Absinthe: spread some of the major civ's culture to the nearby indy cities
- for city in plots().surrounding((iX, iY), radius=4).cities().entities():
+ for city in plots.surrounding((iX, iY), radius=4).cities().entities():
previous_owner = city.getPreviousOwner()
if previous_owner in MINOR_CIVS:
iDen = 25
@@ -685,7 +685,7 @@ def convertPlotCulture(pCurrent, iCiv, iPercent, bOwner):
def pushOutGarrisons(tCityPlot, iOldOwner):
tDestination = (-1, -1)
for plot in (
- plots().surrounding(tCityPlot, radius=2).passable().land().owner(iOldOwner).entities()
+ plots.surrounding(tCityPlot, radius=2).passable().land().owner(iOldOwner).entities()
):
tDestination = location(plot)
break
@@ -704,12 +704,12 @@ def pushOutGarrisons(tCityPlot, iOldOwner):
# RiseAndFall
def relocateSeaGarrisons(tCityPlot, iOldOwner):
tDestination = (-1, -1)
- for city in cities().owner(iOldOwner).entities():
+ for city in cities.owner(iOldOwner).entities():
if city.isCoastalOld():
tDestination = (city.getX(), city.getY())
break
if tDestination == (-1, -1):
- for plot in plots().surrounding(tCityPlot, radius=12).water().entities():
+ for plot in plots.surrounding(tCityPlot, radius=12).water().entities():
tDestination = location(plot)
break
if tDestination != (-1, -1):
@@ -750,7 +750,7 @@ def killAndFragmentCiv(iCiv, bBarbs, bAssignOneCity):
clearPlague(iCiv)
iNumLoyalCities = 0
iCounter = rand(6)
- for city in cities().owner(iCiv).entities():
+ for city in cities.owner(iCiv).entities():
tCoords = (city.getX(), city.getY())
iX, iY = tCoords
pCurrent = gc.getMap().plot(iX, iY)
@@ -831,7 +831,7 @@ def killAndFragmentCiv(iCiv, bBarbs, bAssignOneCity):
flipUnitsInArea((iX - 1, iY - 1), (iX + 1, iY + 1), iNewCiv, iCiv, False, True)
if not bAssignOneCity:
# flipping units may cause a bug: if a unit is inside another civ's city when it becomes independent or barbarian, may raze it
- for unit in units().owner(iCiv).entities():
+ for unit in units.owner(iCiv).entities():
unit.kill(False, Civ.BARBARIAN)
resetUHV(iCiv)
@@ -852,7 +852,7 @@ def resetUHV(iPlayer):
def clearPlague(iCiv):
- for city in cities().owner(iCiv).building(PlagueType.PLAGUE).entities():
+ for city in cities.owner(iCiv).building(PlagueType.PLAGUE).entities():
city.setHasRealBuilding(PlagueType.PLAGUE, False)
@@ -876,7 +876,7 @@ def getMaster(iCiv):
def squareSearch(tTopLeft, tBottomRight, function, argsList): # by LOQ
"""Searches all tiles in the square from tTopLeft to tBottomRight and calls function for every tile, passing argsList."""
tPaintedList = []
- for plot in plots().rectangle(tTopLeft, tBottomRight).entities():
+ for plot in plots.rectangle(tTopLeft, tBottomRight).entities():
bPaintPlot = function(location(plot), argsList)
if bPaintPlot:
tPaintedList.append(location(plot))
@@ -910,7 +910,7 @@ def outerSeaSpawn(tCoords, argsList):
if pCurrent.isWater() and pCurrent.getTerrainType() == Terrain.COAST:
if not pCurrent.isUnit():
if pCurrent.countTotalCulture() == 0:
- for plot in plots().surrounding(tCoords).entities():
+ for plot in plots.surrounding(tCoords).entities():
if plot.isUnit():
return False
return True
@@ -922,7 +922,7 @@ def innerSeaSpawn(tCoords, argsList):
pCurrent = gc.getMap().plot(tCoords[0], tCoords[1])
if pCurrent.isWater() and pCurrent.getTerrainType() == Terrain.COAST:
if not pCurrent.isUnit():
- for plot in plots().surrounding(tCoords).entities():
+ for plot in plots.surrounding(tCoords).entities():
if plot.isUnit():
return False
return True
@@ -936,7 +936,7 @@ def outerSpawn(tCoords, argsList):
if pCurrent.getFeatureType() not in [Feature.MARSH, Feature.JUNGLE]:
if not pCurrent.isCity() and not pCurrent.isUnit():
if pCurrent.countTotalCulture() == 0:
- for plot in plots().surrounding(tCoords).entities():
+ for plot in plots.surrounding(tCoords).entities():
if plot.isUnit():
return False
return True
@@ -950,7 +950,7 @@ def innerSpawn(tCoords, argsList):
if pCurrent.getFeatureType() not in [Feature.MARSH, Feature.JUNGLE]:
if not pCurrent.isCity() and not pCurrent.isUnit():
if pCurrent.getOwner() in argsList:
- for plot in plots().surrounding(tCoords).entities():
+ for plot in plots.surrounding(tCoords).entities():
if plot.isUnit():
return False
return True
@@ -995,19 +995,17 @@ def collapseImmune(iCiv):
return False
-# Absinthe: chooseable persecution popup
def showPersecutionPopup():
"""Asks the human player to select a religion to persecute."""
-
- popup = Popup.PyPopup(7628, EventContextTypes.EVENTCONTEXT_ALL)
- popup.setHeaderString("Religious Persecution")
- popup.setBodyString("Choose a religious minority to deal with...")
+ labels = []
for iReligion in data.lPersecutionReligions:
strIcon = gc.getReligionInfo(iReligion).getType()
strIcon = "[%s]" % (strIcon.replace("RELIGION_", "ICON_"))
strButtonText = "%s %s" % (text(strIcon), gc.getReligionInfo(iReligion).getText())
- popup.addButton(strButtonText)
- popup.launch(False)
+ labels.append(strButtonText)
+ event_popup(
+ 7628, "Religious Persecution", "Choose a religious minority to deal with...", labels
+ )
# Absinthe: persecution
@@ -1134,7 +1132,7 @@ def prosecute(iPlotX, iPlotY, iUnitID, iReligion=-1):
# Jews may spread to another random city
if iReligion == Religion.JUDAISM:
if percentage_chance(80, strict=True):
- pSpreadCity = cities().majors().random_entry()
+ pSpreadCity = cities.majors().random_entry()
spreadJews(location(pSpreadCity), Religion.JUDAISM)
if pSpreadCity.getOwner() == iOwner:
message(
@@ -1442,7 +1440,7 @@ def StabilityOverlayCiv(iChoice):
iMaxTextWidth = iTextWidth
# apply the highlight
- for plot in plots().all().land().entities():
+ for plot in plots.all().land().entities():
if gc.getGame().isDebugMode() or plot.isRevealed(iHumanTeam, False):
if PROVINCES_MAP[plot.getY()][plot.getX()] == -1: # ocean and non-province tiles
szColor = "COLOR_GREY"
@@ -1524,7 +1522,7 @@ def getMostAdvancedCiv():
def getNumberCargoShips(iPlayer):
- return units().owner(iPlayer).filter(lambda u: u.cargoSpace() > 0).len()
+ return units.owner(iPlayer).filter(lambda u: u.cargoSpace() > 0).len()
def isWonder(iBuilding):
diff --git a/Assets/Python/Religions.py b/Assets/Python/Religions.py
new file mode 100644
index 000000000..65755dd7e
--- /dev/null
+++ b/Assets/Python/Religions.py
@@ -0,0 +1,1247 @@
+import Popup
+import UniquePowers
+from Consts import MessageData
+from Core import (
+ cities,
+ civilization,
+ civilizations,
+ event_popup,
+ human,
+ location,
+ message,
+ player,
+ text,
+ turn,
+ units,
+ year,
+)
+from CoreTypes import (
+ Building,
+ City,
+ Civ,
+ Civic,
+ Province,
+ Religion,
+ StabilityCategory,
+ Technology,
+ UniquePower,
+ Unit,
+ Wonder,
+)
+from CvPythonExtensions import (
+ CyGlobalContext,
+ DirectionTypes,
+ EventContextTypes,
+ InterfaceMessageTypes,
+ UnitAITypes,
+)
+from Events import handler, popup_handler
+from LocationsData import CITIES
+from ProvinceMapData import PROVINCES_MAP
+from PyUtils import choice, percentage, percentage_chance, rand
+from ReligionData import RELIGIOUS_BUILDINGS, RELIGIOUS_WONDERS
+from RFCUtils import getBaseBuilding, prosecute
+from StoredData import data
+
+gc = CyGlobalContext()
+
+
+### Regions to spread religion ###
+tSpain = [
+ Province.LEON,
+ Province.GALICIA,
+ Province.ARAGON,
+ Province.CATALONIA,
+ Province.CASTILE,
+ Province.LA_MANCHA,
+ Province.ANDALUSIA,
+ Province.VALENCIA,
+]
+tPoland = [
+ Province.GREATER_POLAND,
+ Province.LESSER_POLAND,
+ Province.MASOVIA,
+ Province.SILESIA,
+ Province.SUVALKIJA,
+ Province.BREST,
+ Province.POMERANIA,
+ Province.GALICJA,
+]
+tGermany = [
+ Province.LORRAINE,
+ Province.FRANCONIA,
+ Province.BAVARIA,
+ Province.SWABIA,
+]
+tWestAfrica = [
+ Province.TETOUAN,
+ Province.MOROCCO,
+ Province.MARRAKESH,
+ Province.FEZ,
+ Province.ORAN,
+]
+tNorthAfrica = [
+ Province.ALGIERS,
+ Province.IFRIQIYA,
+ Province.TRIPOLITANIA,
+ Province.CYRENAICA,
+]
+tBalkansAndAnatolia = [
+ Province.CONSTANTINOPLE,
+ Province.THRACE,
+ Province.OPSIKION,
+ Province.PAPHLAGONIA,
+ Province.THRAKESION,
+ Province.CILICIA,
+ Province.ANATOLIKON,
+ Province.ARMENIAKON,
+ Province.CHARSIANON,
+]
+tCentralEurope = [
+ Province.GREATER_POLAND,
+ Province.LESSER_POLAND,
+ Province.MASOVIA,
+ Province.GALICJA,
+ Province.BREST,
+ Province.SUVALKIJA,
+ Province.LITHUANIA,
+ Province.PRUSSIA,
+ Province.POMERANIA,
+ Province.SAXONY,
+ Province.BRANDENBURG,
+ Province.HOLSTEIN,
+ Province.DENMARK,
+ Province.BAVARIA,
+ Province.SWABIA,
+ Province.BOHEMIA,
+ Province.MORAVIA,
+ Province.SILESIA,
+ Province.HUNGARY,
+ Province.TRANSYLVANIA,
+ Province.UPPER_HUNGARY,
+ Province.PANNONIA,
+ Province.SLAVONIA,
+ Province.CARINTHIA,
+ Province.AUSTRIA,
+]
+tMaghrebAndalusia = [
+ Province.TETOUAN,
+ Province.MOROCCO,
+ Province.MARRAKESH,
+ Province.FEZ,
+ Province.ORAN,
+ Province.ALGIERS,
+ Province.IFRIQIYA,
+ Province.TRIPOLITANIA,
+ Province.CYRENAICA,
+ Province.LA_MANCHA,
+ Province.ANDALUSIA,
+ Province.VALENCIA,
+]
+tBulgariaBalkans = [
+ Province.MOESIA,
+ Province.MACEDONIA,
+ Province.SERBIA,
+ Province.WALLACHIA,
+]
+tOldRus = [
+ Province.NOVGOROD,
+ Province.ROSTOV,
+ Province.POLOTSK,
+ Province.SMOLENSK,
+ Province.MINSK,
+ Province.CHERNIGOV,
+ Province.KIEV,
+ Province.PEREYASLAVL,
+ Province.SLOBODA,
+]
+tSouthScandinavia = [
+ Province.DENMARK,
+ Province.GOTALAND,
+ Province.SKANELAND,
+ Province.VESTFOLD,
+ Province.NORWAY,
+]
+tHungary = [
+ Province.HUNGARY,
+ Province.TRANSYLVANIA,
+ Province.UPPER_HUNGARY,
+ Province.PANNONIA,
+]
+
+
+@handler("GameStart")
+def setup():
+ gc.getPlayer(Civ.BYZANTIUM).changeFaith(10)
+ gc.getPlayer(Civ.OTTOMAN).changeFaith(20)
+
+
+@handler("cityAcquired")
+def arabia_should_found_islam(owner, player_id, city, bConquest, bTrade):
+ # Absinthe: If Arabia doesn't found it's first city, but acquires it with a different method
+ # (conquest, flip, trade), it should found Islam there (otherwise no holy city at all)
+ if player_id == Civ.ARABIA and not gc.getGame().isReligionFounded(Religion.ISLAM):
+ # has to be done before the Arab UP is triggered
+ gc.getPlayer(Civ.ARABIA).foundReligion(Religion.ISLAM, Religion.ISLAM, False)
+ gc.getGame().getHolyCity(Religion.ISLAM).setNumRealBuilding(Building.ISLAMIC_SHRINE, 1)
+
+ # TODO when possible move this in UP.py and use firstCity event from DOC?
+ # Arab UP
+ if gc.hasUP(player_id, UniquePower.SPREAD_STATE_RELIGION_TO_NEW_CITIES):
+ UniquePowers.faithUP(player_id, city)
+
+
+@handler("cityAcquired")
+def dutch_should_found_protestantism_on_city_acquired(owner, player_id, city, bConquest, bTrade):
+ dutch_should_found_protestantism(player_id)
+
+
+@handler("cityBuilt")
+def dutch_should_found_protestantism_on_city_built(city):
+ dutch_should_found_protestantism(city.getOwner())
+
+
+def dutch_should_found_protestantism(player_id):
+ # Absinthe: If Protestantism has not been founded by the time the Dutch spawn,
+ # then the Dutch should found it with their first city
+ if player_id == Civ.DUTCH and not gc.getGame().isReligionFounded(Religion.PROTESTANTISM):
+ gc.getPlayer(Civ.DUTCH).foundReligion(
+ Religion.PROTESTANTISM, Religion.PROTESTANTISM, False
+ )
+ gc.getGame().getHolyCity(Religion.PROTESTANTISM).setNumRealBuilding(
+ Building.PROTESTANT_SHRINE, 1
+ )
+ setReformationActive(True)
+ reformationchoice(Civ.DUTCH)
+ reformationOther(Civ.INDEPENDENT)
+ reformationOther(Civ.INDEPENDENT_2)
+ reformationOther(Civ.INDEPENDENT_3)
+ reformationOther(Civ.INDEPENDENT_4)
+ reformationOther(Civ.BARBARIAN)
+ setReformationHitMatrix(Civ.DUTCH, 2)
+
+ for neighbour in civilization(Civ.DUTCH).location.reformation_neighbours:
+ if getReformationHitMatrix(neighbour) == 0:
+ setReformationHitMatrix(neighbour, 1)
+
+
+@handler("cityBuilt")
+def spread_religion_on_city_built(city):
+ # 3MiroUP: spread religion on city foundation
+ iOwner = city.getOwner()
+ if gc.hasUP(iOwner, UniquePower.SPREAD_STATE_RELIGION_TO_NEW_CITIES):
+ UniquePowers.faithUP(iOwner, city)
+
+
+@handler("religionFounded")
+def onReligionFounded(iReligion, iFounder):
+ if iReligion != Religion.JUDAISM:
+ for city in cities.owner(iFounder).entities():
+ if city.isHolyCityByType(
+ iReligion
+ ): # Sedna: Protestant Shrine is now starting point for consistency with Religion.xml, Judaism is special
+ if iReligion == Religion.PROTESTANTISM:
+ iTemple = Building.PROTESTANT_TEMPLE
+ iShrine = Building.PROTESTANT_SHRINE
+ elif iReligion == Religion.ISLAM:
+ iTemple = Building.ISLAMIC_TEMPLE
+ iShrine = Building.ISLAMIC_SHRINE
+ elif iReligion == Religion.CATHOLICISM:
+ iTemple = Building.CATHOLIC_TEMPLE
+ iShrine = Building.CATHOLIC_SHRINE
+ elif iReligion == Religion.ORTHODOXY:
+ iTemple = Building.ORTHODOX_TEMPLE
+ iShrine = Building.ORTHODOX_SHRINE
+ if not city.isHasRealBuilding(iShrine):
+ city.setHasRealBuilding(iShrine, True)
+ if not city.isHasRealBuilding(iTemple):
+ city.setHasRealBuilding(iTemple, True)
+ break
+
+
+def getReformationActive():
+ return data.bReformationActive
+
+
+def setReformationActive(bNewValue):
+ data.bReformationActive = bNewValue
+
+
+def getReformationHitMatrix(iCiv):
+ return data.lReformationHitMatrix[iCiv]
+
+
+def setReformationHitMatrix(iCiv, bNewValue):
+ data.lReformationHitMatrix[iCiv] = bNewValue
+
+
+def getReformationHitMatrixAll():
+ return data.lReformationHitMatrix
+
+
+def getCounterReformationActive():
+ return data.bCounterReformationActive
+
+
+def setCounterReformationActive(bNewValue):
+ data.bCounterReformationActive = bNewValue
+
+
+@handler("BeginGameTurn")
+def checkTurn(iGameTurn):
+ # Absinthe: Spreading religion in a couple preset dates
+ if iGameTurn == year(700) - 2:
+ # Spread Judaism to Toledo
+ spreadReligion(CITIES[City.TOLEDO], Religion.JUDAISM)
+ # Spread Islam to a random city in Africa
+ tCity = selectRandomCityRegion(tNorthAfrica, Religion.ISLAM)
+ if tCity:
+ spreadReligion(tCity, Religion.ISLAM)
+ elif iGameTurn == year(700) + 2:
+ # Spread Judaism and Islam to a random city in Africa
+ tCity = selectRandomCityRegion(tWestAfrica, Religion.ISLAM)
+ if tCity:
+ spreadReligion(tCity, Religion.ISLAM)
+ tCity = selectRandomCityRegion(tWestAfrica, Religion.JUDAISM)
+ if tCity:
+ spreadReligion(tCity, Religion.JUDAISM)
+ elif iGameTurn == year(900):
+ # Spread Judaism to another city in Spain
+ tCity = selectRandomCityRegion(tSpain, Religion.JUDAISM)
+ if tCity:
+ spreadReligion(tCity, Religion.JUDAISM)
+ elif iGameTurn == year(1000):
+ # Spread Judaism to a city in France/Germany
+ tCity = selectRandomCityRegion(tGermany, Religion.JUDAISM)
+ if tCity:
+ spreadReligion(tCity, Religion.JUDAISM)
+ # Spread Islam to another city in Africa
+ tCity = selectRandomCityRegion(tNorthAfrica, Religion.ISLAM)
+ if tCity:
+ spreadReligion(tCity, Religion.ISLAM)
+ elif iGameTurn == year(1101):
+ # Spread Judaism to a couple towns in Poland
+ tCity = selectRandomCityRegion(tPoland, Religion.JUDAISM)
+ if tCity:
+ spreadReligion(tCity, Religion.JUDAISM)
+ elif iGameTurn == year(1200):
+ # Spread Judaism to a couple towns in Poland
+ tCity = selectRandomCityRegion(tPoland, Religion.JUDAISM)
+ if tCity:
+ spreadReligion(tCity, Religion.JUDAISM)
+ elif year(1299) < iGameTurn < year(1350) and iGameTurn % 3 == 0:
+ # Spread Islam to a couple cities in Anatolia before the Ottoman spawn
+ tCity = selectRandomCityRegion(tBalkansAndAnatolia, Religion.ISLAM)
+ if tCity:
+ spreadReligion(tCity, Religion.ISLAM)
+ elif iGameTurn == year(1401):
+ # Spread Judaism to a couple towns in Poland
+ tCity = selectRandomCityRegion(tPoland, Religion.JUDAISM)
+ if tCity:
+ spreadReligion(tCity, Religion.JUDAISM)
+
+ # Absinthe: Spreading Judaism in random dates
+ # General 6% chance to spread Jews to a random city in every third turn
+ if year(800) < iGameTurn < year(1700) and iGameTurn % 3 == 0:
+ if percentage_chance(6, strict=True):
+ tCity = cities.all().random_entry()
+ if tCity is not None:
+ spreadReligion(tCity, Religion.JUDAISM)
+
+ # Additional 11% chance to spread Jews to a random Central European city in every third turn
+ if year(1000) < iGameTurn < year(1500) and iGameTurn % 3 == 1:
+ if percentage_chance(11, strict=True):
+ tCity = selectRandomCityRegion(tCentralEurope, Religion.JUDAISM)
+ if tCity:
+ spreadReligion(tCity, Religion.JUDAISM)
+
+ # Absinthe: Encouraging desired religion spread in a couple areas (mostly for Islam and Orthodoxy)
+ # Maghreb and Cordoba:
+ if year(700) < iGameTurn < year(800) and iGameTurn % 2 == 1:
+ if percentage_chance(32, strict=True):
+ tCity = selectRandomCityRegion(tMaghrebAndalusia, Religion.ISLAM, True)
+ if tCity:
+ spreadReligion(tCity, Religion.ISLAM)
+ if year(800) < iGameTurn < year(1200) and iGameTurn % 3 == 2:
+ if percentage_chance(28, strict=True):
+ tCity = selectRandomCityRegion(tMaghrebAndalusia, Religion.ISLAM, True)
+ if tCity:
+ spreadReligion(tCity, Religion.ISLAM)
+
+ # Bulgaria and Balkans:
+ if year(700) < iGameTurn < year(800) and iGameTurn % 3 == 1:
+ if percentage_chance(25, strict=True):
+ tCity = selectRandomCityRegion(tBulgariaBalkans, Religion.ORTHODOXY, True)
+ if tCity:
+ spreadReligion(tCity, Religion.ORTHODOXY)
+ if year(800) < iGameTurn < year(1000) and iGameTurn % 4 == 1:
+ if percentage_chance(15, strict=True):
+ tCity = selectRandomCityRegion(tBulgariaBalkans, Religion.ORTHODOXY, True)
+ if tCity:
+ spreadReligion(tCity, Religion.ORTHODOXY)
+ # Old Rus territories:
+ if year(852) < iGameTurn < year(1300) and iGameTurn % 4 == 3:
+ if percentage_chance(25, strict=True):
+ tCity = selectRandomCityRegion(tOldRus, Religion.ORTHODOXY, True)
+ if tCity:
+ spreadReligion(tCity, Religion.ORTHODOXY)
+
+ # Extra chance for early Orthodoxy spread in Novgorod:
+ if year(852) < iGameTurn < year(960) and iGameTurn % 5 == 2:
+ if percentage_chance(34, strict=True):
+ tCity = selectRandomCityRegion(
+ [Province.NOVGOROD, Province.POLOTSK, Province.SMOLENSK],
+ Religion.ORTHODOXY,
+ True,
+ )
+ if tCity:
+ spreadReligion(tCity, Religion.ORTHODOXY)
+ # Hungary:
+ if year(960) < iGameTurn < year(1200) and iGameTurn % 4 == 2:
+ if percentage_chance(21, strict=True):
+ tCity = selectRandomCityRegion(tHungary, Religion.CATHOLICISM, True)
+ if tCity:
+ spreadReligion(tCity, Religion.CATHOLICISM)
+
+ # Scandinavia:
+ if year(1000) < iGameTurn < year(1300) and iGameTurn % 4 == 0:
+ if percentage_chance(24, strict=True):
+ tCity = selectRandomCityRegion(tSouthScandinavia, Religion.CATHOLICISM, True)
+ if tCity:
+ spreadReligion(tCity, Religion.CATHOLICISM)
+
+ # Absinthe: Persecution cooldown
+ for i in civilizations().majors().ids():
+ pPlayer = gc.getPlayer(i)
+ if pPlayer.getProsecutionCount() > 0:
+ pPlayer.changeProsecutionCount(-1)
+ # Religious Law means a bigger decrease in persecution points
+ if pPlayer.getCivics(1) == Civic.RELIGIOUS_LAW:
+ if pPlayer.getProsecutionCount() > 0:
+ pPlayer.changeProsecutionCount(-1)
+
+ # Absinthe: Resettle Jewish refugees
+ iRefugies = gc.getMinorReligionRefugies()
+ for i in range(iRefugies):
+ resettleRefugies()
+ gc.setMinorReligionRefugies(0)
+
+ # Absinthe: Benefits for Catholics from the Pope
+ catholic_civs = civilizations().main().catholic().open_borders(Civ.POPE)
+ # Gold gift
+ if iGameTurn >= year(752):
+ if iGameTurn > year(1648): # End of religious wars
+ iDivBy = 14
+ elif iGameTurn > year(1517): # Protestantism
+ iDivBy = 11
+ elif iGameTurn > year(1053): # Schism
+ iDivBy = 6
+ else:
+ iDivBy = 9
+ if iGameTurn % iDivBy == 3 and player(Civ.POPE).getGold() > 100 and percentage_chance(90):
+ weights = []
+ for civ in catholic_civs:
+ iCatholicFaith = 0
+ # Relations with the Pope are much more important here
+ iCatholicFaith += civ.player.getFaith()
+ iCatholicFaith += 8 * max(0, player(Civ.POPE).AI_getAttitude(civ.id))
+ if iCatholicFaith > 0:
+ weights.append(iCatholicFaith)
+ else:
+ weights.append(0)
+
+ if catholic_civs:
+ iChosenPlayer = choice(catholic_civs, weights)
+ if iGameTurn < 100:
+ iGift = min(
+ player(Civ.POPE).getGold() / 5, 40
+ ) # between 20-40, based on the Pope's wealth
+ else:
+ iGift = min(
+ player(Civ.POPE).getGold() / 2, 80
+ ) # between 50-80, based on the Pope's wealth
+ civilization(Civ.POPE).send_gold(iChosenPlayer, iGift)
+
+ if iChosenPlayer.is_human():
+ sText = text("TXT_KEY_FAITH_GOLD_GIFT", iGift)
+ message(civ.id, sText, color=MessageData.BLUE)
+ # Free religious building
+ if iGameTurn > year(800): # The crowning of Charlemagne
+ if iGameTurn > year(1648): # End of religious wars
+ iDivBy = 21
+ elif iGameTurn > year(1517): # Protestantism
+ iDivBy = 14
+ elif iGameTurn > year(1053): # Schism
+ iDivBy = 8
+ else:
+ iDivBy = 11
+ if iGameTurn % iDivBy == 2 and percentage_chance(80, strict=True):
+ weights = []
+ iJerusalemOwner = gc.getMap().plot(*CITIES[City.JERUSALEM]).getPlotCity().getOwner()
+ for civ in catholic_civs:
+ iCatholicFaith = 0
+ # Faith points are the deciding factor for buildings
+ iCatholicFaith += civ.player.getFaith()
+ iCatholicFaith += 2 * max(0, player(Civ.POPE).AI_getAttitude(civ.id))
+ if civ.id == iJerusalemOwner:
+ iCatholicFaith += 30
+ weights.append(iCatholicFaith)
+
+ if catholic_civs:
+ iChosenPlayer = choice(catholic_civs, weights)
+ iCatholicBuilding = Building.CATHOLIC_TEMPLE
+ # No chance for monastery if the selected player knows the Scientific Method tech (which obsoletes monasteries), otherwise 50-50% for temple and monastery
+ if not iChosenPlayer.has_tech(Technology.SCIENTIFIC_METHOD) and percentage_chance(
+ 50
+ ):
+ iCatholicBuilding = Building.CATHOLIC_MONASTERY
+ buildInRandomCity(iChosenPlayer.id, iCatholicBuilding, Religion.CATHOLICISM)
+ # Free technology
+ if iGameTurn > year(843): # Treaty of Verdun, the Carolingian Empire divided into 3 parts
+ if (
+ iGameTurn % 13 == 4
+ ): # checked every 13th turn - won't change it as the game progresses, as the number of available techs will already change with the number of Catholic civs
+ weights = []
+ for civ in catholic_civs:
+ iCatholicFaith = 0
+ # Faith points are the deciding factor for techs
+ iCatholicFaith += civ.player.getFaith()
+ iCatholicFaith += 2 * max(0, player(Civ.POPE).AI_getAttitude(civ.id))
+ if iCatholicFaith > 0:
+ weights.append(iCatholicFaith)
+ else:
+ weights.append(0)
+
+ if catholic_civs:
+ iChosenPlayer = choice(catholic_civs, weights)
+ # look for techs which are known by the Pope but unknown to the chosen civ
+ for tech in Technology:
+ if (
+ civilization(Civ.POPE).has_tech(tech)
+ and not iChosenPlayer.has_tech(tech)
+ and iChosenPlayer.player.getFaith() + 20 > rand(70)
+ ):
+ # chance for actually giving this tech, based on faith points
+ # +20, to have a real chance with low faith points as well
+ iChosenPlayer.add_tech(tech, annoncing=True)
+ if iChosenPlayer.is_human():
+ sText = text(
+ "TXT_KEY_FAITH_TECH_GIFT",
+ gc.getTechInfo(tech).getDescription(),
+ )
+ message(iChosenPlayer.id, sText, force=True, color=MessageData.BLUE)
+ # don't continue if a tech was already given - this also means that there is bigger chance for getting a tech if the chosen civ is multiple techs behind
+ break
+
+ if iGameTurn % 6 == 3:
+ update_pope_techs(catholic_civs)
+
+ # Absinthe: Reformation
+ if getCounterReformationActive():
+ doCounterReformation()
+ if getReformationActive():
+ reformationArrayChoice()
+ if getReformationActive():
+ reformationArrayChoice()
+ if getReformationActive():
+ reformationArrayChoice()
+
+
+def update_pope_techs(catholic_civs):
+ # Absinthe: Pope gets all techs known by at least 3 Catholic civs
+ catholic_civs = civilizations().main().catholic()
+ for tech in Technology:
+ if not civilization(Civ.POPE).has_tech(tech):
+ counter = 0
+ for civ in catholic_civs:
+ if civ.has_tech(tech):
+ counter += 1
+ if counter >= 3:
+ civilization(Civ.POPE).add_tech(tech)
+ break
+
+
+@handler("religionSpread")
+def onReligionSpread(iReligion, iPlayer):
+ pPlayer = gc.getPlayer(iPlayer)
+ if pPlayer.getStateReligion() == iReligion:
+ pPlayer.changeFaith(1)
+ else:
+ pPlayer.changeFaith(-1)
+
+
+@handler("buildingBuilt")
+def onBuildingBuilt(city, building_type):
+ # Absinthe: Faith, Kazimierz, Mont Saint-Michel
+ pPlayer = player(city)
+ iStateReligion = pPlayer.getStateReligion()
+ if iStateReligion != -1:
+ if building_type in RELIGIOUS_BUILDINGS[iStateReligion]:
+ pPlayer.changeFaith(1)
+ if building_type in [
+ Building.CATHOLIC_CATHEDRAL,
+ Building.ORTHODOX_CATHEDRAL,
+ Building.ISLAMIC_CATHEDRAL,
+ Building.PROTESTANT_CATHEDRAL,
+ Wonder.KAZIMIERZ,
+ ]:
+ pPlayer.changeFaith(3)
+ if pPlayer.countNumBuildings(Wonder.PALAIS_DES_PAPES) > 0:
+ pPlayer.changeFaith(1)
+
+ # Absinthe: Wonders: Mont Saint-Michel wonder effect
+ if getBaseBuilding(building_type) in [Building.WALLS, Building.CASTLE]:
+ if pPlayer.countNumBuildings(Wonder.MONT_SAINT_MICHEL) > 0:
+ pPlayer.changeFaith(1)
+ if building_type in RELIGIOUS_WONDERS:
+ pPlayer.changeFaith(4)
+ if pPlayer.countNumBuildings(Wonder.PALAIS_DES_PAPES) > 0:
+ pPlayer.changeFaith(1)
+ if iStateReligion != Religion.JUDAISM and building_type == Wonder.KAZIMIERZ:
+ pPlayer.changeFaith(-min(1, pPlayer.getFaith()))
+ # Kazimierz tries to spread Judaism to a couple new cities
+ cityList = cities.owner(pPlayer).entities()
+ iJewCityNum = int(max((len(cityList) + 2) / 3 + 1, 3))
+ # number of tries are based on number of cities, but at least 3
+ for i in range(iJewCityNum):
+ city = choice(cityList)
+ if not city.isHasReligion(Religion.JUDAISM):
+ city.setHasReligion(Religion.JUDAISM, True, True, False)
+ # Adds Jewish Quarter to all cities which already has Judaism (including the ones where it just spread)
+ for city in cityList:
+ if city.isHasReligion(Religion.JUDAISM):
+ city.setHasRealBuilding(Building.JEWISH_QUARTER, True)
+
+
+def selectRandomCityRegion(tProvinces, iReligionToSpread, bNoSpreadWithReligion=False):
+ cityList = []
+ for iPlayer in civilizations().ids():
+ if not gc.getPlayer(iPlayer).isAlive():
+ continue
+ for city in cities.owner(iPlayer).entities():
+ if PROVINCES_MAP[city.getY()][city.getX()] in tProvinces:
+ # do not try to spread to cities which already have the desired religion
+ if not city.isHasReligion(iReligionToSpread):
+ if bNoSpreadWithReligion:
+ # check if there is any religion already present in the city
+ bAlreadyHasReligion = False
+ for iReligion in range(len(Religion)):
+ if city.isHasReligion(iReligion):
+ bAlreadyHasReligion = True
+ break
+ if not bAlreadyHasReligion:
+ cityList.append(city)
+ else:
+ cityList.append(city)
+ if cityList:
+ city = choice(cityList)
+ return (city.getX(), city.getY())
+ return False
+
+
+def spreadReligion(tPlot, iReligion):
+ x, y = location(tPlot)
+ pPlot = gc.getMap().plot(x, y)
+ if pPlot.isCity():
+ pPlot.getPlotCity().setHasReligion(
+ iReligion, True, True, False
+ ) # Absinthe: puts the given religion into this city, with interface message
+
+
+def buildInRandomCity(iPlayer, iBuilding, iReligion):
+ cityList = []
+ for city in cities.owner(iPlayer).entities():
+ if not city.hasBuilding(iBuilding) and city.isHasReligion(iReligion):
+ cityList.append(city)
+ if cityList:
+ city = choice(cityList)
+ city.setHasRealBuilding(iBuilding, True)
+ gc.getPlayer(iPlayer).changeFaith(1)
+ if human() == iPlayer:
+ sText = (
+ text("TXT_KEY_FAITH_BUILDING1")
+ + " "
+ + gc.getBuildingInfo(iBuilding).getDescription()
+ + " "
+ + text("TXT_KEY_FAITH_BUILDING2")
+ + " "
+ + city.getName()
+ )
+ message(
+ iPlayer,
+ sText,
+ button=gc.getBuildingInfo(iBuilding).getButton(),
+ color=MessageData.BLUE,
+ location=city,
+ )
+
+
+@handler("playerChangeAllCivics")
+def onPlayerChangeAllCivics(
+ iPlayer,
+ new_civic_1,
+ new_civic_2,
+ new_civic_3,
+ new_civic_4,
+ new_civic_5,
+ new_civic_6,
+ old_civic_1,
+ old_civic_2,
+ old_civic_3,
+ old_civic_4,
+ old_civic_5,
+ old_civic_6,
+):
+ # free religion change when switching away from Paganism
+ if iPlayer < civilizations().majors().len():
+ if old_civic_5 == Civic.PAGANISM:
+ if new_civic_5 in [
+ Civic.STATE_RELIGION,
+ Civic.THEOCRACY,
+ Civic.ORGANIZED_RELIGION,
+ ]:
+ if iPlayer == human():
+ # check the available religions
+ religionList = []
+ for city in cities.owner(iPlayer).entities():
+ for iReligion in range(gc.getNumReligionInfos()):
+ if iReligion not in religionList:
+ if city.isHasReligion(iReligion):
+ religionList.append(iReligion)
+ if (
+ len(religionList) == gc.getNumReligionInfos()
+ ): # no need to check any further, if we already have all religions in the list
+ break
+ if (
+ len(religionList) == gc.getNumReligionInfos()
+ ): # no need to check any further, if we already have all religions in the list
+ break
+ data.lReligionChoices = religionList
+ # no popup if no available religions
+ if religionList:
+ showFreeRevolutionPopup(iPlayer, religionList)
+ elif iPlayer < civilizations().main().len():
+ iBestReligionPoint = 0
+ iBestReligion = Religion.CATHOLICISM
+ # loop through all religions
+ for iReligion in range(gc.getNumReligionInfos()):
+ iReligionPoint = 0
+ # check cities for religions and holy cities
+ for city in cities.owner(iPlayer).entities():
+ if city.isHasReligion(iReligion):
+ iReligionPoint += 10
+ if city.isHolyCityByType(iReligion):
+ iReligionPoint += 1000
+ spread_factor = civilization(iPlayer).religion.spreading_threshold[
+ iReligion
+ ]
+ if spread_factor < 60:
+ iReligionPoint = (iReligionPoint * 5) / 10
+ elif spread_factor < 100:
+ iReligionPoint = (iReligionPoint * 8) / 10
+ elif spread_factor > 200:
+ iReligionPoint = (iReligionPoint * 12) / 10
+ # update if better
+ if iReligionPoint > iBestReligionPoint:
+ iBestReligionPoint = iReligionPoint
+ iBestReligion = iReligion
+ # convert to the best religion
+ pPlayer = gc.getPlayer(iPlayer)
+ pPlayer.convertForFree(iBestReligion)
+
+
+# Absinthe: free religion change popup
+def showFreeRevolutionPopup(iPlayer, religionList):
+ """Possibility for the human player to select a religion anarchy-free."""
+ popup = Popup.PyPopup(7629, EventContextTypes.EVENTCONTEXT_ALL)
+ popup.setHeaderString("Religious Revolution")
+ popup.setBodyString("Choose the religion you want to adopt as your State Religion:")
+ for iReligion in religionList:
+ strIcon = gc.getReligionInfo(iReligion).getType()
+ strIcon = "[%s]" % (strIcon.replace("RELIGION_", "ICON_"))
+ strButtonText = "%s %s" % (text(strIcon), gc.getReligionInfo(iReligion).getText())
+ popup.addButton(strButtonText)
+ popup.addButton("We don't want to adopt a State Religion right now")
+ popup.launch(False)
+
+
+@popup_handler(7629)
+def FreeReligiousRevolutionEvent(playerID, netUserData, popupReturn):
+ """Free religious revolution."""
+ # Absinthe: event of the free religion change popup
+ # the last option is the no change option
+ player(playerID).convertForFree(data.lReligionChoices[popupReturn.getButtonClicked()])
+
+
+# REFORMATION
+
+
+@popup_handler(7624)
+def ReformationEvent(playerID, netUserData, popupReturn):
+ iHuman = human()
+ if popupReturn.getButtonClicked() == 0:
+ reformationyes(iHuman)
+ elif popupReturn.getButtonClicked() == 1:
+ reformationno(iHuman)
+
+
+@handler("techAcquired")
+def onTechAcquired(iTech, iTeam, iPlayer):
+ if (
+ gc.getPlayer(iPlayer).isAlive()
+ and turn() > civilization(iPlayer).date.birth
+ and iPlayer < civilizations().majors().len()
+ ):
+ if iTech == Technology.PRINTING_PRESS:
+ if gc.getPlayer(iPlayer).getStateReligion() == Religion.CATHOLICISM:
+ if not gc.getGame().isReligionFounded(Religion.PROTESTANTISM):
+ gc.getPlayer(iPlayer).foundReligion(
+ Religion.PROTESTANTISM, Religion.PROTESTANTISM, False
+ )
+ gc.getGame().getHolyCity(Religion.PROTESTANTISM).setNumRealBuilding(
+ Building.PROTESTANT_SHRINE, 1
+ )
+ setReformationActive(True)
+ reformationchoice(iPlayer)
+ reformationOther(Civ.INDEPENDENT)
+ reformationOther(Civ.INDEPENDENT_2)
+ reformationOther(Civ.INDEPENDENT_3)
+ reformationOther(Civ.INDEPENDENT_4)
+ reformationOther(Civ.BARBARIAN)
+ setReformationHitMatrix(iPlayer, 2)
+ spread_reform_to_neighbour(iPlayer)
+
+
+def spread_reform_to_neighbour(player_id):
+ for neighbour in civilization(player_id).location.reformation_neighbours:
+ if getReformationHitMatrix(neighbour) == 0:
+ setReformationHitMatrix(neighbour, 1)
+
+
+def reformationArrayChoice():
+ civ = (
+ civilizations()
+ .majors()
+ .filter(lambda c: getReformationHitMatrix(c.id) == 1)
+ .random_entry()
+ )
+ if civ is not None:
+ if civ.is_alive() and civ.is_catholic():
+ reformationchoice(civ.id)
+ else:
+ reformationOther(civ.id)
+ setReformationHitMatrix(civ.id, 2)
+ spread_reform_to_neighbour(civ.id)
+
+ if sum(getReformationHitMatrixAll()) == 2 * civilizations().majors().len():
+ setReformationActive(False)
+ # after all players have been hit by the Reformation
+ setCounterReformationActive(True)
+
+
+def reformationchoice(iCiv):
+ if iCiv == Civ.POPE:
+ return # Absinthe: totally exclude the Pope from the Reformation
+
+ if civilization(iCiv).has_state_religion(Religion.PROTESTANTISM) or percentage_chance(
+ civilization(iCiv).ai.reformation_threshold
+ ):
+ reformationyes(iCiv)
+ elif civilization(iCiv).is_human():
+ event_popup(
+ 7624,
+ text("TXT_KEY_REFORMATION_TITLE"),
+ text("TXT_KEY_REFORMATION_MESSAGE"),
+ [text("TXT_KEY_POPUP_YES"), text("TXT_KEY_POPUP_NO")],
+ )
+ else:
+ reformationno(iCiv)
+
+
+def reformationyes(iCiv):
+ iFaith = 0
+ for city in cities.owner(iCiv).entities():
+ if city.isHasReligion(Religion.CATHOLICISM):
+ iFaith += reformationReformCity(city, iCiv)
+
+ # disband catholic missionaries of the AI civs on reformation
+ if iCiv != human():
+ for pUnit in units.owner(iCiv).entities():
+ iUnitType = pUnit.getUnitType()
+ if iUnitType == Unit.CATHOLIC_MISSIONARY:
+ pUnit.kill(0, -1)
+
+ pPlayer = gc.getPlayer(iCiv)
+ # iStateReligion = pPlayer.getStateReligion()
+ # if (pPlayer.getStateReligion() == Religion.CATHOLICISM):
+ pPlayer.setLastStateReligion(Religion.PROTESTANTISM)
+ pPlayer.setConversionTimer(10)
+ pPlayer.setFaith(iFaith)
+
+
+def reformationno(iCiv):
+ iLostFaith = 0
+ pPlayer = gc.getPlayer(iCiv)
+ for city in cities.owner(iCiv).entities():
+ if city.isHasReligion(Religion.CATHOLICISM) and not city.isHasReligion(
+ Religion.PROTESTANTISM
+ ):
+ if percentage_chance(25 + civilization(iCiv).ai.reformation_threshold / 2):
+ city.setHasReligion(
+ Religion.PROTESTANTISM, True, False, False
+ ) # no announcement in this case
+ if pPlayer.isHuman():
+ CityName = city.getNameKey()
+ message(
+ human(),
+ text("TXT_KEY_REFORMATION_RELIGION_STILL_SPREAD", CityName),
+ event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
+ color=MessageData.WHITE,
+ )
+ iLostFaith += 1
+ gc.getPlayer(iCiv).changeFaith(-min(gc.getPlayer(iCiv).getFaith(), iLostFaith))
+
+
+def reformationOther(iCiv):
+ for city in cities.owner(iCiv).entities():
+ if city.isHasReligion(Religion.CATHOLICISM):
+ reformationOtherCity(city, iCiv)
+
+
+def reformationReformCity(pCity, iCiv):
+ iFaith = 0
+ iPopBonus = 0
+ iAIBonus = 0
+ pPlayer = gc.getPlayer(iCiv)
+ # bigger cities have more chance for a new religion to spread
+ if pCity.getPopulation() > 11:
+ iPopBonus = 20
+ elif pCity.getPopulation() > 8:
+ iPopBonus = 15
+ elif pCity.getPopulation() > 5:
+ iPopBonus = 10
+ elif pCity.getPopulation() > 2:
+ iPopBonus = 5
+ # civ-specific modifier, between 3 and 27
+ iCivRef = (civilization(pCity).ai.reformation_threshold / 10) * 3
+ # AI bonus
+ if human() == iCiv:
+ iAIBonus = 10
+
+ # spread the religion: range goes from 48-68% (Catholicism-lovers) to 72-92% (Protestantism-lovers), based on lReformationMatrix
+ # +10% extra bonus for the AI
+ if percentage_chance(45 + iCivRef + iPopBonus + iAIBonus, strict=True):
+ pCity.setHasReligion(Religion.PROTESTANTISM, True, True, False)
+ iFaith += 1
+ iChance = 55 + iCivRef
+ # if protestantism has spread, chance for replacing the buildings: between 58% and 82%, based on lReformationMatrix
+ if pCity.hasBuilding(Building.CATHOLIC_CHAPEL) and percentage_chance(iChance, strict=True):
+ pCity.setHasRealBuilding(Building.CATHOLIC_CHAPEL, False)
+ pCity.setHasRealBuilding(Building.PROTESTANT_CHAPEL, True)
+ if pCity.hasBuilding(Building.CATHOLIC_TEMPLE) and percentage_chance(iChance, strict=True):
+ pCity.setHasRealBuilding(Building.CATHOLIC_TEMPLE, False)
+ pCity.setHasRealBuilding(Building.PROTESTANT_TEMPLE, True)
+ iFaith += 1
+ if pCity.hasBuilding(Building.CATHOLIC_MONASTERY) and percentage_chance(
+ iChance, strict=True
+ ):
+ pCity.setHasRealBuilding(Building.CATHOLIC_MONASTERY, False)
+ pCity.setHasRealBuilding(Building.PROTESTANT_SEMINARY, True)
+ iFaith += 1
+ if pCity.hasBuilding(Building.CATHOLIC_CATHEDRAL) and percentage_chance(
+ iChance, strict=True
+ ):
+ pCity.setHasRealBuilding(Building.CATHOLIC_CATHEDRAL, False)
+ pCity.setHasRealBuilding(Building.PROTESTANT_CATHEDRAL, True)
+ iFaith += 2
+
+ # remove Catholicism if there are no religious buildings left, and there are no catholic wonders in the city
+ # range goes from 39-59% to 71-91%, based on lReformationMatrix
+ if percentage_chance(
+ 55 + ((civilization(iCiv).ai.reformation_threshold / 5) * 2) - iPopBonus,
+ strict=True,
+ ):
+ lCathlist = [
+ Building.CATHOLIC_TEMPLE,
+ Building.CATHOLIC_CHAPEL,
+ Building.CATHOLIC_MONASTERY,
+ Building.CATHOLIC_CATHEDRAL,
+ Wonder.MONASTERY_OF_CLUNY,
+ Wonder.KRAK_DES_CHEVALIERS,
+ Wonder.PALAIS_DES_PAPES,
+ Wonder.NOTRE_DAME,
+ Wonder.WESTMINSTER,
+ ]
+ bCathBuildings = False
+ for iBuilding in lCathlist:
+ if pCity.hasBuilding(iBuilding):
+ bCathBuildings = True
+ break
+ if not bCathBuildings:
+ pCity.setHasReligion(Religion.CATHOLICISM, False, False, False)
+ if pPlayer.isHuman():
+ CityName = pCity.getNameKey()
+ message(
+ human(),
+ text("TXT_KEY_REFORMATION_PEOPLE_ABANDON_CATHOLICISM_1", CityName),
+ event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
+ color=MessageData.WHITE,
+ )
+
+ return iFaith
+
+
+def reformationOtherCity(pCity, iCiv):
+ iPopBonus = 0
+ pPlayer = gc.getPlayer(iCiv)
+ # bigger cities have more chance for a new religion to spread
+ if pCity.getPopulation() > 11:
+ iPopBonus = 30
+ elif pCity.getPopulation() > 7:
+ iPopBonus = 20
+ elif pCity.getPopulation() > 3:
+ iPopBonus = 10
+ # civ-specific, between 3 and 27
+ iCivRef = (civilization(pCity).ai.reformation_threshold / 10) * 3
+
+ # spread the religion: range goes from 23-53% (Catholicism-lovers) to 47-77% (Protestantism-lovers), based on lReformationMatrix
+ if percentage_chance(20 + iCivRef + iPopBonus, strict=True):
+ pCity.setHasReligion(Religion.PROTESTANTISM, True, True, False)
+ # if protestantism has spread, chance for replacing the buildings: between 31% and 79%, based on lReformationMatrix
+ iChance = 25 + 2 * iCivRef
+ if pCity.hasBuilding(Building.CATHOLIC_CHAPEL) and percentage_chance(iChance, strict=True):
+ pCity.setHasRealBuilding(Building.CATHOLIC_CHAPEL, False)
+ pCity.setHasRealBuilding(Building.PROTESTANT_CHAPEL, True)
+ if pCity.hasBuilding(Building.CATHOLIC_TEMPLE) and percentage_chance(iChance, strict=True):
+ pCity.setHasRealBuilding(Building.CATHOLIC_TEMPLE, False)
+ pCity.setHasRealBuilding(Building.PROTESTANT_TEMPLE, True)
+ if pCity.hasBuilding(Building.CATHOLIC_MONASTERY) and percentage_chance(
+ iChance, strict=True
+ ):
+ pCity.setHasRealBuilding(Building.CATHOLIC_MONASTERY, False)
+ pCity.setHasRealBuilding(Building.PROTESTANT_SEMINARY, True)
+ if pCity.hasBuilding(Building.CATHOLIC_CATHEDRAL) and percentage_chance(
+ iChance, strict=True
+ ):
+ pCity.setHasRealBuilding(Building.CATHOLIC_CATHEDRAL, False)
+ pCity.setHasRealBuilding(Building.PROTESTANT_CATHEDRAL, True)
+
+ # remove Catholicism if there are no religious buildings left, and there are no catholic wonders in the city
+ # range goes from 39-54% to 71-86%, based on lReformationMatrix
+ if percentage_chance(
+ 50 + ((civilization(iCiv).ai.reformation_threshold / 5) * 2) - (iPopBonus / 2),
+ strict=True,
+ ):
+ lCathlist = [
+ Building.CATHOLIC_TEMPLE,
+ Building.CATHOLIC_CHAPEL,
+ Building.CATHOLIC_MONASTERY,
+ Building.CATHOLIC_CATHEDRAL,
+ Wonder.MONASTERY_OF_CLUNY,
+ Wonder.KRAK_DES_CHEVALIERS,
+ Wonder.PALAIS_DES_PAPES,
+ Wonder.NOTRE_DAME,
+ Wonder.WESTMINSTER,
+ ]
+ bCathBuildings = False
+ for iBuilding in lCathlist:
+ if pCity.hasBuilding(iBuilding):
+ bCathBuildings = True
+ break
+ if not bCathBuildings:
+ pCity.setHasReligion(Religion.CATHOLICISM, False, False, False)
+ if pPlayer.isHuman(): # message for the human player
+ CityName = pCity.getNameKey()
+ if pPlayer.getStateReligion() == Religion.ISLAM:
+ message(
+ human(),
+ text("TXT_KEY_REFORMATION_PEOPLE_ABANDON_CATHOLICISM_2", CityName),
+ event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
+ color=MessageData.WHITE,
+ )
+ else:
+ message(
+ human(),
+ text("TXT_KEY_REFORMATION_PEOPLE_ABANDON_CATHOLICISM_3", CityName),
+ event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
+ color=MessageData.WHITE,
+ )
+
+
+def doCounterReformation():
+ for iPlayer in range(Civ.POPE - 1):
+ pPlayer = gc.getPlayer(iPlayer)
+ if pPlayer.isAlive() and pPlayer.getStateReligion() == Religion.CATHOLICISM:
+ if pPlayer.isHuman():
+ doCounterReformationHuman(iPlayer)
+ elif percentage_chance(
+ civilization(iPlayer).ai.reformation_threshold, strict=True, reverse=True
+ ):
+ doCounterReformationYes(iPlayer)
+ else:
+ doCounterReformationNo(iPlayer)
+ setCounterReformationActive(False)
+
+
+def doCounterReformationHuman(iPlayer):
+ pPlayer = gc.getPlayer(iPlayer)
+ szMessageYes = (
+ text("TXT_KEY_COUNTER_REFORMATION_MESSAGE_YES_1")
+ + " +%d " % (max(1, pPlayer.getNumCities() / 3))
+ + text("TXT_KEY_COUNTER_REFORMATION_MESSAGE_YES_2")
+ )
+ szMessageNo = (
+ text("TXT_KEY_COUNTER_REFORMATION_MESSAGE_NO_1")
+ + " +%d " % (max(1, pPlayer.getNumCities() / 3))
+ + text("TXT_KEY_COUNTER_REFORMATION_MESSAGE_NO_2")
+ )
+ showCounterPopup(
+ 7626,
+ text("TXT_KEY_COUNTER_REFORMATION_TITLE"),
+ text("TXT_KEY_COUNTER_REFORMATION_MESSAGE"),
+ (szMessageYes, szMessageNo),
+ )
+
+
+def showCounterPopup(popupID, title, message, labels):
+ popup = Popup.PyPopup(popupID, EventContextTypes.EVENTCONTEXT_ALL)
+ popup.setHeaderString(title)
+ popup.setBodyString(message)
+ for i in labels:
+ popup.addButton(i)
+ popup.launch(False)
+
+
+@popup_handler(7626)
+def CounterReformationEvent(playerID, netUserData, popupReturn):
+ iHuman = human()
+ if popupReturn.getButtonClicked() == 0:
+ doCounterReformationYes(iHuman)
+ elif popupReturn.getButtonClicked() == 1:
+ doCounterReformationNo(iHuman)
+
+
+@popup_handler(7628)
+def PersecutionEvent(playerID, netUserData, popupReturn):
+ """Persecution popup event."""
+ iPlotX, iPlotY, iUnitID = data.lPersecutionData
+ iChosenReligion = data.lPersecutionReligions[popupReturn.getButtonClicked()]
+ prosecute(iPlotX, iPlotY, iUnitID, iChosenReligion)
+
+
+def doCounterReformationYes(iPlayer):
+ pPlayer = gc.getPlayer(iPlayer)
+ pCapital = pPlayer.getCapitalCity()
+ iX = pCapital.getX()
+ iY = pCapital.getY()
+ if not pCapital.isNone():
+ if pPlayer.getNumCities() > 0:
+ pCapital = cities.owner(iPlayer).random_entry()
+ iX = pCapital.getX()
+ iY = pCapital.getY()
+ else:
+ return
+ iNumProsecutors = max(1, pPlayer.getNumCities() / 3)
+ for i in range(iNumProsecutors):
+ pPlayer.initUnit(
+ Unit.PROSECUTOR,
+ iX,
+ iY,
+ UnitAITypes.UNITAI_MISSIONARY,
+ DirectionTypes.DIRECTION_SOUTH,
+ )
+
+ for neighbour in civilization(iPlayer).location.reformation_neighbours:
+ civ = civilization(neighbour)
+ if civ.is_alive() and civ.is_protestant():
+ if not civ.player.getCapitalCity().isNone() and civ.player.getNumCities() > 0:
+ capital = cities.owner(neighbour).random_entry()
+ else:
+ return
+
+ civ.player.initUnit(
+ Unit.PROSECUTOR,
+ capital.getX(),
+ capital.getY(),
+ UnitAITypes.UNITAI_MISSIONARY,
+ DirectionTypes.DIRECTION_SOUTH,
+ )
+
+
+def doCounterReformationNo(iPlayer):
+ pPlayer = gc.getPlayer(iPlayer)
+ pPlayer.changeStabilityBase(StabilityCategory.CITIES, max(1, pPlayer.getNumCities() / 3))
+
+
+### End Reformation ###
+
+
+def resettleRefugies():
+ intolerance = [-1] * civilizations().len()
+ for iPlayer in civilizations().ids():
+ pPlayer = gc.getPlayer(iPlayer)
+ if pPlayer.isAlive():
+ if iPlayer < Civ.POPE:
+ # add a random element
+ intolerance[iPlayer] += percentage()
+ intolerance[iPlayer] += 10 * pPlayer.getProsecutionCount()
+ if pPlayer.getProsecutionCount() == 0:
+ intolerance[iPlayer] = max(
+ 0, intolerance[iPlayer] - 30
+ ) # if this player doesn't prosecute, decrease intolerance
+ iRCivic = pPlayer.getCivics(4)
+ if iRCivic == Civic.THEOCRACY:
+ intolerance[iPlayer] += 50
+ elif iRCivic == Civic.FREE_RELIGION:
+ intolerance[iPlayer] = max(0, intolerance[iPlayer] - 30)
+ if iPlayer > Civ.POPE:
+ intolerance[iPlayer] += percentage()
+ # once we have the list of potential nations
+ iCandidate1 = 0
+ for iPlayer in civilizations().ids():
+ if intolerance[iPlayer] > -1 and intolerance[iPlayer] < intolerance[iCandidate1]:
+ iCandidate1 = iPlayer
+ iCandidate2 = 0
+ if iCandidate2 == iCandidate1:
+ iCandidate2 = 1
+ for iPlayer in civilizations().ids():
+ if (
+ intolerance[iPlayer] > -1
+ and iPlayer != iCandidate1
+ and intolerance[iPlayer] < intolerance[iCandidate1]
+ ):
+ iCandidate2 = iPlayer
+
+ if percentage_chance(50, strict=True):
+ migrateJews(iCandidate1)
+ else:
+ migrateJews(iCandidate2)
+
+
+def migrateJews(iPlayer):
+ pPlayer = gc.getPlayer(iPlayer)
+
+ lCityList = [
+ city
+ for city in cities.owner(iPlayer).entities()
+ if not city.isHasReligion(Religion.JUDAISM)
+ ]
+
+ if lCityList:
+ city = choice(lCityList)
+ city.setHasReligion(Religion.JUDAISM, True, True, False)
+
+
+def spread1200ADJews():
+ # Spread Judaism to a random city in Africa
+ tCity = selectRandomCityRegion(tWestAfrica, Religion.JUDAISM)
+ if tCity:
+ spreadReligion(tCity, Religion.JUDAISM)
+ # Spread Judaism to another city in Spain
+ tCity = selectRandomCityRegion(tSpain, Religion.JUDAISM)
+ if tCity:
+ spreadReligion(tCity, Religion.JUDAISM)
+ # Spread Judaism to a city in France/Germany
+ tCity = selectRandomCityRegion(tGermany, Religion.JUDAISM)
+ if tCity:
+ spreadReligion(tCity, Religion.JUDAISM)
diff --git a/Assets/Python/Resources.py b/Assets/Python/Resources.py
new file mode 100644
index 000000000..8a2a314dd
--- /dev/null
+++ b/Assets/Python/Resources.py
@@ -0,0 +1,149 @@
+from CvPythonExtensions import *
+from Consts import MessageData
+from Core import get_scenario, message_if_human, text, message, year
+from CoreTypes import Feature, Improvement, Bonus, Scenario
+from Events import handler
+
+# globals
+gc = CyGlobalContext()
+
+
+@handler("cityAcquired")
+def remove_silk_near_constantinople(owner, player, city, bConquest, bTrade):
+ # Remove Silk resource near Constantinople if it is conquered
+ # TODO should we specify which civ is the conqueror?
+ tCity = (city.getX(), city.getY())
+ if tCity == (81, 24):
+ removeResource(80, 24)
+
+
+@handler("cityAcquired")
+def remove_horse_near_constantinople(owner, player, city, bConquest, bTrade):
+ # Remove horse resource near Hadrianople in 1200 AD scenario if someone captures Hadrianople or Constantinople
+ # TODO should we specify which civ is the conqueror?
+ tCity = (city.getX(), city.getY())
+ if get_scenario() == Scenario.i1200AD:
+ if tCity == (76, 25) or tCity == (81, 24):
+ removeResource(77, 24)
+
+
+def createResource(iX, iY, iBonus, textKey="TXT_KEY_RESOURCE_DISCOVERED"):
+ """Creates a bonus resource and alerts the plot owner"""
+ if (
+ gc.getMap().plot(iX, iY).getBonusType(-1) == -1 or iBonus == -1
+ ): # Absinthe: only proceed if there isn't any bonus resources on the plot, or if we're removing the bonus
+ if iBonus == -1:
+ iBonus = gc.getMap().plot(iX, iY).getBonusType(-1) # for alert
+ gc.getMap().plot(iX, iY).setBonusType(-1)
+ else:
+ gc.getMap().plot(iX, iY).setBonusType(iBonus)
+
+ iOwner = gc.getMap().plot(iX, iY).getOwner()
+ if iOwner >= 0 and textKey != -1: # Absinthe: only show alert to the tile owner
+ city = gc.getMap().findCity(
+ iX,
+ iY,
+ iOwner,
+ TeamTypes.NO_TEAM,
+ True,
+ False,
+ TeamTypes.NO_TEAM,
+ DirectionTypes.NO_DIRECTION,
+ CyCity(),
+ )
+ if not city.isNone():
+ szText = text(
+ textKey,
+ gc.getBonusInfo(iBonus).getTextKey(),
+ city.getName(),
+ gc.getPlayer(iOwner).getCivilizationAdjective(0),
+ )
+ message(
+ iOwner,
+ szText,
+ sound="AS2D_DISCOVERBONUS",
+ event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
+ button=gc.getBonusInfo(iBonus).getButton(),
+ color=MessageData.LIME,
+ location=(iX, iY),
+ )
+
+
+def removeResource(iX, iY, textKey="TXT_KEY_RESOURCE_EXHAUSTED"):
+ """Removes a bonus resource and alerts the plot owner"""
+ if (
+ gc.getMap().plot(iX, iY).getBonusType(-1) != -1
+ ): # only proceed if there is a bonus resource on the plot
+ iBonusType = gc.getMap().plot(iX, iY).getBonusType(-1)
+ iImprovementType = gc.getMap().plot(iX, iY).getImprovementType()
+ createResource(iX, iY, -1, textKey)
+ # Absinthe: remove the improvement too, but only if it improves the given resource
+ # for now only adding the ones we actually use
+ # Pasture, Camp and Colonial Trade Route cannot be built on base terrain (only with resource), so it is always safe to remove those
+ # the question is whether we should also remove Farms and Lumbermills for example
+ if iBonusType == Bonus.HORSE and iImprovementType == Improvement.PASTURE:
+ gc.getMap().plot(iX, iY).setImprovementType(-1)
+ elif iBonusType == Bonus.NORTH_ACCESS and iImprovementType == Improvement.COLONIAL_TRADE:
+ gc.getMap().plot(iX, iY).setImprovementType(-1)
+
+
+@handler("BeginGameTurn")
+def checkTurn(iGameTurn):
+ # Absinthe: note that all actions are taken place in the end of the turn, so actually the resources will appear/disappear for the next turn
+ if iGameTurn == year(552):
+ createResource(80, 24, Bonus.SILK) # Silk near Constantinople
+ elif iGameTurn == year(1000):
+ createResource(36, 24, Bonus.RICE) # Rice in Iberia
+ createResource(86, 2, Bonus.RICE) # Rice in the Middle East
+ elif iGameTurn == (year(1066) + 1):
+ removeResource(2, 69) # Remove the NAA from Iceland
+ elif iGameTurn == year(1452): # Coffee spawns instead of being preplaced
+ createResource(93, 0, Bonus.COFFEE) # near Sinai
+ createResource(99, 13, Bonus.COFFEE) # between Damascus and Edessa
+ elif iGameTurn == year(1500):
+ createResource(
+ 55, 35, Bonus.RICE
+ ) # Rice in Italy - represents trade of the merchant republics
+ elif iGameTurn == year(1580):
+ createResource(32, 59, Bonus.POTATO) # Potatoes in Ireland
+ createResource(29, 57, Bonus.POTATO)
+ createResource(69, 49, Bonus.POTATO) # Poland
+ createResource(66, 46, Bonus.POTATO)
+ createResource(60, 48, Bonus.POTATO) # Northern Germany
+ createResource(55, 52, Bonus.POTATO)
+ createResource(59, 61, Bonus.ACCESS) # Atlantic Access in Scandinavia
+
+
+@handler("plotFeatureRemoved")
+def remove_resource_with_forest_cut_down(pPlot, pCity, iFeatureType):
+ # Absinthe: remove specific resources if the forest/dense forest/palm forest was cut down:
+ # only proceed if there is a bonus resource on the plot
+ if pPlot.getBonusType(-1) != -1:
+ if (
+ iFeatureType == gc.getInfoTypeForString("FEATURE_FOREST")
+ or iFeatureType == Feature.DENSEFOREST
+ or iFeatureType == Feature.PALMFOREST
+ ):
+ iBonusType = pPlot.getBonusType(-1)
+ if iBonusType in [Bonus.TIMBER, Bonus.DEER, Bonus.FUR]:
+ pPlot.setBonusType(-1)
+ # also remove corresponding improvements
+ iImprovementType = pPlot.getImprovementType()
+ if (
+ iImprovementType == Improvement.CAMP
+ ): # camp is only buildable on resources, while lumbermills are removed by default on forest removal
+ pPlot.setImprovementType(-1)
+ # Absinthe: message for the human player if it was inside it's territory
+ iOwner = pPlot.getOwner()
+ message_if_human(
+ iOwner,
+ text(
+ "TXT_KEY_NO_FOREST_NO_RESOURCE",
+ gc.getBonusInfo(iBonusType).getTextKey(),
+ ),
+ sound="AS2D_DISCOVERBONUS",
+ event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
+ button=gc.getBonusInfo(iBonusType).getButton(),
+ color=MessageData.LIME,
+ location=pPlot,
+ )
diff --git a/Assets/Python/components/Resurrection.py b/Assets/Python/Resurrection.py
similarity index 97%
rename from Assets/Python/components/Resurrection.py
rename to Assets/Python/Resurrection.py
index 31967b516..ee7066e70 100644
--- a/Assets/Python/components/Resurrection.py
+++ b/Assets/Python/Resurrection.py
@@ -46,10 +46,9 @@
setTempFlippingCity,
)
from StoredData import data
-import Provinces
+from Provinces import onRespawn
gc = CyGlobalContext()
-pm = Provinces.ProvinceManager()
def resurrection(iGameTurn, iDeadCiv):
@@ -83,8 +82,7 @@ def findCivToResurect(iGameTurn, bSpecialRespawn, iDeadCiv):
tile_max = civilization(iDeadCiv).location.area[AreaType.NORMAL][Area.TILE_MAX]
for city in (
- plots()
- .rectangle(tile_min, tile_max)
+ plots.rectangle(tile_min, tile_max)
.filter(
lambda p: p
not in civilization(iDeadCiv).location.area[AreaType.NORMAL][
@@ -223,9 +221,8 @@ def resurectCiv(iDeadCiv):
setLastRespawnTurn(iDeadCiv, iGameTurn)
# Absinthe: update province status before the cities are flipped, so potential provinces will update if there are cities in them
- pm.onRespawn(
- iDeadCiv
- ) # Absinthe: resetting the original potential provinces, and adding special province changes on respawn (Cordoba)
+ # Absinthe: resetting the original potential provinces, and adding special province changes on respawn (Cordoba)
+ onRespawn(iDeadCiv)
# Absinthe: we shouldn't get a previous leader on respawn - would be changed to a newer one in a couple turns anyway
# instead we have a random chance to remain with the leader before the collapse, or to switch to the next one
@@ -397,7 +394,7 @@ def resurectCiv(iDeadCiv):
def moveBackCapital(iCiv):
- cityList = cities().owner(iCiv).entities()
+ cityList = cities.owner(iCiv).entities()
tiles = civilization(iCiv).location.get(
lambda c: c.new_capital, [civilization(iCiv).location.capital]
)
@@ -442,15 +439,14 @@ def convertBackCulture(iCiv):
# Sedna17: restored to be normal areas, not core
# collect all the cities in the region
for city in (
- plots()
- .rectangle(
+ plots.rectangle(
civilization(iCiv).location.area[AreaType.NORMAL][Area.TILE_MIN],
civilization(iCiv).location.area[AreaType.NORMAL][Area.TILE_MAX],
)
.cities()
.entities()
):
- for plot in plots().surrounding(location(city)).entities():
+ for plot in plots.surrounding(location(city)).entities():
iCivCulture = plot.getCulture(iCiv)
iLoopCivCulture = 0
for civ in civilizations().minors().ids():
diff --git a/Assets/Python/RiseAndFall.py b/Assets/Python/RiseAndFall.py
new file mode 100644
index 000000000..3d653aeb5
--- /dev/null
+++ b/Assets/Python/RiseAndFall.py
@@ -0,0 +1,1411 @@
+from CvPythonExtensions import *
+from Civilizations import (
+ set_initial_contacts,
+ reveal_areas,
+ set_starting_techs_1200AD,
+ set_starting_gold,
+ set_starting_techs,
+ create_starting_units_1200AD,
+ create_starting_units_500AD,
+ create_starting_workers,
+ set_starting_diplomacy_1200AD,
+ set_starting_faith,
+)
+from Consts import MessageData
+from Core import (
+ civilization,
+ civilizations,
+ event_popup,
+ get_scenario,
+ get_scenario_start_turn,
+ human,
+ is_major_civ,
+ is_minor_civ,
+ location,
+ make_unit,
+ make_units,
+ message,
+ player,
+ text,
+ turn,
+ year,
+ cities,
+ plots,
+)
+from History import ottoman_invasion
+from PyUtils import percentage, percentage_chance, rand, choice
+import Provinces
+from RFCUtils import (
+ clearPlague,
+ convertPlotCulture,
+ cultureManager,
+ flipCity,
+ flipUnitsInArea,
+ flipUnitsInCityAfter,
+ flipUnitsInCityBefore,
+ flipUnitsInPlots,
+ forcedInvasion,
+ getLastTurnAlive,
+ getPlagueCountdown,
+ getUniqueBuilding,
+ goodPlots,
+ innerSpawn,
+ killAllUnitsInArea,
+ killUnitsInPlots,
+ outerInvasion,
+ ownedCityPlots,
+ setPlagueCountdown,
+ spreadMajorCulture,
+ squareSearch,
+ updateMinorTechs,
+)
+import Religions
+from Collapse import collapseByBarbs, collapseGeneric, collapseMotherland
+from Secession import secession, secessionCloseCollapse
+from Resurrection import resurectCiv, resurrection
+import Victory
+from StoredData import data
+import Crusades
+
+from MiscData import PLAGUE_IMMUNITY
+from CoreTypes import (
+ Area,
+ AreaType,
+ Building,
+ Civ,
+ LeaderType,
+ PlayerType,
+ Scenario,
+ Terrain,
+ Feature,
+ Improvement,
+ Unit,
+)
+from Wonders import leaning_tower_effect_1200AD
+from Events import handler, popup_handler
+
+gc = CyGlobalContext()
+
+iCheatersPeriod = 12
+iBetrayalPeriod = 8
+iBetrayalThreshold = 66
+iRebellionDelay = 15
+iEscapePeriod = 30
+
+
+@handler("GameStart")
+def setup():
+ setEarlyLeaders()
+ setupRespawnTurns()
+
+ iHuman = human()
+ if get_scenario() == Scenario.i500AD:
+ create_starting_units_500AD()
+ for civ in civilizations().majors().filter(lambda c: c.date.birth == year(500)).ids():
+ reveal_areas(civ)
+ set_initial_contacts(civ)
+
+ else:
+ create_starting_units_1200AD()
+ for civ in (
+ civilizations()
+ .main()
+ .filter(lambda c: c.date.birth < get_scenario_start_turn(Scenario.i1200AD))
+ .ids()
+ ):
+ reveal_areas(civ)
+ set_initial_contacts(civ, False)
+ # Temporarily all civs get the same starting techs as Aragon
+ set_starting_techs_1200AD(civ)
+
+ set_starting_faith()
+ set_starting_diplomacy_1200AD()
+ leaning_tower_effect_1200AD()
+ Religions.spread1200ADJews() # Spread Jews to some random cities
+ Victory.set1200UHVDone(iHuman)
+ # Temporarily all civs get the same starting techs as Aragon
+ set_starting_techs_1200AD(Civ.POPE)
+ Crusades.do1200ADCrusades()
+
+ set_starting_gold()
+ set_war_on_spawn()
+
+
+@handler("cityAcquired")
+def spread_culture_to_new_acquired_city(owner, player, city, bConquest, bTrade):
+ # Absinthe: Spread some culture to the newly acquired city, this is for nearby indy cities,
+ # so should be applied in all cases (conquest, flip, trade)
+ if player < civilizations().majors().len():
+ spreadMajorCulture(player, city.getX(), city.getY())
+
+
+def set_war_on_spawn():
+ for civ in civilizations():
+ wars = civ.scenario.get("wars")
+ if wars is not None:
+ for other, war_threshold in wars.items():
+ if percentage_chance(war_threshold, strict=True) and not civ.at_war(other):
+ civ.set_war(other)
+
+
+def setSpecialRespawnTurn(iCiv, iNewValue):
+ data.lSpecialRespawnTurn[iCiv] = iNewValue
+
+
+def setupRespawnTurns():
+ """Uniform spawns within +/- 10 turns of desired turn."""
+ for iCiv in civilizations().majors().ids():
+ setSpecialRespawnTurn(
+ iCiv, civilization(iCiv).date.respawning + (rand(21) - 10) + (rand(21) - 10)
+ )
+
+
+def setEarlyLeaders():
+ for civ in civilizations().majors().ai():
+ if civ.leaders[LeaderType.EARLY] != civ.leaders[LeaderType.PRIMARY]:
+ leader = civ.leaders[LeaderType.EARLY]
+ civ.player.setLeader(leader)
+
+
+def getNewCiv():
+ return data.iNewCiv
+
+
+def setNewCiv(iNewValue):
+ data.iNewCiv = iNewValue
+
+
+def getNewCivFlip():
+ return data.iNewCivFlip
+
+
+def setNewCivFlip(iNewValue):
+ data.iNewCivFlip = iNewValue
+
+
+def getOldCivFlip():
+ return data.iOldCivFlip
+
+
+def setOldCivFlip(iNewValue):
+ data.iOldCivFlip = iNewValue
+
+
+def getTempTopLeft():
+ return data.iTempTopLeft
+
+
+def setTempTopLeft(tNewValue):
+ data.iTempTopLeft = tNewValue
+
+
+def getTempBottomRight():
+ return data.iTempBottomRight
+
+
+def setTempBottomRight(tNewValue):
+ data.iTempBottomRight = tNewValue
+
+
+def getSpawnWar():
+ return data.iSpawnWar
+
+
+def setSpawnWar(iNewValue):
+ data.iSpawnWar = iNewValue
+
+
+def getAlreadySwitched():
+ return data.bAlreadySwitched
+
+
+def setAlreadySwitched(bNewValue):
+ data.bAlreadySwitched = bNewValue
+
+
+def getSpawnDelay(iCiv):
+ return data.lSpawnDelay[iCiv]
+
+
+def setSpawnDelay(iCiv, iNewValue):
+ data.lSpawnDelay[iCiv] = iNewValue
+
+
+def getFlipsDelay(iCiv):
+ return data.lFlipsDelay[iCiv]
+
+
+def setFlipsDelay(iCiv, iNewValue):
+ data.lFlipsDelay[iCiv] = iNewValue
+
+
+def getBetrayalTurns():
+ return data.iBetrayalTurns
+
+
+def setBetrayalTurns(iNewValue):
+ data.iBetrayalTurns = iNewValue
+
+
+def getRebelCiv():
+ return data.iRebelCiv
+
+
+def getRebelCities():
+ return data.lRebelCities
+
+
+def getRebelSuppress():
+ return data.lRebelSuppress
+
+
+def setRebelSuppress(lSuppressList):
+ data.lRebelSuppress = lSuppressList
+
+
+def getTempFlippingCity():
+ return data.iTempFlippingCity
+
+
+def setTempFlippingCity(tNewValue):
+ data.iTempFlippingCity = tNewValue
+
+
+def getCheatersCheck(i):
+ return data.lCheatersCheck[i]
+
+
+def setCheatersCheck(i, iNewValue):
+ data.lCheatersCheck[i] = iNewValue
+
+
+def getDeleteMode(i):
+ return data.lDeleteMode[i]
+
+
+def setDeleteMode(i, iNewValue):
+ data.lDeleteMode[i] = iNewValue
+
+
+def newCivPopup(iCiv):
+ event_popup(
+ 7614,
+ text("TXT_KEY_NEWCIV_TITLE"),
+ text("TXT_KEY_NEWCIV_MESSAGE", player(iCiv).getCivilizationAdjectiveKey()),
+ [text("TXT_KEY_POPUP_YES"), text("TXT_KEY_POPUP_NO")],
+ )
+ setNewCiv(iCiv)
+
+
+@popup_handler(7614)
+def RiseAndFallPopupEvent(playerID, netUserData, popupReturn):
+ if popupReturn.getButtonClicked() == 0: # 1st button
+ iOldHandicap = gc.getActivePlayer().getHandicapType()
+ iNewCiv = getNewCiv()
+ Victory.switchUHV(iNewCiv, human())
+ gc.getActivePlayer().setHandicapType(gc.getPlayer(iNewCiv).getHandicapType())
+ gc.getGame().setActivePlayer(iNewCiv, False)
+ gc.getPlayer(iNewCiv).setHandicapType(iOldHandicap)
+ for iMaster in civilizations().majors().ids():
+ if gc.getTeam(gc.getPlayer(iNewCiv).getTeam()).isVassal(iMaster):
+ gc.getTeam(gc.getPlayer(iNewCiv).getTeam()).setVassal(iMaster, False, False)
+ setAlreadySwitched(True)
+ gc.getPlayer(iNewCiv).setPlayable(True)
+
+
+def flipPopup(iNewCiv, tTopLeft, tBottomRight):
+ iHuman = human()
+ flipText = text("TXT_KEY_FLIPMESSAGE1")
+
+ for city in (
+ plots.rectangle(tTopLeft, tBottomRight)
+ .add(civilization(iNewCiv).location.area[AreaType.CORE][Area.ADDITIONAL_TILES])
+ .cities()
+ .filter(lambda c: c.getOwner() == iHuman and not c.isCapital())
+ .entities()
+ ):
+ flipText += city.getName() + "\n"
+ flipText += text("TXT_KEY_FLIPMESSAGE2")
+
+ event_popup(
+ 7615,
+ text("TXT_KEY_NEWCIV_TITLE"),
+ flipText,
+ [text("TXT_KEY_POPUP_YES"), text("TXT_KEY_POPUP_NO")],
+ )
+ setNewCivFlip(iNewCiv)
+ setOldCivFlip(iHuman)
+ setTempTopLeft(tTopLeft)
+ setTempBottomRight(tBottomRight)
+
+
+@popup_handler(7615)
+def FlipPopupEvent(playerID, netUserData, popupReturn):
+ iHuman = human()
+ tTopLeft = getTempTopLeft()
+ tBottomRight = getTempBottomRight()
+ iNewCivFlip = getNewCivFlip()
+
+ humanCityList = []
+
+ for city in (
+ plots.rectangle(tTopLeft, tBottomRight)
+ .add(civilization(iNewCivFlip).location.area[AreaType.CORE][Area.ADDITIONAL_TILES])
+ .cities()
+ .filter(lambda c: c.getOwner() == iHuman and not c.isCapital())
+ .entities()
+ ):
+ humanCityList.append(city)
+
+ if popupReturn.getButtonClicked() == 0: # 1st button
+ message(iHuman, text("TXT_KEY_FLIP_AGREED"), force=True, color=MessageData.GREEN)
+
+ if humanCityList:
+ for city in humanCityList:
+ tCity = (city.getX(), city.getY())
+ cultureManager(tCity, 100, iNewCivFlip, iHuman, False, False, False)
+ flipUnitsInCityBefore(tCity, iNewCivFlip, iHuman)
+ setTempFlippingCity(tCity)
+ flipCity(tCity, 0, 0, iNewCivFlip, [iHuman])
+ flipUnitsInCityAfter(tCity, iNewCivFlip)
+
+ # same code as Betrayal - done just once to make sure human player doesn't hold a stack just outside of the cities
+ for plot in plots.rectangle(tTopLeft, tBottomRight).entities():
+ iNumUnitsInAPlot = plot.getNumUnits()
+ if iNumUnitsInAPlot > 0:
+ for i in range(iNumUnitsInAPlot):
+ unit = plot.getUnit(i)
+ if unit.getOwner() == iHuman:
+ rndNum = percentage()
+ if rndNum >= iBetrayalThreshold:
+ if unit.getDomainType() == DomainTypes.DOMAIN_SEA: # land unit
+ iUnitType = unit.getUnitType()
+ unit.kill(False, iNewCivFlip)
+ make_unit(iNewCivFlip, iUnitType, location(plot))
+ i = i - 1
+
+ if getCheatersCheck(0) == 0:
+ setCheatersCheck(0, iCheatersPeriod)
+ setCheatersCheck(1, getNewCivFlip())
+
+ elif popupReturn.getButtonClicked() == 1: # 2nd button
+ message(iHuman, text("TXT_KEY_FLIP_REFUSED"), force=True, color=MessageData.RED)
+
+ if humanCityList:
+ for city in humanCityList:
+ pCurrent = gc.getMap().plot(city.getX(), city.getY())
+ oldCulture = pCurrent.getCulture(iHuman)
+ # Absinthe: changeCulture instead of setCulture, otherwise previous culture will be lost
+ pCurrent.changeCulture(iNewCivFlip, oldCulture / 2, True)
+ pCurrent.setCulture(iHuman, oldCulture / 2, True)
+ iWar = getSpawnWar() + 1
+ setSpawnWar(iWar)
+ if getSpawnWar() == 1:
+ # safety check - don't want to use canDeclareWar, as here we want to always declare war
+ if not gc.getTeam(gc.getPlayer(iNewCivFlip).getTeam()).isAtWar(iHuman):
+ gc.getTeam(gc.getPlayer(iNewCivFlip).getTeam()).declareWar(
+ iHuman, False, -1
+ )
+ setBetrayalTurns(iBetrayalPeriod)
+ initBetrayal()
+
+
+@popup_handler(7622)
+def ResurrectionEvent(playerID, netUserData, popupReturn):
+ # resurrection when some human controlled cities are also included
+ iHuman = human()
+ iRebelCiv = getRebelCiv()
+ iChoice = popupReturn.getButtonClicked()
+ iHumanCity = 0
+ lCityList = getRebelCities()
+ for (x, y) in lCityList:
+ iOwner = gc.getMap().plot(x, y).getPlotCity().getOwner()
+ if iOwner == iHuman:
+ iHumanCity += 1
+
+ if iChoice == 1:
+ lList = getRebelSuppress()
+ lList[iHuman] = 2 # let go + war
+ setRebelSuppress(lList)
+ elif iChoice == 2:
+ if percentage_chance(40, strict=True):
+ lCityList = getRebelCities()
+ for (x, y) in lCityList:
+ pCity = gc.getMap().plot(x, y).getPlotCity()
+ if pCity.getOwner() == iHuman:
+ pCity.changeOccupationTimer(2)
+ pCity.changeHurryAngerTimer(10)
+ lList = getRebelSuppress()
+ lList[iHuman] = 3 # keep cities + war
+ setRebelSuppress(lList)
+ else:
+ lList = getRebelSuppress()
+ lList[iHuman] = 4 # let go + war
+ setRebelSuppress(lList)
+ elif iChoice == 3:
+ iLoyalPrice = min((10 * gc.getPlayer(iHuman).getGold()) / 100, 50 * iHumanCity)
+ gc.getPlayer(iHuman).setGold(gc.getPlayer(iHuman).getGold() - iLoyalPrice)
+ if percentage_chance(iLoyalPrice / iHumanCity, strict=True):
+ lList = getRebelSuppress()
+ lList[iHuman] = 1 # keep + no war
+ setRebelSuppress(lList)
+ else:
+ lList = getRebelSuppress()
+ lList[iHuman] = 4 # let go + war
+ setRebelSuppress(lList)
+ elif iChoice == 4:
+ iLoyalPrice = min((10 * gc.getPlayer(iHuman).getGold()) / 100, 50 * iHumanCity)
+ gc.getPlayer(iHuman).setGold(gc.getPlayer(iHuman).getGold() - iLoyalPrice)
+ if percentage_chance(iLoyalPrice / iHumanCity + 40, strict=True):
+ lCityList = getRebelCities()
+ for (x, y) in lCityList:
+ pCity = gc.getMap().plot(x, y).getPlotCity()
+ if pCity.getOwner() == iHuman:
+ pCity.changeOccupationTimer(2)
+ pCity.changeHurryAngerTimer(10)
+ lList = getRebelSuppress()
+ lList[iHuman] = 3 # keep + war
+ setRebelSuppress(lList)
+ else:
+ lList = getRebelSuppress()
+ lList[iHuman] = 2 # let go + war
+ setRebelSuppress(lList)
+ resurectCiv(getRebelCiv())
+
+
+@handler("cityBuilt")
+def onCityBuilt(pCity):
+ iPlayer = pCity.getOwner()
+ tCity = (pCity.getX(), pCity.getY())
+ Provinces.onCityBuilt(iPlayer, pCity.getX(), pCity.getY())
+ # Absinthe: We can add free buildings for new cities here
+ # Note that it will add the building every time a city is founded on the plot, not just on the first time
+ # Venice (56, 35), Augsburg (55, 41), Porto (23, 31), Prague (60, 44), Riga (74, 58), Perekop (87, 36)
+ # London (41, 52), Novgorod (80, 62) currently has preplaced fort on the map instead
+ if tCity in [(56, 35), (55, 41), (23, 31), (60, 44), (74, 58), (87, 36)]:
+ pCity.setHasRealBuilding(getUniqueBuilding(iPlayer, Building.WALLS), True)
+ elif tCity == (75, 53): # Vilnius - important for AI Lithuania against Prussia
+ if not gc.getPlayer(Civ.LITHUANIA).isHuman():
+ pCity.setHasRealBuilding(getUniqueBuilding(iPlayer, Building.WALLS), True)
+
+
+@handler("BeginGameTurn")
+def checkTurn(iGameTurn):
+ # Trigger betrayal mode
+ if getBetrayalTurns() > 0:
+ initBetrayal()
+
+ if getCheatersCheck(0) > 0:
+ teamPlayer = gc.getTeam(gc.getPlayer(human()).getTeam())
+ if teamPlayer.isAtWar(getCheatersCheck(1)):
+ initMinorBetrayal(getCheatersCheck(1))
+ setCheatersCheck(0, 0)
+ setCheatersCheck(1, -1)
+ else:
+ setCheatersCheck(0, getCheatersCheck(0) - 1)
+
+ if iGameTurn % 20 == 0:
+ for civ in civilizations().independents().alive():
+ updateMinorTechs(civ.id, Civ.BARBARIAN)
+
+ # Absinthe: checking the spawn dates
+ for iLoopCiv in civilizations().majors().ids():
+ if (
+ civilization(iLoopCiv).date.birth != 0
+ and iGameTurn >= civilization(iLoopCiv).date.birth - 2
+ and iGameTurn <= civilization(iLoopCiv).date.birth + 4
+ ):
+ initBirth(iGameTurn, civilization(iLoopCiv).date.birth, iLoopCiv)
+
+ # Fragment minor civs:
+ # 3Miro: Shuffle cities between Indies and Barbs to make sure there is no big Independent nation
+ if iGameTurn >= 20:
+ if iGameTurn % 15 == 6:
+ fragmentIndependents()
+ if iGameTurn % 30 == 12:
+ fragmentBarbarians(iGameTurn)
+
+ # Fall of civs:
+ # Barb collapse: if more than 1/3 of the empire is conquered and/or held by barbs = collapse
+ # Generic collapse: if 1/2 of the empire is lost in only a few turns (16 ATM) = collapse
+ # Motherland collapse: if no city is in the core area and the number of cities in the normal area is less than the number of foreign cities = collapse
+ # Secession: if stability is negative there is a chance (bigger chance with worse stability) for a random city to declare it's independence
+ if iGameTurn >= 64 and iGameTurn % 7 == 0: # mainly for Seljuks, Mongols, Timurids
+ collapseByBarbs(iGameTurn)
+ if iGameTurn >= 34 and iGameTurn % 16 == 0:
+ collapseGeneric(iGameTurn)
+ if iGameTurn >= 34 and iGameTurn % 9 == 7:
+ collapseMotherland(iGameTurn)
+ if iGameTurn > 20 and iGameTurn % 3 == 1:
+ secession(iGameTurn)
+ if iGameTurn > 20 and iGameTurn % 7 == 3:
+ secessionCloseCollapse(iGameTurn)
+
+ # Resurrection of civs:
+ # This is one place to control the frequency of resurrection; will not be called with high iNumDeadCivs
+ # Generally we want to allow Kiev, Bulgaria, Cordoba, Burgundy, Byzantium at least to be dead in late game without respawning
+ # Absinthe: was 12 and 8 originally in RFCE, but we don't need that many dead civs
+ iNumDeadCivs1 = 8 # 5 in vanilla RFC, 8 in warlords RFC
+ iNumDeadCivs2 = 5 # 3 in vanilla RFC, 6 in warlords RFC
+
+ iCiv = getSpecialRespawn(iGameTurn)
+ if iCiv > -1:
+ resurrection(iGameTurn, iCiv)
+ elif (
+ gc.getGame().countCivPlayersEverAlive() - gc.getGame().countCivPlayersAlive()
+ > iNumDeadCivs1
+ ):
+ if iGameTurn % 10 == 7:
+ resurrection(iGameTurn, -1)
+ elif (
+ gc.getGame().countCivPlayersEverAlive() - gc.getGame().countCivPlayersAlive()
+ > iNumDeadCivs2
+ ):
+ if iGameTurn % 23 == 11:
+ resurrection(iGameTurn, -1)
+
+ # Absinthe: Reduce cities to towns, in order to make room for new civs
+ if iGameTurn == civilization(Civ.SCOTLAND).date.birth - 3:
+ # Reduce Inverness and Scone, so more freedom in where to found cities in Scotland
+ reduceCity((37, 65))
+ reduceCity((37, 67))
+ elif iGameTurn == civilization(Civ.ENGLAND).date.birth - 3:
+ # Reduce Norwich and Nottingham, so more freedom in where to found cities in England
+ reduceCity((43, 55))
+ reduceCity((39, 56))
+ elif iGameTurn == civilization(Civ.SWEDEN).date.birth - 2:
+ # Reduce Uppsala
+ reduceCity((65, 66))
+ # Absinthe: Reduce cities to town, if not owned by the human player
+ if iGameTurn == year(1057):
+ # Reduce Kairouan
+ pPlot = gc.getMap().plot(43, 55)
+ if pPlot.isCity():
+ if pPlot.getPlotCity().getOwner() != human():
+ reduceCity((43, 55))
+
+
+def reduceCity(tPlot):
+ # Absinthe: disappearing cities (reducing them to an improvement)
+ pPlot = gc.getMap().plot(tPlot[0], tPlot[1])
+ if pPlot.isCity():
+ # Absinthe: apologize from the player:
+ msgString = (
+ text("TXT_KEY_REDUCE_CITY_1")
+ + " "
+ + pPlot.getPlotCity().getName()
+ + " "
+ + text("TXT_KEY_REDUCE_CITY_2")
+ )
+ message(
+ pPlot.getPlotCity().getOwner(), msgString, color=MessageData.ORANGE, location=pPlot
+ )
+
+ pPlot.eraseCityDevelopment()
+ pPlot.setImprovementType(Improvement.TOWN) # Improvement Town instead of the city
+ pPlot.setRouteType(0) # Also adding a road there
+
+
+@handler("BeginPlayerTurn")
+def checkPlayerTurn(iGameTurn, iPlayer):
+ # Absinthe & Merijn: leader switching with any number of leaders
+ # for the AI only, leader switch and cheats
+ if gc.getPlayer(iPlayer).isAlive() and iPlayer < civilizations().majors().len():
+ if iPlayer != human():
+ late_leaders = civilization(iPlayer).leaders[LeaderType.LATE]
+ if late_leaders:
+ for tLeader in reversed(late_leaders):
+ if iGameTurn >= year(tLeader[1]):
+ switchLateLeaders(iPlayer, tLeader)
+ break
+
+ # 3Miro: English cheat, the AI is utterly incompetent when it has to launch an invasion on an island
+ # if in 1300AD Dublin is still Barbarian, it will flip to England
+ if (
+ iGameTurn == year(1300)
+ and human() != Civ.ENGLAND
+ and iPlayer == Civ.ENGLAND
+ and player(Civ.ENGLAND).isAlive()
+ ):
+ tDublin = (32, 58)
+ pPlot = gc.getMap().plot(tDublin[0], tDublin[1])
+ if pPlot.isCity():
+ if pPlot.getPlotCity().getOwner() == Civ.BARBARIAN:
+ pDublin = pPlot.getPlotCity()
+ cultureManager(tDublin, 50, Civ.ENGLAND, Civ.BARBARIAN, False, True, True)
+ flipUnitsInCityBefore(tDublin, Civ.ENGLAND, Civ.BARBARIAN)
+ setTempFlippingCity(tDublin)
+ flipCity(
+ tDublin, 0, 0, Civ.ENGLAND, [Civ.BARBARIAN]
+ ) # by trade because by conquest may raze the city
+ flipUnitsInCityAfter(tDublin, Civ.ENGLAND)
+
+ # Absinthe: Another English AI cheat, extra defenders and defensive buildings in Normandy some turns after spawn - from RFCE++
+ if (
+ iGameTurn == year(1066) + 3
+ and human() != Civ.ENGLAND
+ and iPlayer == Civ.ENGLAND
+ and player(Civ.ENGLAND).isAlive()
+ ):
+ for city in (
+ plots.rectangle((39, 46), (45, 50)).cities().owner(Civ.ENGLAND).entities()
+ ):
+ make_unit(Civ.ENGLAND, Unit.GUISARME, city)
+ make_unit(Civ.ENGLAND, Unit.ARBALEST, city)
+ city.setHasRealBuilding(Building.WALLS, True)
+ city.setHasRealBuilding(Building.CASTLE, True)
+
+
+def switchLateLeaders(iPlayer, tLeader):
+ iLeader, iDate, iThreshold, iEra = tLeader
+ if iLeader == gc.getPlayer(iPlayer).getLeader():
+ return
+ if gc.getPlayer(iPlayer).getCurrentEra() >= iEra:
+ iThreshold *= 2
+ if (
+ gc.getPlayer(iPlayer).getAnarchyTurns() != 0
+ or getPlagueCountdown(iPlayer) > 0
+ or player(iPlayer).getStability() <= -10
+ or percentage_chance(iThreshold, strict=True)
+ ):
+ gc.getPlayer(iPlayer).setLeader(iLeader)
+
+ # Absinthe: message about the leader switch for the human player
+ iHuman = human()
+ HumanTeam = gc.getTeam(gc.getPlayer(iHuman).getTeam())
+ PlayerTeam = gc.getPlayer(iPlayer).getTeam()
+ if HumanTeam.isHasMet(PlayerTeam) and player().isExisting():
+ message(
+ iHuman,
+ text(
+ "TXT_KEY_LEADER_SWITCH",
+ gc.getPlayer(iPlayer).getName(),
+ gc.getPlayer(iPlayer).getCivilizationDescriptionKey(),
+ ),
+ event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
+ color=MessageData.PURPLE,
+ )
+
+
+def fragmentIndependents():
+ for iIndep1 in civilizations().independents().ids():
+ pIndep1 = gc.getPlayer(iIndep1)
+ iNumCities1 = pIndep1.getNumCities()
+ for iIndep2 in civilizations().independents().ids():
+ if iIndep1 == iIndep2:
+ continue
+ pIndep2 = gc.getPlayer(iIndep2)
+ iNumCities2 = pIndep2.getNumCities()
+ if abs(iNumCities1 - iNumCities2) > 5:
+ if iNumCities1 > iNumCities2:
+ iBig = iIndep1
+ iSmall = iIndep2
+ else:
+ iBig = iIndep2
+ iSmall = iIndep1
+ iDivideCounter = 0
+ iCounter = 0
+ for city in cities.owner(iBig).entities():
+ iDivideCounter += 1
+ if iDivideCounter % 2 == 1:
+ tCity = (city.getX(), city.getY())
+ pCurrent = gc.getMap().plot(tCity[0], tCity[1])
+ cultureManager(tCity, 50, iSmall, iBig, False, True, True)
+ flipUnitsInCityBefore(tCity, iSmall, iBig)
+ setTempFlippingCity(tCity)
+ flipCity(
+ tCity, 0, 0, iSmall, [iBig]
+ ) # by trade because by conquest may raze the city
+ flipUnitsInCityAfter(tCity, iSmall)
+ iCounter += 1
+ if iCounter == 3:
+ break
+
+
+def fragmentBarbarians(iGameTurn):
+ iRndnum = rand(civilizations().majors().len())
+ for j in civilizations().majors().ids():
+ iDeadCiv = (j + iRndnum) % civilizations().majors().len()
+ if (
+ not gc.getPlayer(iDeadCiv).isAlive()
+ and iGameTurn > civilization(iDeadCiv).date.birth + 50
+ ):
+ lCities = [
+ location(city)
+ for city in (
+ plots.rectangle(
+ civilization(iDeadCiv).location.area[AreaType.NORMAL][Area.TILE_MIN],
+ civilization(iDeadCiv).location.area[AreaType.NORMAL][Area.TILE_MAX],
+ )
+ .cities()
+ .owner(Civ.BARBARIAN)
+ .entities()
+ )
+ ]
+ if len(lCities) > 5:
+ iDivideCounter = 0
+ for tCity in lCities:
+ iNewCiv = min(civilizations().independents().ids()) + rand(
+ max(civilizations().independents().ids())
+ - min(civilizations().independents().ids())
+ + 1
+ )
+ if iDivideCounter % 4 in [0, 1]:
+ cultureManager(tCity, 50, iNewCiv, Civ.BARBARIAN, False, True, True)
+ flipUnitsInCityBefore(tCity, iNewCiv, Civ.BARBARIAN)
+ setTempFlippingCity(tCity)
+ flipCity(
+ tCity, 0, 0, iNewCiv, [Civ.BARBARIAN]
+ ) # by trade because by conquest may raze the city
+ flipUnitsInCityAfter(tCity, iNewCiv)
+ iDivideCounter += 1
+ return
+
+
+def initBirth(iCurrentTurn, iBirthYear, iCiv):
+ iHuman = human()
+ if iCurrentTurn == iBirthYear - 1 + getSpawnDelay(iCiv) + getFlipsDelay(iCiv):
+ tCapital = civilization(iCiv).location.capital
+ core_tile_min = civilization(iCiv).location.area[AreaType.CORE][Area.TILE_MIN]
+ core_tile_max = civilization(iCiv).location.area[AreaType.CORE][Area.TILE_MAX]
+ broader_tile_min = civilization(iCiv).location.area[AreaType.BROADER][Area.TILE_MIN]
+ broader_tile_max = civilization(iCiv).location.area[AreaType.BROADER][Area.TILE_MAX]
+ if getFlipsDelay(iCiv) == 0: # city hasn't already been founded
+
+ # Absinthe: for the human player, kill all foreign units on the capital plot - this probably fixes a couple instances of the -1 turn autoplay bug
+ if iCiv == iHuman:
+ killPlot = gc.getMap().plot(tCapital[0], tCapital[1])
+ iNumUnitsInAPlot = killPlot.getNumUnits()
+ if iNumUnitsInAPlot > 0:
+ iSkippedUnit = 0
+ for i in range(iNumUnitsInAPlot):
+ unit = killPlot.getUnit(iSkippedUnit)
+ if unit.getOwner() != iCiv:
+ unit.kill(False, Civ.BARBARIAN)
+ else:
+ iSkippedUnit += 1
+
+ # Absinthe: if the plot is owned by a civ, bDeleteEverything becomes True unless there is a human city in the 1+8 neighbour plots.
+ bDeleteEverything = False
+ if gc.getMap().plot(tCapital[0], tCapital[1]).isOwned():
+ if iCiv == iHuman or not gc.getPlayer(iHuman).isAlive():
+ bDeleteEverything = True
+ else:
+ bDeleteEverything = True
+ if plots.surrounding(tCapital).cities().owner(iHuman).entities():
+ bDeleteEverything = False
+
+ if not gc.getMap().plot(tCapital[0], tCapital[1]).isOwned():
+ birthInFreeRegion(iCiv, tCapital, core_tile_min, core_tile_max)
+ elif bDeleteEverything:
+ setDeleteMode(0, iCiv)
+ # Absinthe: kill off units near the starting plot
+ killAllUnitsInArea(
+ (tCapital[0] - 1, tCapital[1] - 1), (tCapital[0] + 1, tCapital[1] + 1)
+ )
+ for plot in plots.surrounding(tCapital).entities():
+ if plot.isCity():
+ plot.eraseAIDevelopment() # new function, similar to erase but won't delete rivers, resources and features
+ for civ in civilizations().ids():
+ if iCiv != civ:
+ plot.setCulture(civ, 0, True)
+ plot.setOwner(-1)
+ birthInFreeRegion(iCiv, tCapital, core_tile_min, core_tile_max)
+ else:
+ birthInForeignBorders(
+ iCiv,
+ core_tile_min,
+ core_tile_max,
+ broader_tile_min,
+ broader_tile_max,
+ tCapital,
+ )
+ else:
+ birthInFreeRegion(iCiv, tCapital, core_tile_min, core_tile_max)
+
+ # 3MiroCrusader modification. Crusaders cannot change nations.
+ # Sedna17: Straight-up no switching within 40 turns of your birth
+ if iCurrentTurn == iBirthYear + getSpawnDelay(iCiv):
+ if (
+ gc.getPlayer(iCiv).isAlive()
+ and not getAlreadySwitched()
+ and iCurrentTurn > civilization(iHuman).date.birth + 40
+ and not gc.getPlayer(iHuman).getIsCrusader()
+ ):
+ newCivPopup(iCiv)
+
+
+@handler("BeginPlayerTurn")
+def deleteMode(iGameTurn, iCurrentPlayer):
+ iCiv = getDeleteMode(0)
+ if iCiv != -1:
+ tCapital = civilization(iCiv).location.capital
+ if iCurrentPlayer == iCiv:
+ for plot in plots.surrounding(tCapital, radius=2).entities():
+ plot.setCulture(iCiv, 300, True)
+ for plot in plots.surrounding(tCapital).entities():
+ convertPlotCulture(plot, iCiv, 100, True)
+ if plot.getCulture(iCiv) < 3000:
+ # 2000 in vanilla/warlords, cos here Portugal is choked by Spanish culture
+ plot.setCulture(iCiv, 3000, True)
+ plot.setOwner(iCiv)
+ setDeleteMode(0, -1)
+ return
+
+ if iCurrentPlayer != iCiv - 1:
+ return
+
+ for plot in plots.surrounding(tCapital).entities():
+ if plot.isOwned():
+ for iLoopCiv in civilizations().ids():
+ if iLoopCiv != iCiv:
+ plot.setCulture(iLoopCiv, 0, True)
+ plot.setOwner(iCiv)
+
+
+def birthInFreeRegion(iCiv, tCapital, tTopLeft, tBottomRight):
+ startingPlot = gc.getMap().plot(tCapital[0], tCapital[1])
+ if getFlipsDelay(iCiv) == 0:
+ iFlipsDelay = getFlipsDelay(iCiv) + 2
+
+ if iFlipsDelay > 0:
+ # Absinthe: kill off units near the starting plot
+ killAllUnitsInArea(
+ (tCapital[0] - 1, tCapital[1] - 1), (tCapital[0] + 1, tCapital[1] + 1)
+ )
+ createStartingUnits(iCiv, (tCapital[0], tCapital[1]))
+ reveal_areas(iCiv)
+ set_initial_contacts(iCiv)
+ # Absinthe: there was another mistake here with barbarian and indy unit flips...
+ # we don't simply want to check an area based on distance from capital, as it might lead out from the actual spawn area
+ # so we only check plots which are in the core area: in 4 distance for barb units, 2 distance for indies
+ lPlotBarbFlip = []
+ lPlotIndyFlip = []
+ # if inside the core rectangle and extra plots, and in 4 (barb) or 2 (indy) distance from the starting plot, append to barb or indy flip zone
+
+ lSurroundingPlots4 = [
+ location(plot) for plot in plots.surrounding(tCapital, radius=4).entities()
+ ]
+ lSurroundingPlots2 = [
+ location(plot) for plot in plots.surrounding(tCapital, radius=2).entities()
+ ]
+ for tPlot in (
+ plots.rectangle(tTopLeft, tBottomRight)
+ .add(civilization(iCiv).location.area[AreaType.CORE][Area.ADDITIONAL_TILES])
+ .apply(location) # TODO fix this with _keyify by default
+ ):
+ if tPlot in lSurroundingPlots2:
+ lPlotIndyFlip.append(tPlot)
+ lPlotBarbFlip.append(tPlot)
+ elif tPlot in lSurroundingPlots4:
+ lPlotBarbFlip.append(tPlot)
+ # remaining barbs in the region: killed for the human player, flipped for the AI
+ if iCiv == human():
+ killUnitsInPlots(lPlotBarbFlip, Civ.BARBARIAN)
+ else:
+ flipUnitsInPlots(lPlotBarbFlip, iCiv, Civ.BARBARIAN, True, True)
+ for iIndyCiv in civilizations().independents().ids():
+ # remaining independents in the region: killed for the human player, flipped for the AI
+ if iCiv == human():
+ killUnitsInPlots(lPlotIndyFlip, iIndyCiv)
+ else:
+ flipUnitsInPlots(lPlotIndyFlip, iCiv, iIndyCiv, True, False)
+ set_starting_techs(iCiv)
+ setPlagueCountdown(iCiv, -PLAGUE_IMMUNITY)
+ clearPlague(iCiv)
+ setFlipsDelay(iCiv, iFlipsDelay) # save
+
+ else: # starting units have already been placed, now the second part
+ iNumAICitiesConverted, iNumHumanCitiesToConvert = convertSurroundingCities(
+ iCiv, tTopLeft, tBottomRight
+ )
+ convertSurroundingPlotCulture(iCiv, tTopLeft, tBottomRight)
+ if iCiv != human():
+ flipUnitsInArea(
+ tTopLeft, tBottomRight, iCiv, Civ.BARBARIAN, False, True
+ ) # remaining barbs in the region now belong to the new civ
+ flipUnitsInPlots(
+ civilization(iCiv).location.area[AreaType.CORE][Area.ADDITIONAL_TILES],
+ iCiv,
+ Civ.BARBARIAN,
+ False,
+ True,
+ ) # remaining barbs in the region now belong to the new civ
+ for iIndyCiv in civilizations().independents().ids():
+ if iCiv != human():
+ flipUnitsInArea(
+ tTopLeft, tBottomRight, iCiv, iIndyCiv, False, False
+ ) # remaining independents in the region now belong to the new civ
+ flipUnitsInPlots(
+ civilization(iCiv).location.area[AreaType.CORE][Area.ADDITIONAL_TILES],
+ iCiv,
+ iIndyCiv,
+ False,
+ False,
+ ) # remaining independents in the region now belong to the new civ
+ # cover plots revealed by the catapult
+ plotZero = gc.getMap().plot(32, 0) # sync with rfcebalance module
+ if plotZero.getNumUnits():
+ catapult = plotZero.getUnit(0)
+ catapult.kill(False, iCiv)
+ gc.getMap().plot(31, 0).setRevealed(iCiv, False, True, -1)
+ gc.getMap().plot(32, 0).setRevealed(iCiv, False, True, -1)
+ gc.getMap().plot(33, 0).setRevealed(iCiv, False, True, -1)
+ gc.getMap().plot(31, 1).setRevealed(iCiv, False, True, -1)
+ gc.getMap().plot(32, 1).setRevealed(iCiv, False, True, -1)
+ gc.getMap().plot(33, 1).setRevealed(iCiv, False, True, -1)
+
+ if gc.getPlayer(iCiv).getNumCities() > 0:
+ capital = gc.getPlayer(iCiv).getCapitalCity()
+ create_starting_workers(iCiv, (capital.getX(), capital.getY()))
+ if iCiv == Civ.OTTOMAN:
+ ottoman_invasion(iCiv, (77, 23))
+
+ if iNumHumanCitiesToConvert > 0:
+ flipPopup(iCiv, tTopLeft, tBottomRight)
+
+
+def birthInForeignBorders(
+ iCiv, tTopLeft, tBottomRight, tBroaderTopLeft, tBroaderBottomRight, tCapital
+):
+ iNumAICitiesConverted, iNumHumanCitiesToConvert = convertSurroundingCities(
+ iCiv, tTopLeft, tBottomRight
+ )
+ convertSurroundingPlotCulture(iCiv, tTopLeft, tBottomRight)
+
+ # now starting units must be placed
+ if iNumAICitiesConverted > 0:
+ # Absinthe: there is an issue that core area is not calculated correctly for flips, as the additional tiles in lExtraPlots are not checked here
+ # so if all flipped cities are outside of the core area (they are in the "exceptions"), the civ will start without it's starting units and techs
+ plotList = squareSearch(tTopLeft, tBottomRight, ownedCityPlots, iCiv)
+ # Absinthe: add the exception plots
+ for plot in civilization(iCiv).location.area[AreaType.CORE][Area.ADDITIONAL_TILES]:
+ plot = gc.getMap().plot(*plot)
+ if plot.getOwner() == iCiv:
+ if plot.isCity():
+ plotList.append(plot)
+ if plotList:
+ plot = choice(plotList)
+ createStartingUnits(iCiv, plot)
+ reveal_areas(iCiv)
+ set_initial_contacts(iCiv)
+ set_starting_techs(iCiv)
+ setPlagueCountdown(iCiv, -PLAGUE_IMMUNITY)
+ clearPlague(iCiv)
+ flipUnitsInArea(
+ tTopLeft, tBottomRight, iCiv, Civ.BARBARIAN, False, True
+ ) # remaining barbs in the region now belong to the new civ
+ flipUnitsInPlots(
+ civilization(iCiv).location.area[AreaType.CORE][Area.ADDITIONAL_TILES],
+ iCiv,
+ Civ.BARBARIAN,
+ False,
+ True,
+ ) # remaining barbs in the region now belong to the new civ
+ for iIndyCiv in civilizations().independents().ids():
+ flipUnitsInArea(
+ tTopLeft, tBottomRight, iCiv, iIndyCiv, False, False
+ ) # remaining independents in the region now belong to the new civ
+ flipUnitsInPlots(
+ civilization(iCiv).location.area[AreaType.CORE][Area.ADDITIONAL_TILES],
+ iCiv,
+ iIndyCiv,
+ False,
+ False,
+ ) # remaining independents in the region now belong to the new civ
+
+ else:
+ # Absinthe: there is an issue that core area is not calculated correctly for flips, as the additional tiles in lExtraPlots are not checked here
+ # so if all flipped cities are outside of the core area (they are in the "exceptions"), the civ will start without it's starting units and techs
+ plotList = squareSearch(tTopLeft, tBottomRight, goodPlots, [])
+ # Absinthe: add the exception plots
+ for plot in civilization(iCiv).location.area[AreaType.CORE][Area.ADDITIONAL_TILES]:
+ plot = gc.getMap().plot(*plot)
+ if (plot.isHills() or plot.isFlatlands()) and not plot.isImpassable():
+ if not plot.isUnit():
+ if plot.getTerrainType() not in [
+ Terrain.DESERT,
+ Terrain.TUNDRA,
+ ] and plot.getFeatureType() not in [
+ Feature.MARSH,
+ Feature.JUNGLE,
+ ]:
+ if plot.countTotalCulture() == 0:
+ plotList.append(plot)
+ if plotList:
+ plot = choice(plotList)
+ createStartingUnits(iCiv, plot)
+ reveal_areas(iCiv)
+ set_initial_contacts(iCiv)
+ set_starting_techs(iCiv)
+ setPlagueCountdown(iCiv, -PLAGUE_IMMUNITY)
+ clearPlague(iCiv)
+ else:
+ plotList = squareSearch(tBroaderTopLeft, tBroaderBottomRight, goodPlots, [])
+ if plotList:
+ plot = choice(plotList)
+ createStartingUnits(iCiv, plot)
+ reveal_areas(iCiv)
+ set_initial_contacts(iCiv)
+ create_starting_workers(iCiv, plot)
+ if iCiv == Civ.OTTOMAN:
+ ottoman_invasion(iCiv, (77, 23))
+ set_starting_techs(iCiv)
+ setPlagueCountdown(iCiv, -PLAGUE_IMMUNITY)
+ clearPlague(iCiv)
+ flipUnitsInArea(
+ tTopLeft, tBottomRight, iCiv, Civ.BARBARIAN, True, True
+ ) # remaining barbs in the region now belong to the new civ
+ flipUnitsInPlots(
+ civilization(iCiv).location.area[AreaType.CORE][Area.ADDITIONAL_TILES],
+ iCiv,
+ Civ.BARBARIAN,
+ True,
+ True,
+ ) # remaining barbs in the region now belong to the new civ
+ for iIndyCiv in civilizations().independents().ids():
+ flipUnitsInArea(
+ tTopLeft, tBottomRight, iCiv, iIndyCiv, True, False
+ ) # remaining independents in the region now belong to the new civ
+ flipUnitsInPlots(
+ civilization(iCiv).location.area[AreaType.CORE][Area.ADDITIONAL_TILES],
+ iCiv,
+ iIndyCiv,
+ True,
+ False,
+ ) # remaining independents in the region now belong to the new civ
+
+ if iNumHumanCitiesToConvert > 0:
+ flipPopup(iCiv, tTopLeft, tBottomRight)
+
+
+def convertSurroundingCities(iCiv, tTopLeft, tBottomRight):
+ iConvertedCitiesCount = 0
+ iNumHumanCities = 0
+ setSpawnWar(0)
+
+ # collect all the cities in the spawn region
+ for city in (
+ plots.rectangle(tTopLeft, tBottomRight)
+ .add(civilization(iCiv).location.area[AreaType.CORE][Area.ADDITIONAL_TILES])
+ .cities()
+ .not_owner(iCiv)
+ .entities()
+ ):
+ # if 0, no flip; if > 0, flip will occur with the value as variable for CultureManager()
+ iCultureChange = 0
+
+ if is_minor_civ(city):
+ iCultureChange = 100
+ # case 2: human city
+ elif city.getOwner() == human() and not city.isCapital():
+ if iNumHumanCities == 0:
+ iNumHumanCities += 1
+ # case 3: other
+ elif not city.isCapital(): # 3Miro: this keeps crashing in the C++, makes no sense
+ if iConvertedCitiesCount < 6: # there won't be more than 5 flips in the area
+ iCultureChange = 50
+ if turn() <= civilization(iCiv).date.birth + 5: # if we're during a birth
+ rndNum = percentage()
+ # 3Miro: I don't know why the iOwner check is needed below, but the module crashes sometimes
+ if is_major_civ(city) and rndNum >= civilization(city).ai.stop_birth_threshold:
+ if not civilization(iCiv).at_war(city):
+ civilization(iCiv).declare_war(city)
+ if player(iCiv).getNumCities() > 0:
+ if location(player(iCiv).getCapitalCity()) != (-1, -1):
+ # this check is needed, otherwise game crashes
+ createAdditionalUnits(iCiv, player(iCiv).getCapitalCity())
+ else:
+ createAdditionalUnits(
+ iCiv, civilization(iCiv).location.capital
+ )
+
+ if iCultureChange > 0:
+ cultureManager(
+ location(city), iCultureChange, iCiv, city.getOwner(), True, False, False
+ )
+ flipUnitsInCityBefore(location(city), iCiv, city.getOwner())
+ setTempFlippingCity(location(city)) # necessary for the (688379128, 0) bug
+ flipCity(location(city), 0, 0, iCiv, [city.getOwner()])
+ flipUnitsInCityAfter(getTempFlippingCity(), iCiv)
+ iConvertedCitiesCount += 1
+
+ if iConvertedCitiesCount > 0:
+ if player(iCiv).isHuman():
+ message(iCiv, text("TXT_KEY_FLIP_TO_US"), force=True, color=MessageData.GREEN)
+ return (iConvertedCitiesCount, iNumHumanCities)
+
+
+def convertSurroundingPlotCulture(iCiv, tTopLeft, tBottomRight):
+ for plot in (
+ plots.rectangle(tTopLeft, tBottomRight)
+ .add(civilization(iCiv).location.area[AreaType.CORE][Area.ADDITIONAL_TILES])
+ .filter(lambda p: not p.isCity())
+ .entities()
+ ):
+ convertPlotCulture(plot, iCiv, 100, False)
+
+
+def findSeaPlots(tCoords, iRange):
+ """Searches a sea plot that isn't occupied by a unit within range of the starting coordinates"""
+ # we can search inside other players territory, since all naval units can cross sea borders
+ seaPlotList = [
+ location(plot)
+ for plot in (
+ plots.surrounding(tCoords, radius=iRange)
+ .water()
+ .filter(lambda p: not p.isUnit())
+ .entities()
+ )
+ ]
+ # this is a good plot, so paint it and continue search
+ if seaPlotList:
+ return choice(seaPlotList)
+ return None
+
+
+def getSpecialRespawn(
+ iGameTurn,
+): # Absinthe: only the first civ for which it is True is returned, so the order of the civs is very important here
+ if canSpecialRespawn(Civ.FRANCE, iGameTurn, 12):
+ # France united in it's modern borders, start of the Bourbon royal line
+ if year(1588) < iGameTurn < year(1700) and iGameTurn % 5 == 3:
+ return Civ.FRANCE
+ if canSpecialRespawn(Civ.ARABIA, iGameTurn):
+ # Saladin, Ayyubid Dynasty
+ if year(1080) < iGameTurn < year(1291) and iGameTurn % 7 == 3:
+ return Civ.ARABIA
+ if canSpecialRespawn(Civ.BULGARIA, iGameTurn):
+ # second Bulgarian Empire
+ if year(1080) < iGameTurn < year(1299) and iGameTurn % 5 == 1:
+ return Civ.BULGARIA
+ if canSpecialRespawn(Civ.CORDOBA, iGameTurn):
+ # special respawn as the Hafsid dynasty in North Africa
+ if year(1229) < iGameTurn < year(1540) and iGameTurn % 5 == 3:
+ return Civ.CORDOBA
+ if canSpecialRespawn(Civ.BURGUNDY, iGameTurn, 20):
+ # Burgundy in the 100 years war
+ if year(1336) < iGameTurn < year(1453) and iGameTurn % 8 == 1:
+ return Civ.BURGUNDY
+ if canSpecialRespawn(Civ.PRUSSIA, iGameTurn):
+ # respawn as the unified Prussia
+ if iGameTurn > year(1618) and iGameTurn % 3 == 1:
+ return Civ.PRUSSIA
+ if canSpecialRespawn(Civ.HUNGARY, iGameTurn):
+ # reconquest of Buda from the Ottomans
+ if iGameTurn > year(1680) and iGameTurn % 6 == 2:
+ return Civ.HUNGARY
+ if canSpecialRespawn(Civ.CASTILE, iGameTurn, 25):
+ # respawn as the Castile/Aragon Union
+ if year(1470) < iGameTurn < year(1580) and iGameTurn % 5 == 0:
+ return Civ.CASTILE
+ if canSpecialRespawn(Civ.ENGLAND, iGameTurn, 12):
+ # restoration of monarchy
+ if iGameTurn > year(1660) and iGameTurn % 6 == 2:
+ return Civ.ENGLAND
+ if canSpecialRespawn(Civ.SCOTLAND, iGameTurn, 30):
+ if iGameTurn <= year(1600) and iGameTurn % 6 == 3:
+ return Civ.SCOTLAND
+ if canSpecialRespawn(Civ.PORTUGAL, iGameTurn):
+ # respawn to be around for colonies
+ if year(1431) < iGameTurn < year(1580) and iGameTurn % 5 == 3:
+ return Civ.PORTUGAL
+ if canSpecialRespawn(Civ.AUSTRIA, iGameTurn):
+ # increasing Habsburg influence in Hungary
+ if year(1526) < iGameTurn < year(1690) and iGameTurn % 8 == 3:
+ return Civ.AUSTRIA
+ if canSpecialRespawn(Civ.KIEV, iGameTurn):
+ # Cossack Hetmanate
+ if year(1620) < iGameTurn < year(1750) and iGameTurn % 5 == 3:
+ return Civ.KIEV
+ if canSpecialRespawn(Civ.MOROCCO, iGameTurn):
+ # Alaouite Dynasty
+ if iGameTurn > year(1631) and iGameTurn % 8 == 7:
+ return Civ.MOROCCO
+ if canSpecialRespawn(Civ.ARAGON, iGameTurn):
+ # Kingdom of Sicily
+ if iGameTurn > year(1700) and iGameTurn % 8 == 7:
+ return Civ.ARAGON
+ if canSpecialRespawn(Civ.VENECIA, iGameTurn):
+ if year(1401) < iGameTurn < year(1571) and iGameTurn % 8 == 7:
+ return Civ.VENECIA
+ if canSpecialRespawn(Civ.POLAND, iGameTurn):
+ if year(1410) < iGameTurn < year(1570) and iGameTurn % 8 == 7:
+ return Civ.POLAND
+ if canSpecialRespawn(Civ.OTTOMAN, iGameTurn):
+ # Mehmed II's conquests
+ if year(1453) < iGameTurn < year(1514) and iGameTurn % 6 == 3:
+ return Civ.OTTOMAN
+ return -1
+
+
+def canSpecialRespawn(iPlayer, iGameTurn, iLastAliveInterval=10):
+ pPlayer = gc.getPlayer(iPlayer)
+ if pPlayer.isAlive():
+ return False
+ if pPlayer.getEverRespawned():
+ return False
+ if iGameTurn <= civilization(iPlayer).date.birth + 25:
+ return False
+ if iGameTurn <= (getLastTurnAlive(iPlayer) + iLastAliveInterval):
+ return False
+ return True
+
+
+def initMinorBetrayal(iCiv):
+ iHuman = human()
+ plotList = squareSearch(
+ civilization(iCiv).location.area[AreaType.CORE][Area.TILE_MIN],
+ civilization(iCiv).location.area[AreaType.CORE][Area.TILE_MAX],
+ outerInvasion,
+ [],
+ )
+ if plotList:
+ tPlot = choice(plotList)
+ createAdditionalUnits(iCiv, tPlot)
+ unitsBetrayal(
+ iCiv,
+ iHuman,
+ civilization(iCiv).location.area[AreaType.CORE][Area.TILE_MIN],
+ civilization(iCiv).location.area[AreaType.CORE][Area.TILE_MAX],
+ tPlot,
+ )
+
+
+def initBetrayal():
+ iHuman = human()
+ turnsLeft = getBetrayalTurns()
+ plotList = squareSearch(getTempTopLeft(), getTempBottomRight(), outerInvasion, [])
+ if not plotList:
+ plotList = squareSearch(
+ getTempTopLeft(),
+ getTempBottomRight(),
+ innerSpawn,
+ [getOldCivFlip(), getNewCivFlip()],
+ )
+ if not plotList:
+ plotList = squareSearch(
+ getTempTopLeft(),
+ getTempBottomRight(),
+ forcedInvasion,
+ [getOldCivFlip(), getNewCivFlip()],
+ )
+ if plotList:
+ tPlot = choice(plotList)
+ if turnsLeft == iBetrayalPeriod:
+ createAdditionalUnits(getNewCivFlip(), tPlot)
+ unitsBetrayal(
+ getNewCivFlip(),
+ getOldCivFlip(),
+ getTempTopLeft(),
+ getTempBottomRight(),
+ tPlot,
+ )
+ setBetrayalTurns(turnsLeft - 1)
+
+
+def unitsBetrayal(iNewOwner, iOldOwner, tTopLeft, tBottomRight, tPlot):
+ if gc.getPlayer(getOldCivFlip()).isHuman():
+ message(getOldCivFlip(), text("TXT_KEY_FLIP_BETRAYAL"), color=MessageData.RED)
+ elif gc.getPlayer(getNewCivFlip()).isHuman():
+ message(getNewCivFlip(), text("TXT_KEY_FLIP_BETRAYAL_NEW"), color=MessageData.GREEN)
+ for unit in plots.rectangle(tTopLeft, tBottomRight).units().owner(iOldOwner).entities():
+ if percentage_chance(iBetrayalThreshold, reverse=True):
+ if unit.getDomainType() == DomainTypes.DOMAIN_LAND:
+ iUnitType = unit.getUnitType()
+ unit.kill(False, iNewOwner)
+ make_unit(iNewOwner, iUnitType, tPlot)
+ i = i - 1
+
+
+def createAdditionalUnits(iCiv, tPlot):
+ # additional starting units if someone declares war on the civ during birth
+ units = civilization(iCiv).initial.get("additional_units")
+ if units is not None:
+ if iCiv != human():
+ for unit, number in units.get(PlayerType.AI, {}).items():
+ make_units(iCiv, unit, tPlot, number)
+ else:
+ for unit, number in units.get(PlayerType.HUMAN, {}).items():
+ make_units(iCiv, unit, tPlot, number)
+
+
+def createStartingUnits(iCiv, tPlot):
+ # set the provinces
+ Provinces.onSpawn(iCiv)
+
+ units = civilization(iCiv).initial.get("units")
+ if units is not None:
+ for unit, number in units.get(PlayerType.ANY, {}).items():
+ make_units(iCiv, unit, tPlot, number)
+
+ if iCiv != human():
+ for unit, number in units.get(PlayerType.AI, {}).items():
+ make_units(iCiv, unit, tPlot, number)
+ else:
+ for unit, number in units.get(PlayerType.HUMAN, {}).items():
+ make_units(iCiv, unit, tPlot, number)
+
+ if iCiv == Civ.VENECIA:
+ tSeaPlot = findSeaPlots((57, 35), 2)
+ if tSeaPlot:
+ make_unit(iCiv, Unit.WORKBOAT, tSeaPlot)
+ make_unit(iCiv, Unit.GALLEY, tSeaPlot, UnitAITypes.UNITAI_SETTLER_SEA)
+ make_unit(iCiv, Unit.GALLEY, tSeaPlot, UnitAITypes.UNITAI_ESCORT_SEA)
+ make_unit(iCiv, Unit.SETTLER, tSeaPlot)
+ make_unit(iCiv, Unit.ARCHER, tSeaPlot)
+ make_unit(iCiv, Unit.GALLEY, tSeaPlot, UnitAITypes.UNITAI_SETTLER_SEA)
+ make_unit(iCiv, Unit.SETTLER, tSeaPlot)
+ make_unit(iCiv, Unit.SPEARMAN, tSeaPlot)
+ elif iCiv == Civ.NORWAY:
+ tSeaPlot = findSeaPlots(tPlot, 2)
+ if tSeaPlot:
+ make_unit(iCiv, Unit.GALLEY, tSeaPlot, UnitAITypes.UNITAI_SETTLER_SEA)
+ make_unit(iCiv, Unit.GALLEY, tSeaPlot, UnitAITypes.UNITAI_ESCORT_SEA)
+ make_unit(iCiv, Unit.GALLEY, tSeaPlot, UnitAITypes.UNITAI_ESCORT_SEA)
+ make_unit(iCiv, Unit.SETTLER, tSeaPlot)
+ make_unit(iCiv, Unit.ARCHER, tSeaPlot)
+ elif iCiv == Civ.DENMARK:
+ tSeaPlot = findSeaPlots((60, 57), 2)
+ if tSeaPlot:
+ make_unit(iCiv, Unit.GALLEY, tSeaPlot, UnitAITypes.UNITAI_SETTLER_SEA)
+ make_unit(iCiv, Unit.GALLEY, tSeaPlot, UnitAITypes.UNITAI_SETTLER_SEA)
+ make_unit(iCiv, Unit.GALLEY, tSeaPlot, UnitAITypes.UNITAI_ESCORT_SEA)
+ make_unit(iCiv, Unit.SETTLER, tSeaPlot)
+ make_unit(iCiv, Unit.CROSSBOWMAN, tSeaPlot)
+ make_unit(iCiv, Unit.SETTLER, tSeaPlot)
+ make_unit(iCiv, Unit.CROSSBOWMAN, tSeaPlot)
+ elif iCiv == Civ.GENOA:
+ tSeaPlot = findSeaPlots(tPlot, 2)
+ if tSeaPlot:
+ make_unit(iCiv, Unit.GALLEY, tSeaPlot, UnitAITypes.UNITAI_SETTLER_SEA)
+ make_unit(iCiv, Unit.WAR_GALLEY, tSeaPlot, UnitAITypes.UNITAI_ESCORT_SEA)
+ make_unit(iCiv, Unit.SETTLER, tSeaPlot)
+ make_unit(iCiv, Unit.CROSSBOWMAN, tSeaPlot)
+ make_unit(iCiv, Unit.WORKBOAT, tSeaPlot)
+ elif iCiv == Civ.ENGLAND:
+ tSeaPlot = findSeaPlots((43, 53), 1)
+ if tSeaPlot:
+ make_unit(iCiv, Unit.GALLEY, tSeaPlot, UnitAITypes.UNITAI_SETTLER_SEA)
+ make_unit(iCiv, Unit.WAR_GALLEY, tSeaPlot, UnitAITypes.UNITAI_ESCORT_SEA)
+ elif iCiv == Civ.ARAGON:
+ tSeaPlot = findSeaPlots((42, 29), 1)
+ if tSeaPlot:
+ make_units(iCiv, Unit.WAR_GALLEY, tSeaPlot, 2, UnitAITypes.UNITAI_ESCORT_SEA)
+ make_unit(iCiv, Unit.COGGE, tSeaPlot, UnitAITypes.UNITAI_SETTLER_SEA)
+ make_unit(iCiv, Unit.SETTLER, tSeaPlot)
+ make_unit(iCiv, Unit.CROSSBOWMAN, tSeaPlot)
+ make_unit(iCiv, Unit.WORKBOAT, tSeaPlot)
+ elif iCiv == Civ.SWEDEN:
+ tSeaPlot = findSeaPlots((69, 65), 2)
+ if tSeaPlot:
+ make_unit(iCiv, Unit.WORKBOAT, tSeaPlot)
+ make_unit(iCiv, Unit.WAR_GALLEY, tSeaPlot, UnitAITypes.UNITAI_ESCORT_SEA)
+ make_units(iCiv, Unit.COGGE, tSeaPlot, 2, UnitAITypes.UNITAI_SETTLER_SEA)
+ make_unit(iCiv, Unit.SETTLER, tSeaPlot)
+ make_unit(iCiv, Unit.ARBALEST, tSeaPlot)
+ elif iCiv == Civ.DUTCH:
+ tSeaPlot = findSeaPlots(tPlot, 2)
+ if tSeaPlot:
+ make_units(iCiv, Unit.WORKBOAT, tSeaPlot, 2)
+ make_units(iCiv, Unit.GALLEON, tSeaPlot, 2)
diff --git a/Assets/Python/Rules.py b/Assets/Python/Rules.py
new file mode 100644
index 000000000..b41fe8c99
--- /dev/null
+++ b/Assets/Python/Rules.py
@@ -0,0 +1,87 @@
+import Barbs
+from Core import civilizations, location, player, plot
+from CoreTypes import Building, Improvement
+from Events import handler
+from RFCUtils import getUniqueBuilding, spreadMajorCulture
+
+iImpBeforeCity = 0
+
+
+@handler("cityBuilt")
+def spread_culture(city):
+ iOwner = city.getOwner()
+ if iOwner < civilizations().majors().len():
+ spreadMajorCulture(iOwner, city.getX(), city.getY())
+
+
+@handler("cityBuilt")
+def remove_minor_cultures(city):
+ # Rhye - delete culture of barbs and minor civs to prevent weird unhappiness
+ for civ in civilizations().minors().ids():
+ plot(city).setCulture(civ, 0, True)
+
+
+@handler("improvementDestroyed")
+def onImprovementDestroyed(iImprovement, iOwner, iX, iY):
+ # Absinthe: Free walls if city is built on a fort
+ # This is a hack for it, checking what was the improvement before the city was built
+ # Saving the improvement type and coordinates here as a global variable, and accessing later in the onCityBuilt function
+ global iImpBeforeCity
+ iImpBeforeCity = 10000 * iImprovement + 100 * iX + 1 * iY
+
+
+@handler("cityBuilt")
+def free_building_when_city_built_over_improvement(city):
+ # Absinthe: Free buildings if city is built on a tile improvement
+ # The problem is that the improvement is auto-destroyed before the city is founded, and totally separately from this function,
+ # thus a workaround is needed
+ # Solution: getting the coordinates of the last destroyed improvement from a different file in a global variable
+ # If the last destroyed improvement in the game is a fort, and it was in the same place as the city, then it's good enough for me
+ # (only problem might be if currently there is no improvement on the city-founding tile, but the last destroyed improvement in the game
+ # was a fort on the exact same plot some turns ago - but IMO that's not much of a stress of reality, there was a fort there after all)
+ # Note that CvEventManager.iImpBeforeCity needs to have some initial value if a city is founded before the first destroyed improvement
+ # adding an improvement in the scenario map to one of the preplaced Byzantine cities won't work perfectly:
+ # while the improvement will be autorazed on the beginning of the 1st players turn when starting in 500AD, does nothing if you load a saved game
+
+ iOwner = city.getOwner()
+ tCity = (city.getX(), city.getY())
+ iImpBeforeCityType = (iImpBeforeCity / 10000) % 100
+ iImpBeforeCityX = (iImpBeforeCity / 100) % 100
+ iImpBeforeCityY = iImpBeforeCity % 100
+ # Absinthe: free walls if built on fort
+ if iImpBeforeCityType == Improvement.FORT and (iImpBeforeCityX, iImpBeforeCityY) == tCity:
+ city.setHasRealBuilding(getUniqueBuilding(iOwner, Building.WALLS), True)
+ # Absinthe: free granary if built on hamlet
+ if iImpBeforeCityType == Improvement.HAMLET and (iImpBeforeCityX, iImpBeforeCityY) == tCity:
+ city.setHasRealBuilding(getUniqueBuilding(iOwner, Building.GRANARY), True)
+ # Absinthe: free granary and +1 population if built on village or town
+ if iImpBeforeCityType in [Improvement.TOWN, Improvement.VILLAGE]:
+ if (iImpBeforeCityX, iImpBeforeCityY) == tCity:
+ city.changePopulation(1)
+ city.setHasRealBuilding(getUniqueBuilding(iOwner, Building.GRANARY), True)
+
+
+@handler("cityBuilt")
+def free_food_on_city_built(city):
+ # Absinthe: Some initial food for all cities on foundation
+ # So Leon and Roskilde for example don't lose a population in the first couple turns
+ # Nor the indy cities on spawn (they start with zero-sized culture, so they shrink without some food reserves)
+ # Currently 1/5 of the treshold of the next population growth
+ city.setFood(city.growthThreshold() / 5)
+
+
+@handler("unitPillage")
+def spawn_barbs_when_pillage_cottage(pUnit, iImprovement, iRoute, iOwner):
+ if plot(pUnit).countTotalCulture() == 0:
+ if Improvement.COTTAGE <= iImprovement <= Improvement.TOWN:
+ Barbs.onImprovementDestroyed(location(pUnit))
+
+
+@handler("unitPillage")
+def reduce_stability_with_pillage(pUnit, iImprovement, iRoute, iOwner):
+ # TODO only when same religion?
+ # TODO make announce?
+ owner = pUnit.getOwner()
+ if owner > -1 and owner < civilizations().majors().len():
+ pPlayer = player(owner)
+ pPlayer.setStabilitySwing(pPlayer.getStabilitySwing() - 2)
diff --git a/Assets/Python/components/Secession.py b/Assets/Python/Secession.py
similarity index 97%
rename from Assets/Python/components/Secession.py
rename to Assets/Python/Secession.py
index 4b7246cf1..06b01d424 100644
--- a/Assets/Python/components/Secession.py
+++ b/Assets/Python/Secession.py
@@ -1,7 +1,7 @@
from CvPythonExtensions import CyGlobalContext, WarPlanTypes
from Consts import MessageData
-from Core import civilization, civilizations, message, human, cities, text
+from Core import civilization, civilizations, cities, message_if_human, text
from CoreTypes import ProvinceType, StabilityCategory, UniquePower
from PyUtils import chance, rand, choice
from RFCUtils import (
@@ -71,7 +71,7 @@ def revoltCity(iPlayer, bForce):
cityListInCore = []
cityListInNotCore = []
- for city in cities().owner(iPlayer).entities():
+ for city in cities.owner(iPlayer).entities():
tCity = (city.getX(), city.getY())
x, y = tCity
pCurrent = gc.getMap().plot(city.getX(), city.getY())
@@ -232,13 +232,12 @@ def revoltCity(iPlayer, bForce):
tCity = (splittingCity.getX(), splittingCity.getY())
sCityName = splittingCity.getName()
- if iPlayer == human():
- message(
- iPlayer,
- sCityName + " " + text("TXT_KEY_STABILITY_SECESSION"),
- force=True,
- color=MessageData.ORANGE,
- )
+ message_if_human(
+ iPlayer,
+ sCityName + " " + text("TXT_KEY_STABILITY_SECESSION"),
+ force=True,
+ color=MessageData.ORANGE,
+ )
cultureManager(tCity, 50, iIndy, iPlayer, False, True, True)
flipUnitsInCitySecession(tCity, iIndy, iPlayer)
setTempFlippingCity(tCity)
diff --git a/Assets/Python/Locations.py b/Assets/Python/Setup.py
similarity index 59%
rename from Assets/Python/Locations.py
rename to Assets/Python/Setup.py
index 0eeece4af..bc0a9499f 100644
--- a/Assets/Python/Locations.py
+++ b/Assets/Python/Setup.py
@@ -1,133 +1,135 @@
-from CvPythonExtensions import CyGlobalContext
-from Consts import WORLD_HEIGHT, WORLD_WIDTH
-from Core import (
- civilizations,
- get_data_from_upside_down_map,
- get_data_from_province_map,
- location,
- plot as _plot,
- location as _location,
- plots,
-)
-from CoreTypes import Area, AreaType, Civ, PlagueType, ProvinceType, Religion, Technology
-from LocationsData import LAKE_LOCATIONS
-from CityMapData import CITIES_MAP
-from ProvinceMapData import PROVINCES_MAP
-from SettlerMapData import SETTLERS_MAP
-from WarMapData import WARS_MAP
-
-gc = CyGlobalContext()
-
-
-def init():
- """Run in Handlers when the game starts."""
- init_player_variables()
- init_provinces()
- set_province_type_parameters()
-
-
-def setup():
- init_player_maps()
- update_province_id()
- update_city_name()
- update_lake_id()
- update_core()
- set_vizualization_areas()
-
-
-def init_player_variables():
- gc.setSizeNPlayers(
- WORLD_WIDTH,
- WORLD_HEIGHT,
- civilizations().majors().len(),
- civilizations().drop(Civ.BARBARIAN).len(),
- len(Technology),
- PlagueType.BUILDING_PLAGUE,
- len(Religion),
- )
- # set the Number of Provinces, call this before you set any AI or culture modifiers
- gc.setProvinceTypeNumber(len(ProvinceType))
-
-
-def init_player_maps():
- for civ in civilizations().majors():
- for plot in plots().all().entities():
- x, y = location(plot)
- gc.setSettlersMap(civ.id, y, x, SETTLERS_MAP[civ.key][y][x])
- gc.setWarsMap(civ.id, y, x, WARS_MAP[civ.key][y][x])
-
-
-def init_provinces():
- # for plot in plots().all().filter(lambda p: get_data_from_province_map(p) > -1).entities():
- for y in range(WORLD_HEIGHT):
- for x in range(WORLD_WIDTH):
- if PROVINCES_MAP[y][x] > -1:
- gc.setProvince(x, y, PROVINCES_MAP[y][x])
- gc.createProvinceCrossreferenceList()
-
-
-def set_province_type_parameters():
- # How much culture should we get into a province of this type, ignore the war and settler values (0,0)
- gc.setProvinceTypeParams(ProvinceType.NONE, 0, 0, 1, 3) # 1/3 culture
- gc.setProvinceTypeParams(ProvinceType.CONTESTED, 0, 0, 1, 1) # no change to culture
- gc.setProvinceTypeParams(ProvinceType.POTENTIAL, 0, 0, 1, 1) # same as outer culture
- gc.setProvinceTypeParams(ProvinceType.HISTORICAL, 0, 0, 2, 1) # double-culture
- gc.setProvinceTypeParams(ProvinceType.CORE, 0, 0, 3, 1) # triple-culture
-
-
-def update_province_id():
- for plot in plots().all().entities():
- plot.setProvinceID(get_data_from_province_map(plot))
-
-
-def update_city_name():
- for civ in civilizations().main():
- for plot in plots().all().entities():
- value = get_data_from_upside_down_map(CITIES_MAP, civ.id, plot)
- _plot(plot).setCityNameMap(civ.id, value)
-
-
-def update_lake_id():
- for plot in plots().all().entities():
- for name, locations in LAKE_LOCATIONS.items():
- if _location(plot) in locations:
- value = name
- else:
- value = -1
- plot.setLakeNameID(value)
-
-
-def update_core():
- for civ in civilizations().majors():
- core_tile_min = civ.location.area[AreaType.CORE][Area.TILE_MIN]
- core_tile_max = civ.location.area[AreaType.CORE][Area.TILE_MAX]
- core_additional_tiles = civ.location.area[AreaType.CORE][Area.ADDITIONAL_TILES]
- normal_tile_min = civ.location.area[AreaType.NORMAL][Area.TILE_MIN]
- normal_tile_max = civ.location.area[AreaType.NORMAL][Area.TILE_MAX]
- normal_exception_tiles = civ.location.area[AreaType.NORMAL][Area.EXCEPTION_TILES]
- gc.setCoreNormal(
- civ.id,
- core_tile_min[0],
- core_tile_min[1],
- core_tile_max[0],
- core_tile_max[1],
- normal_tile_min[0],
- normal_tile_min[1],
- normal_tile_max[0],
- normal_tile_max[1],
- len(core_additional_tiles),
- len(normal_exception_tiles),
- )
- for tile in core_additional_tiles:
- gc.addCoreException(civ.id, *tile)
- for tile in normal_exception_tiles:
- gc.addNormalException(civ.id, *tile)
-
-
-def set_vizualization_areas():
- # Absinthe: separate visualization function for spawn and respawn areas
- # set it to 1 in the GlobalDefines_Alt.xml if you want to enable it
- # hold down the shift key, and hover over the map
- # hold down the alt key, and hover over the map
- gc.setCoreToPlot(gc.getDefineINT("ENABLE_SPAWN_AREA_DISPLAY"))
- gc.setNormalToPlot(gc.getDefineINT("ENABLE_RESPAWN_AREA_DISPLAY"))
+from CvPythonExtensions import CyGlobalContext
+from CityNameManager import renameCities
+from CoreTypes import Civ, Scenario, Area, AreaType
+from PyUtils import rand
+from StoredData import data
+from Events import handler
+from Consts import iLighthouseEarthQuake, iByzantiumVikingAttack
+from Core import (
+ civilizations,
+ get_scenario,
+ get_data_from_upside_down_map,
+ get_data_from_province_map,
+ location,
+ log,
+ plot as _plot,
+ location as _location,
+ plots,
+ cities,
+)
+from LocationsData import LAKE_LOCATIONS
+from CityMapData import CITIES_MAP
+from SettlerMapData import SETTLERS_MAP
+from WarMapData import WARS_MAP
+
+gc = CyGlobalContext()
+
+
+@handler("GameStart")
+def setup_gamestart():
+ setup()
+
+
+@handler("OnLoad")
+def setup_on_load():
+ setup()
+
+
+def setup():
+ init_player_maps()
+ update_core()
+ set_vizualization_areas()
+ update_province_id()
+ update_city_name()
+ update_lake_id()
+ set_random_event()
+ rename_cities_1200AD()
+ refresh_dynamic_civ_name()
+ log("RFCE: Setup.setup()")
+
+
+def init_player_maps():
+ for civ in civilizations().majors():
+ for plot in plots.all().entities():
+ x, y = location(plot)
+ gc.setSettlersMap(civ.id, y, x, SETTLERS_MAP[civ.key][y][x])
+ gc.setWarsMap(civ.id, y, x, WARS_MAP[civ.key][y][x])
+
+
+def update_province_id():
+ for plot in plots.all().entities():
+ plot.setProvinceID(get_data_from_province_map(plot))
+
+
+def update_city_name():
+ for civ in civilizations().main():
+ for plot in plots.all().entities():
+ value = get_data_from_upside_down_map(CITIES_MAP, civ.id, plot)
+ _plot(plot).setCityNameMap(civ.id, value)
+
+
+def update_lake_id():
+ for plot in plots.all().entities():
+ for name, locations in LAKE_LOCATIONS.items():
+ if _location(plot) in locations:
+ value = name
+ else:
+ value = -1
+ plot.setLakeNameID(value)
+
+
+def update_core():
+ for civ in civilizations().majors():
+ core_tile_min = civ.location.area[AreaType.CORE][Area.TILE_MIN]
+ core_tile_max = civ.location.area[AreaType.CORE][Area.TILE_MAX]
+ core_additional_tiles = civ.location.area[AreaType.CORE][Area.ADDITIONAL_TILES]
+ normal_tile_min = civ.location.area[AreaType.NORMAL][Area.TILE_MIN]
+ normal_tile_max = civ.location.area[AreaType.NORMAL][Area.TILE_MAX]
+ normal_exception_tiles = civ.location.area[AreaType.NORMAL][Area.EXCEPTION_TILES]
+ gc.setCoreNormal(
+ civ.id,
+ core_tile_min[0],
+ core_tile_min[1],
+ core_tile_max[0],
+ core_tile_max[1],
+ normal_tile_min[0],
+ normal_tile_min[1],
+ normal_tile_max[0],
+ normal_tile_max[1],
+ len(core_additional_tiles),
+ len(normal_exception_tiles),
+ )
+ for tile in core_additional_tiles:
+ gc.addCoreException(civ.id, *tile)
+ for tile in normal_exception_tiles:
+ gc.addNormalException(civ.id, *tile)
+
+
+def set_vizualization_areas():
+ # Absinthe: separate visualization function for spawn and respawn areas
+ # set it to 1 in the GlobalDefines_Alt.xml if you want to enable it
+ # hold down the shift key, and hover over the map
+ # hold down the alt key, and hover over the map
+ gc.setCoreToPlot(gc.getDefineINT("ENABLE_SPAWN_AREA_DISPLAY"))
+ gc.setNormalToPlot(gc.getDefineINT("ENABLE_RESPAWN_AREA_DISPLAY"))
+
+
+def set_random_event():
+ # Absinthe: generate and store randomized turn modifiers
+ data.lEventRandomness[iLighthouseEarthQuake] = rand(40)
+ data.lEventRandomness[iByzantiumVikingAttack] = rand(10)
+
+
+def rename_cities_1200AD():
+ # Absinthe: rename cities on the 1200AD scenario - the WB file cannot handle special chars and long names properly
+ # some of the cities intentionally have different names though (compared to the CNM), for example some Kievan cities
+ # thus it's only set for Hungary for now, we can add more civs/cities later on if there are naming issues
+ if get_scenario() == Scenario.i1200AD:
+ for city in cities.owner(Civ.HUNGARY).entities():
+ renameCities(city, Civ.HUNGARY)
+
+
+def refresh_dynamic_civ_name():
+ # Absinthe: refresh Dynamic Civ Names for all civs on the initial turn of the given scenario
+ for iPlayer in civilizations().majors().ids():
+ gc.getPlayer(iPlayer).processCivNames()
diff --git a/Assets/Python/Shortcuts.py b/Assets/Python/Shortcuts.py
new file mode 100644
index 000000000..43af90cba
--- /dev/null
+++ b/Assets/Python/Shortcuts.py
@@ -0,0 +1,127 @@
+from CvPythonExtensions import *
+from Core import human, make_unit, player
+from CoreTypes import Civ, Unit
+import CvMercenaryManager
+import CvScreenEnums
+from Events import events, handler
+from ProvinceMapData import PROVINCES_MAP
+from RFCUtils import getProvinceStabilityLevel
+
+gc = CyGlobalContext()
+lastProvinceID = -1
+mercenaryManager = CvMercenaryManager.CvMercenaryManager(CvScreenEnums.MERCENARY_MANAGER)
+
+
+@handler("kbdEvent")
+def display_mercenary_manager_with_key_shortcut(eventType, key, mx, my, px, py):
+ key = int(key)
+ if player().isAlive():
+ if (
+ events.bCtrl
+ and eventType == events.EventKeyDown
+ and key == int(InputTypes.KB_M)
+ and gc.getActivePlayer().getNumCities() > 0
+ ):
+ mercenaryManager.interfaceScreen()
+
+
+@handler("kbdEvent")
+def print_plots_debug(eventType, key, mx, my, px, py):
+ key = int(key)
+ if events.bAlt and eventType == events.EventKeyDown and key == int(InputTypes.KB_N):
+ events.printPlotsDebug()
+
+
+@handler("kbdEvent")
+def autoplay_dead_civ(eventType, key, mx, my, px, py):
+ key = int(key)
+ if (
+ events.bAlt
+ and events.bShift
+ and eventType == events.EventKeyDown
+ and key == int(InputTypes.KB_E)
+ ):
+ # picks a dead civ so that autoplay can be started with game.AIplay xx
+ iDebugDeadCiv = Civ.BURGUNDY # always dead in 500AD
+ make_unit(iDebugDeadCiv, Unit.AXEMAN, (0, 0))
+ gc.getGame().setActivePlayer(iDebugDeadCiv, False)
+ gc.getPlayer(iDebugDeadCiv).setPlayable(True)
+
+
+@handler("kbdEvent")
+def province_highlight(eventType, key, mx, my, px, py):
+ global lastProvinceID
+ key = int(key)
+ if (
+ events.bCtrl
+ and not events.bAlt
+ and eventType == events.EventKeyDown
+ and px >= 0
+ and py >= 0
+ and int(key) == 45
+ ):
+
+ plot = gc.getMap().plot(px, py)
+ iActivePlayer = gc.getGame().getActivePlayer()
+ iActiveTeam = gc.getPlayer(iActivePlayer).getTeam()
+ iProvinceID = PROVINCES_MAP[plot.getY()][plot.getX()]
+
+ # do not show provinces of unrevealed tiles
+ if not plot.isRevealed(iActiveTeam, False) and not gc.getGame().isDebugMode():
+ return
+
+ # do not redraw if already drawn
+ if lastProvinceID == iProvinceID:
+ return
+
+ map = CyMap()
+ engine = CyEngine()
+
+ # clear the highlight
+ engine.clearAreaBorderPlots(AreaBorderLayers.AREA_BORDER_LAYER_HIGHLIGHT_PLOT)
+
+ # cache the plot's coords
+ lastProvinceID = PROVINCES_MAP[plot.getY()][plot.getX()]
+
+ # select an appropriate color
+ if PROVINCES_MAP[plot.getY()][plot.getX()] == -1: # ocean and non-province tiles
+ return
+ else:
+ iLevel = getProvinceStabilityLevel(human(), iProvinceID)
+ if iLevel == 4:
+ color = gc.getColorInfo(gc.getInfoTypeForString("COLOR_HIGHLIGHT_CORE")).getColor()
+ elif iLevel == 3:
+ color = gc.getColorInfo(
+ gc.getInfoTypeForString("COLOR_HIGHLIGHT_NATURAL")
+ ).getColor()
+ elif iLevel == 2:
+ color = gc.getColorInfo(
+ gc.getInfoTypeForString("COLOR_HIGHLIGHT_POTENTIAL")
+ ).getColor()
+ elif iLevel == 1:
+ color = gc.getColorInfo(
+ gc.getInfoTypeForString("COLOR_HIGHLIGHT_BORDER")
+ ).getColor()
+ else:
+ color = gc.getColorInfo(
+ gc.getInfoTypeForString("COLOR_HIGHLIGHT_FOREIGN")
+ ).getColor()
+
+ # apply the highlight
+ for i in range(map.numPlots()):
+ plot = map.plotByIndex(i)
+ if PROVINCES_MAP[plot.getY()][plot.getX()] == iProvinceID and (
+ gc.getGame().isDebugMode() or plot.isRevealed(iActiveTeam, False)
+ ):
+ engine.fillAreaBorderPlot(
+ plot.getX(),
+ plot.getY(),
+ color,
+ AreaBorderLayers.AREA_BORDER_LAYER_HIGHLIGHT_PLOT,
+ )
+
+ return
+
+ if eventType == events.EventKeyUp and events.bCtrl or eventType == events.EventKeyDown:
+ CyEngine().clearAreaBorderPlots(AreaBorderLayers.AREA_BORDER_LAYER_HIGHLIGHT_PLOT)
+ lastProvinceID = -1
diff --git a/Assets/Python/Stability.py b/Assets/Python/Stability.py
new file mode 100644
index 000000000..7de54def9
--- /dev/null
+++ b/Assets/Python/Stability.py
@@ -0,0 +1,1025 @@
+# Rhye's and Fall of Civilization: Europe - Stability
+
+from CvPythonExtensions import *
+from Core import get_scenario, civilization, civilizations, message, human, cities, text, turn
+from Consts import MessageData
+from CoreTypes import (
+ Building,
+ Civ,
+ Civic,
+ Project,
+ Scenario,
+ Religion,
+ FaithPointBonusCategory,
+ ProvinceType,
+ SpecialParameter,
+ UniquePower,
+ StabilityCategory,
+ Technology,
+ Wonder,
+)
+from PyUtils import percentage_chance, rand
+from ProvinceMapData import PROVINCES_MAP
+from RFCUtils import collapseImmune, getLastRespawnTurn, getUniqueBuilding, killAndFragmentCiv
+from Provinces import updatePotential
+from Secession import revoltCity
+from Events import handler
+
+gc = CyGlobalContext()
+
+tStabilityPenalty = (-5, -2, 0, 0, 0) # province type: unstable, border, potential, historic, core
+
+
+@handler("GameStart")
+def setup():
+ for iPlayer in civilizations().majors().ids():
+ pPlayer = gc.getPlayer(iPlayer)
+ for iCath in range(4):
+ pPlayer.changeStabilityBase(iCath, -pPlayer.getStabilityBase(iCath))
+ pPlayer.setStabilityVary(iCath, 0)
+ pPlayer.setStabilitySwing(0)
+ # Absinthe: bonus stability for the human player based on difficulty level
+ iHandicap = gc.getGame().getHandicapType()
+ if iHandicap == 0:
+ gc.getPlayer(human()).changeStabilityBase(StabilityCategory.EXPANSION, 6)
+ elif iHandicap == 1:
+ gc.getPlayer(human()).changeStabilityBase(StabilityCategory.EXPANSION, 2)
+
+ # Absinthe: Stability is accounted properly for stuff preplaced in the scenario file - from RFCE++
+ for iPlayer in civilizations().majors().ids():
+ pPlayer = gc.getPlayer(iPlayer)
+ teamPlayer = gc.getTeam(pPlayer.getTeam())
+ iCounter = 0
+ for pCity in cities.owner(iPlayer).entities():
+ iCounter += 1
+ iOldStab = pPlayer.getStability()
+
+ # Province stability
+ iProv = PROVINCES_MAP[pCity.getY()][pCity.getX()]
+ iProvinceType = pPlayer.getProvinceType(iProv)
+ if iProvinceType == ProvinceType.CORE:
+ pPlayer.changeStabilityBase(StabilityCategory.EXPANSION, 1)
+ elif not gc.hasUP(
+ iPlayer, UniquePower.STABILITY_BONUS_FOUNDING
+ ): # no instability with the Settler UP
+ if iProvinceType == ProvinceType.CONTESTED:
+ pPlayer.changeStabilityBase(StabilityCategory.EXPANSION, -1)
+ elif iProvinceType == ProvinceType.NONE:
+ pPlayer.changeStabilityBase(StabilityCategory.EXPANSION, -2)
+
+ # Building stability: only a chance for these, as all the permanent negative stability modifiers are missing up to the start
+ if pCity.hasBuilding(
+ getUniqueBuilding(iPlayer, Building.MANOR_HOUSE)
+ ) and percentage_chance(70, strict=True):
+ pPlayer.changeStabilityBase(StabilityCategory.ECONOMY, 1)
+ if pCity.hasBuilding(
+ getUniqueBuilding(iPlayer, Building.CASTLE)
+ ) and percentage_chance(70, strict=True):
+ pPlayer.changeStabilityBase(StabilityCategory.EXPANSION, 1)
+ if pCity.hasBuilding(
+ getUniqueBuilding(iPlayer, Building.NIGHT_WATCH)
+ ) and percentage_chance(70, strict=True):
+ pPlayer.changeStabilityBase(StabilityCategory.CIVICS, 1)
+ if pCity.hasBuilding(
+ getUniqueBuilding(iPlayer, Building.COURTHOUSE)
+ ) and percentage_chance(70, strict=True):
+ pPlayer.changeStabilityBase(StabilityCategory.CITIES, 1)
+
+ # Small boost for small civs
+ if iCounter < 6: # instead of the additional boost for the first few cities
+ pPlayer.changeStabilityBase(StabilityCategory.EXPANSION, (6 - iCounter) / 2 + 1)
+
+ # Known techs which otherwise give instability should also give the penalty here
+ for iTech in [
+ Technology.FEUDALISM,
+ Technology.GUILDS,
+ Technology.GUNPOWDER,
+ Technology.PROFESSIONAL_ARMY,
+ Technology.NATIONALISM,
+ Technology.CIVIL_SERVICE,
+ Technology.ECONOMICS,
+ Technology.MACHINERY,
+ Technology.ARISTOCRACY,
+ ]:
+ if teamPlayer.isHasTech(iTech):
+ gc.getPlayer(iPlayer).changeStabilityBase(StabilityCategory.ECONOMY, -1)
+
+ # Absinthe: update all potential provinces at the start for all living players (needed for the scenario)
+ if pPlayer.isAlive():
+ updatePotential(iPlayer)
+
+ # Absinthe: AI stability bonus - for civs that have a hard time at the beginning
+ # for example France, Arabia, Bulgaria, Cordoba, Ottomans
+ for iPlayer in civilizations().main().ids():
+ pPlayer = gc.getPlayer(iPlayer)
+ if iPlayer != human():
+ pPlayer.changeStabilityBase(
+ StabilityCategory.EXPANSION, civilization(iPlayer).ai.stability_bonus
+ )
+
+ # Absinthe: update Byzantine stability on the start of the game
+ if get_scenario() == Scenario.i500AD:
+ # small stability boost for the human player for the first UHV
+ if Civ.BYZANTIUM == human():
+ pByzantium = gc.getPlayer(Civ.BYZANTIUM)
+ pByzantium.changeStabilityBase(StabilityCategory.EXPANSION, 4)
+ recalcEpansion(Civ.BYZANTIUM)
+
+
+def recalcEpansion(iPlayer):
+ pPlayer = gc.getPlayer(iPlayer)
+ iExpStability = 0
+ iCivic5 = pPlayer.getCivics(5)
+ bIsUPLandStability = gc.hasUP(iPlayer, UniquePower.LESS_INSTABILITY_WITH_FOREIGN_LAND)
+ iCivicBonus = 0
+ iUPBonus = 0
+ for pCity in cities.owner(iPlayer).entities():
+ iProvType = pPlayer.getProvinceType(pCity.getProvince())
+ iProvNum = pCity.getProvince()
+ CityName = pCity.getNameKey()
+ assert 0 <= iProvType < len(tStabilityPenalty), (
+ "Bad ProvinceType value for CityName (%s)" % CityName
+ )
+
+ iExpStability += tStabilityPenalty[iProvType]
+ if iProvType <= ProvinceType.CONTESTED:
+ if iCivic5 == Civic.IMPERIALISM: # Imperialism
+ iCivicBonus += 1
+ if bIsUPLandStability: # French UP
+ iUPBonus += 1
+ iExpStability += iCivicBonus # Imperialism
+ iExpStability += iUPBonus # French UP
+ if pPlayer.getCivics(5) != Civic.OCCUPATION:
+ iExpStability -= 3 * pPlayer.getForeignCitiesInMyProvinceType(
+ ProvinceType.CORE
+ ) # -3 stability for each foreign/enemy city in your core provinces, without the Militarism civic
+ iExpStability -= 1 * pPlayer.getForeignCitiesInMyProvinceType(
+ ProvinceType.HISTORICAL
+ ) # -1 stability for each foreign/enemy city in your natural provinces, without the Militarism civic
+ if pPlayer.getMaster() > -1:
+ iExpStability += 8
+ if iCivic5 == Civic.VASSALAGE:
+ iExpStability += 3 * pPlayer.countVassals()
+ else:
+ iExpStability += pPlayer.countVassals()
+ iNumCities = pPlayer.getNumCities()
+ if iPlayer in [Civ.OTTOMAN, Civ.MOSCOW]: # five free cities for those two
+ iNumCities = max(0, iNumCities - 5)
+ iExpStability -= iNumCities * iNumCities / 40
+ pPlayer.setStabilityVary(StabilityCategory.EXPANSION, iExpStability)
+
+
+@handler("BeginGameTurn")
+def checkTurn(iGameTurn):
+ # Absinthe: logging AI stability levels
+ if iGameTurn % 9 == 2:
+ for iPlayer in civilizations().main().ids():
+ pPlayer = gc.getPlayer(iPlayer)
+ if pPlayer.getStability() != 0:
+ print(
+ "AI stability check:",
+ pPlayer.getCivilizationDescription(0),
+ pPlayer.getStability(),
+ )
+
+
+@handler("BeginPlayerTurn")
+def updateBaseStability(iGameTurn, iPlayer):
+ # Base stability is temporary (i.e. turn-based) stability
+ # 3Miro: this is called for every player
+ if gc.getPlayer(iPlayer).isAlive() and iPlayer < civilizations().majors().len():
+ if gc.getPlayer(iPlayer).getNumCities() > 0:
+ pPlayer = gc.getPlayer(iPlayer)
+ # Swing stability converges to zero very fast
+ iStabilitySwing = pPlayer.getStabilitySwing()
+ if iStabilitySwing < -3 or iStabilitySwing > 3:
+ pPlayer.setStabilitySwing(pPlayer.getStabilitySwing() / 2)
+ elif iStabilitySwing < 0:
+ pPlayer.setStabilitySwing(min(0, pPlayer.getStabilitySwing() + 2))
+ elif iStabilitySwing > 0:
+ pPlayer.setStabilitySwing(max(0, pPlayer.getStabilitySwing() - 2))
+
+ # Absinthe: Anarchy swing stability gets halved every turn
+ iStabSwingAnarchy = pPlayer.getStabSwingAnarchy()
+ if iStabSwingAnarchy > 1:
+ pPlayer.setStabSwingAnarchy(pPlayer.getStabSwingAnarchy() / 2)
+ elif iStabSwingAnarchy == 1:
+ pPlayer.setStabSwingAnarchy(0)
+
+ # Absinthe: anarchy timer refreshes later in the turn, so it should be reduced by 1 if we want to have it on the correct turns (if nothing else then for the human player)
+ # but this also means that all 1st turn instability has to be added directly on the revolution / converting - CvPlayer::revolution and CvPlayer::convert
+ if pPlayer.getAnarchyTurns() - 1 > 0:
+ recalcCivicCombos(iPlayer)
+ recalcEpansion(iPlayer)
+ iNumCities = pPlayer.getNumCities()
+
+ if iPlayer != Civ.PRUSSIA: # Absinthe: Prussian UP
+ if pPlayer.isHuman():
+ # Absinthe: anarchy base instability
+ pPlayer.changeStabilityBase(
+ StabilityCategory.CIVICS, min(0, max(-2, (-iNumCities + 4) / 7))
+ ) # 0 with 1-4 cities, -1 with 5-11 cities, -2 with at least 12 cities
+
+ # Absinthe: more constant swing instability during anarchy, instead of ever-increasing instability from it
+ iStabSwingAnarchy = pPlayer.getStabSwingAnarchy()
+ if (
+ iStabSwingAnarchy > 0
+ ): # half of it is already included in the swing, we only add the other half
+ pPlayer.setStabSwingAnarchy(4)
+ else: # safety net (should be positive, as we add it before the first check)
+ pPlayer.setStabSwingAnarchy(8)
+ pPlayer.setStabilitySwing(
+ pPlayer.getStabilitySwing() - pPlayer.getStabSwingAnarchy()
+ )
+
+ else:
+ # Absinthe: anarchy base instability
+ pPlayer.changeStabilityBase(
+ StabilityCategory.CIVICS, min(0, max(-1, (-iNumCities + 6) / 7))
+ ) # Absinthe: reduced for the AI: 0 with 1-6 cities, -1 with at least 7
+
+ # Absinthe: more constant swing instability during anarchy, instead of ever-increasing instability from it
+ iStabSwingAnarchy = pPlayer.getStabSwingAnarchy()
+ if (
+ iStabSwingAnarchy > 0
+ ): # half of it is already included in the swing, we only add the other half
+ pPlayer.setStabSwingAnarchy(2)
+ else: # safety net (should be positive, as we add it before the first check)
+ pPlayer.setStabSwingAnarchy(4)
+ pPlayer.setStabilitySwing(
+ pPlayer.getStabilitySwing() - pPlayer.getStabSwingAnarchy()
+ )
+
+ if (
+ pPlayer.getWarPeaceChange() == -1
+ ): # Whenever your nation switches from peace to the state of war (with a major nation)
+ gc.getPlayer(iPlayer).changeStabilityBase(
+ StabilityCategory.CITIES, -1
+ ) # 1 permanent stability loss, since your people won't appreciate leaving the state of peace
+ pPlayer.setStabilitySwing(pPlayer.getStabilitySwing() - 3)
+
+ if (iGameTurn + iPlayer) % 3 == 0: # Economy Check every 3 turns
+ recalcEconomy(iPlayer)
+
+ recalcCity(iPlayer) # update city stability
+
+ # Absinthe: Collapse dates for AI nations
+ if (
+ iGameTurn > civilization(iPlayer).date.collapse
+ and iPlayer != human()
+ and pPlayer.isAlive()
+ ):
+ # Absinthe: -1 stability every 4 turns up to a total of -15 stability
+ if iGameTurn % 4 == 0 and iGameTurn <= civilization(iPlayer).date.collapse + 60:
+ pPlayer.changeStabilityBase(StabilityCategory.CITIES, -1)
+
+
+def refreshBaseStability(iPlayer): # Base stability is temporary (i.e. turn-based) stability
+ # Absinthe: this is called upon entering the stability/finance screen (F2)
+
+ pPlayer = gc.getPlayer(iPlayer)
+
+ recalcCivicCombos(iPlayer)
+ recalcEpansion(iPlayer)
+ recalcEconomy(iPlayer)
+ recalcCity(iPlayer)
+
+
+def continentsNormalization(iGameTurn): # Sedna17
+ pass
+
+
+@handler("cityBuilt")
+def onCityBuilt(city):
+ iPlayer = city.getOwner()
+ if iPlayer < civilizations().majors().len():
+ x, y = city.getX(), city.getY()
+ iProv = PROVINCES_MAP[y][x]
+ pPlayer = gc.getPlayer(iPlayer)
+ # Absinthe: +1 for core, -1 for contested, -2 for foreign provinces
+ iProvinceType = pPlayer.getProvinceType(iProv)
+ if iProvinceType == ProvinceType.CORE:
+ pPlayer.changeStabilityBase(StabilityCategory.EXPANSION, 1)
+ elif not gc.hasUP(
+ iPlayer, UniquePower.STABILITY_BONUS_FOUNDING
+ ): # no instability with the Settler UP
+ if iProvinceType == ProvinceType.CONTESTED:
+ pPlayer.changeStabilityBase(StabilityCategory.EXPANSION, -1)
+ elif iProvinceType == ProvinceType.NONE:
+ pPlayer.changeStabilityBase(StabilityCategory.EXPANSION, -2)
+ if pPlayer.getNumCities() < 5: # early boost to small civs
+ pPlayer.changeStabilityBase(StabilityCategory.EXPANSION, 1)
+ recalcEpansion(iPlayer)
+ recalcCivicCombos(iPlayer)
+
+
+@handler("cityAcquired")
+def onCityAcquired(iOwner, playerType, city, bConquest, bTrade):
+ pOwner = gc.getPlayer(iOwner)
+ pConq = gc.getPlayer(playerType)
+
+ if city.hasBuilding(Wonder.ESCORIAL):
+ pConq.setPicklefreeParameter(SpecialParameter.HAS_ESCORIAL, 1)
+ pOwner.setPicklefreeParameter(SpecialParameter.HAS_ESCORIAL, 0)
+ if city.hasBuilding(Wonder.STEPHANSDOM):
+ pConq.setPicklefreeParameter(SpecialParameter.HAS_STEPHANSDOM, 1)
+ pOwner.setPicklefreeParameter(SpecialParameter.HAS_STEPHANSDOM, 0)
+ if city.hasBuilding(Wonder.SHRINE_OF_UPPSALA):
+ pConq.setPicklefreeParameter(SpecialParameter.HAS_UPPSALA_SHRINE, 1)
+ pOwner.setPicklefreeParameter(SpecialParameter.HAS_UPPSALA_SHRINE, 0)
+ if city.hasBuilding(Wonder.KOUTOUBIA_MOSQUE):
+ pConq.setPicklefreeParameter(SpecialParameter.HAS_KOUTOUBIA_MOSQUE, 1)
+ pOwner.setPicklefreeParameter(SpecialParameter.HAS_KOUTOUBIA_MOSQUE, 0)
+ if city.hasBuilding(Wonder.MAGNA_CARTA):
+ pConq.setPicklefreeParameter(SpecialParameter.HAS_MAGNACARTA, 1)
+ pOwner.setPicklefreeParameter(SpecialParameter.HAS_MAGNACARTA, 0)
+
+ recalcCivicCombos(playerType)
+ recalcCivicCombos(iOwner)
+ iProv = city.getProvince()
+ iProvOwnerType = pOwner.getProvinceType(iProv)
+ iProvConqType = pConq.getProvinceType(iProv)
+
+ if iProvOwnerType >= ProvinceType.HISTORICAL:
+ if iOwner == Civ.SCOTLAND: # Scotland UP part 2
+ pOwner.changeStabilityBase(StabilityCategory.EXPANSION, -2)
+ pOwner.setStabilitySwing(pOwner.getStabilitySwing() - 2)
+ else:
+ pOwner.changeStabilityBase(StabilityCategory.EXPANSION, -3)
+ pOwner.setStabilitySwing(pOwner.getStabilitySwing() - 4)
+ elif iProvOwnerType < ProvinceType.HISTORICAL:
+ if iOwner == Civ.SCOTLAND: # Scotland UP part 2
+ pOwner.setStabilitySwing(pOwner.getStabilitySwing() - 1)
+ else:
+ pOwner.setStabilitySwing(pOwner.getStabilitySwing() - 2)
+
+ if iProvConqType >= ProvinceType.HISTORICAL:
+ pConq.changeStabilityBase(StabilityCategory.EXPANSION, 1)
+ pConq.setStabilitySwing(pConq.getStabilitySwing() + 3)
+
+ if pConq.getCivics(5) == Civic.OCCUPATION:
+ pConq.changeStabilityBase(StabilityCategory.EXPANSION, 1)
+
+ if (
+ iOwner < civilizations().majors().len()
+ and (city.getX(), city.getY()) == civilization(iOwner).location.capital
+ ):
+ if iOwner == Civ.SCOTLAND: # Scotland UP part 2
+ pOwner.changeStabilityBase(StabilityCategory.EXPANSION, -5)
+ pOwner.setStabilitySwing(pOwner.getStabilitySwing() - 5)
+ elif gc.hasUP(
+ iOwner, UniquePower.NO_COLLAPSE_IN_CORE_AND_NORMAL_AREAS
+ ): # If Byzantium loses Constantinople, they should lose all non-core cities
+ pOwner.changeStabilityBase(StabilityCategory.EXPANSION, -20)
+ pOwner.setStabilitySwing(pOwner.getStabilitySwing() - 20)
+ else:
+ pOwner.changeStabilityBase(StabilityCategory.EXPANSION, -10)
+ pOwner.setStabilitySwing(pOwner.getStabilitySwing() - 10)
+ recalcEpansion(iOwner)
+ recalcEpansion(playerType)
+
+
+@handler("cityRazed")
+def onCityRazed(city, iPlayer):
+ iPreviousOwner = city.getOwner()
+ if iPreviousOwner == iPlayer and city.getPreviousOwner() != -1:
+ iPreviousOwner = city.getPreviousOwner()
+
+ pPlayer = gc.getPlayer(iPlayer)
+ pPreviousOwner = gc.getPlayer(iPreviousOwner)
+ if city.hasBuilding(Wonder.ESCORIAL):
+ pPlayer.setPicklefreeParameter(SpecialParameter.HAS_ESCORIAL, 1)
+ pPreviousOwner.setPicklefreeParameter(SpecialParameter.HAS_ESCORIAL, 0)
+ if city.hasBuilding(Wonder.STEPHANSDOM):
+ pPlayer.setPicklefreeParameter(SpecialParameter.HAS_STEPHANSDOM, 1)
+ pPreviousOwner.setPicklefreeParameter(SpecialParameter.HAS_STEPHANSDOM, 0)
+ if city.hasBuilding(Wonder.SHRINE_OF_UPPSALA):
+ pPlayer.setPicklefreeParameter(SpecialParameter.HAS_UPPSALA_SHRINE, 1)
+ pPreviousOwner.setPicklefreeParameter(SpecialParameter.HAS_UPPSALA_SHRINE, 0)
+ if city.hasBuilding(Wonder.KOUTOUBIA_MOSQUE):
+ pPlayer.setPicklefreeParameter(SpecialParameter.HAS_KOUTOUBIA_MOSQUE, 1)
+ pPreviousOwner.setPicklefreeParameter(SpecialParameter.HAS_KOUTOUBIA_MOSQUE, 0)
+ if city.hasBuilding(Wonder.MAGNA_CARTA):
+ pPlayer.setPicklefreeParameter(SpecialParameter.HAS_MAGNACARTA, 1)
+ pPreviousOwner.setPicklefreeParameter(SpecialParameter.HAS_MAGNACARTA, 0)
+ recalcCivicCombos(iPlayer)
+ recalcCivicCombos(iPreviousOwner)
+
+ # Absinthe: city razing penalty - permanent, based on city population
+ # note that the city is already reduced by 1 on city conquest, so city.getPopulation() is one less than the original size
+ # so currently: 0 with 1-2 population, -1 with 3-5 population, -2 with 6-9 population, -3 with 10+ population
+ iRazeStab = 0
+ if city.getPopulation() >= 9:
+ iRazeStab = 3
+ elif city.getPopulation() >= 5:
+ iRazeStab = 2
+ elif city.getPopulation() >= 2:
+ iRazeStab = 1
+ # Absinthe: Norwegian UP - one less stability penalty
+ if iPlayer == Civ.NORWAY:
+ iRazeStab -= 1
+ if iRazeStab > 0:
+ pPlayer.changeStabilityBase(StabilityCategory.EXPANSION, -iRazeStab)
+ # temporary, 3 for everyone but Norway
+ if iPlayer != Civ.NORWAY:
+ pPlayer.setStabilitySwing(pPlayer.getStabilitySwing() - 3)
+ recalcEpansion(iPlayer)
+
+
+@handler("techAcquired")
+def onTechAcquired(iTech, iTeam, iPlayer):
+ if (
+ gc.getPlayer(iPlayer).isAlive()
+ and turn() > civilization(iPlayer).date.birth
+ and iPlayer < civilizations().majors().len()
+ ):
+ if iTech in [
+ Technology.FEUDALISM,
+ Technology.GUILDS,
+ Technology.GUNPOWDER,
+ Technology.PROFESSIONAL_ARMY,
+ Technology.NATIONALISM,
+ Technology.CIVIL_SERVICE,
+ Technology.ECONOMICS,
+ Technology.MACHINERY,
+ Technology.ARISTOCRACY,
+ ]:
+ gc.getPlayer(iPlayer).changeStabilityBase(StabilityCategory.ECONOMY, -1)
+
+
+@handler("buildingBuilt")
+def onBuildingBuilt(city, building_type):
+ iPlayer = city.getOwner()
+ if iPlayer < civilizations().majors().len():
+ pPlayer = gc.getPlayer(iPlayer)
+ if building_type == getUniqueBuilding(iPlayer, Building.MANOR_HOUSE):
+ pPlayer.changeStabilityBase(StabilityCategory.ECONOMY, 1)
+ recalcEconomy(iPlayer)
+ elif building_type == getUniqueBuilding(iPlayer, Building.CASTLE):
+ pPlayer.changeStabilityBase(StabilityCategory.EXPANSION, 1)
+ recalcEpansion(iPlayer)
+ elif building_type == getUniqueBuilding(iPlayer, Building.NIGHT_WATCH):
+ pPlayer.changeStabilityBase(StabilityCategory.CIVICS, 1)
+ recalcCivicCombos(iPlayer)
+ elif building_type == getUniqueBuilding(iPlayer, Building.COURTHOUSE):
+ pPlayer.changeStabilityBase(StabilityCategory.CITIES, 1)
+ recalcCity(iPlayer)
+ elif building_type == Wonder.ESCORIAL:
+ pPlayer.setPicklefreeParameter(SpecialParameter.HAS_ESCORIAL, 1)
+ elif building_type == Wonder.STEPHANSDOM:
+ pPlayer.setPicklefreeParameter(SpecialParameter.HAS_STEPHANSDOM, 1)
+ elif building_type == Wonder.SHRINE_OF_UPPSALA:
+ pPlayer.setPicklefreeParameter(SpecialParameter.HAS_UPPSALA_SHRINE, 1)
+ elif building_type == Wonder.KOUTOUBIA_MOSQUE:
+ pPlayer.setPicklefreeParameter(SpecialParameter.HAS_KOUTOUBIA_MOSQUE, 1)
+ elif building_type == Wonder.MAGNA_CARTA:
+ pPlayer.setPicklefreeParameter(SpecialParameter.HAS_MAGNACARTA, 1)
+ elif building_type == Building.PALACE:
+ pPlayer.changeStabilityBase(StabilityCategory.EXPANSION, -2)
+ pPlayer.setStabilitySwing(pPlayer.getStabilitySwing() - 5)
+ recalcEpansion(iPlayer)
+ elif building_type == Building.RELIQUARY:
+ pPlayer.changeStabilityBase(StabilityCategory.EXPANSION, 1)
+ recalcEpansion(iPlayer)
+
+
+@handler("projectBuilt")
+def onProjectBuilt(city, project):
+ if city.getOwner() < civilizations().majors().len():
+ iPlayer = city.getOwner()
+ pPlayer = gc.getPlayer(iPlayer)
+ iCivic5 = pPlayer.getCivics(5)
+ if project >= len(Project):
+ pPlayer.changeStabilityBase(
+ StabilityCategory.EXPANSION, -2
+ ) # -2 stability for each colony
+ if iCivic5 == Civic.COLONIALISM:
+ pPlayer.changeStabilityBase(
+ StabilityCategory.EXPANSION, 1
+ ) # one less stability penalty if civ is in Colonialism
+ recalcEpansion(iPlayer)
+
+
+@handler("EndGameTurn")
+def checkImplosion(iGameTurn):
+ if iGameTurn > 14 and iGameTurn % 6 == 3:
+ for iPlayer in civilizations().main().ids():
+ pPlayer = gc.getPlayer(iPlayer)
+ # Absinthe: no city secession for 15 turns after spawn, for 10 turns after respawn
+ iRespawnTurn = getLastRespawnTurn(iPlayer)
+ if (
+ pPlayer.isAlive()
+ and iGameTurn >= civilization(iPlayer).date.birth + 15
+ and iGameTurn >= iRespawnTurn + 10
+ ):
+ iStability = pPlayer.getStability()
+ # Absinthe: human player with very bad stability should have a much bigger chance for collapse
+ if iStability < -14 and iPlayer == human():
+ if percentage_chance(-2 * iStability, strict=True):
+ # 30 chance with -15, 50% with -25, 70% with -35, 100% with -50 or less
+ if not collapseImmune(iPlayer):
+ collapseCivilWar(iPlayer, iStability)
+ else: # when won't collapse, secession should always happen
+ revoltCity(iPlayer, False)
+ # Absinthe: if stability is less than -3, there is a chance that the secession/revolt or collapse mechanics start
+ # if more than 8 cities: high chance for secession mechanics, low chance for collapse
+ # elif more than 4 cities: medium chance for collapse mechanics, medium chance for secession
+ # otherwise big chance for collapse mechanics
+ # the actual chance for both secession/revolt and total collapse is increasing with lower stability
+ elif iStability < -3:
+ iRand1 = rand(10)
+ iRand2 = rand(10)
+ iRand3 = rand(10)
+ if pPlayer.getNumCities() > 8:
+ if iRand1 < 8: # 80 chance for secession start
+ if iRand2 < (
+ -3 - iStability
+ ): # 10% at -4, increasing by 10% with each point (100% with -13 or less)
+ revoltCity(iPlayer, False)
+ elif (
+ iRand3 < 1
+ and iGameTurn >= civilization(iPlayer).date.birth + 20
+ and not collapseImmune(iPlayer)
+ ): # 10 chance for collapse start
+ if iRand2 < (
+ -1.5 - (iStability / 2)
+ ): # 10% at -4, increasing by 10% with 2 points (100% with -22 or less)
+ collapseCivilWar(iPlayer, iStability)
+ elif pPlayer.getNumCities() > 4:
+ if iRand1 < 4: # 40 chance for secession start
+ if iRand2 < (
+ -3 - iStability
+ ): # 10% at -4, increasing by 10% with each point (100% with -13 or less)
+ revoltCity(iPlayer, False)
+ elif (
+ iRand3 < 4
+ and iGameTurn >= civilization(iPlayer).date.birth + 20
+ and not collapseImmune(iPlayer)
+ ): # 40 chance for collapse start
+ if iRand2 < (
+ -1.5 - (iStability / 2)
+ ): # 10% at -4, increasing by 10% with 2 points (100% with -22 or less)
+ collapseCivilWar(iPlayer, iStability)
+ elif (
+ iRand1 < 7
+ and iGameTurn >= civilization(iPlayer).date.birth + 20
+ and not collapseImmune(iPlayer)
+ ): # 70 chance for collapse start
+ if iRand2 < (
+ -1.5 - (iStability / 2)
+ ): # 10% at -4, increasing by 10% with 2 points (100% with -22 or less)
+ collapseCivilWar(iPlayer, iStability)
+
+
+def collapseCivilWar(iPlayer, iStability):
+ pPlayer = gc.getPlayer(iPlayer)
+ iHuman = human()
+ if iPlayer != iHuman:
+ if gc.getPlayer(iHuman).canContact(iPlayer):
+ message(
+ iHuman,
+ pPlayer.getCivilizationDescription(0)
+ + " "
+ + text("TXT_KEY_STABILITY_CIVILWAR_STABILITY"),
+ color=MessageData.RED,
+ )
+ killAndFragmentCiv(iPlayer, False, False)
+ elif pPlayer.getNumCities() > 1:
+ message(
+ iPlayer,
+ text("TXT_KEY_STABILITY_CIVILWAR_STABILITY_HUMAN"),
+ force=True,
+ color=MessageData.RED,
+ )
+ killAndFragmentCiv(iPlayer, False, True)
+ zeroStability(iPlayer)
+
+
+def printStability(iGameTurn, iPlayer):
+ pPlayer = gc.getPlayer(iPlayer)
+ print(" Turn: ", iGameTurn)
+ print(" ---------------- New Stability For " + pPlayer.getCivilizationShortDescription())
+ print(" Stability : ", pPlayer.getStability())
+ print(
+ " Cities : ",
+ pPlayer.getStabilityBase(StabilityCategory.CITIES)
+ + pPlayer.getStabilityVary(StabilityCategory.CITIES),
+ )
+ print(
+ " Civics : ",
+ pPlayer.getStabilityBase(StabilityCategory.CIVICS)
+ + pPlayer.getStabilityVary(StabilityCategory.CIVICS),
+ )
+ print(
+ " Economy : ",
+ pPlayer.getStabilityBase(StabilityCategory.ECONOMY)
+ + pPlayer.getStabilityVary(StabilityCategory.ECONOMY),
+ )
+ print(
+ " Expansion : ",
+ pPlayer.getStabilityBase(StabilityCategory.EXPANSION)
+ + pPlayer.getStabilityVary(StabilityCategory.EXPANSION),
+ )
+
+
+def zeroStability(iPlayer): # Called by Stability.CheckImplosion
+ pPlayer = gc.getPlayer(iPlayer)
+ pPlayer.changeStabilityBase(
+ StabilityCategory.CITIES,
+ -pPlayer.getStabilityBase(StabilityCategory.CITIES),
+ )
+ pPlayer.changeStabilityBase(
+ StabilityCategory.CIVICS,
+ -pPlayer.getStabilityBase(StabilityCategory.CIVICS),
+ )
+ pPlayer.changeStabilityBase(
+ StabilityCategory.ECONOMY,
+ -pPlayer.getStabilityBase(StabilityCategory.ECONOMY),
+ )
+ pPlayer.changeStabilityBase(
+ StabilityCategory.EXPANSION,
+ -pPlayer.getStabilityBase(StabilityCategory.EXPANSION),
+ )
+ pPlayer.setStabilityVary(StabilityCategory.CITIES, 0)
+ pPlayer.setStabilityVary(StabilityCategory.CIVICS, 0)
+ pPlayer.setStabilityVary(StabilityCategory.ECONOMY, 0)
+ pPlayer.setStabilityVary(StabilityCategory.EXPANSION, 0)
+ pPlayer.setStabilitySwing(0)
+
+
+def recalcCity(iPlayer):
+ pPlayer = gc.getPlayer(iPlayer)
+ iCivic4 = pPlayer.getCivics(4)
+ iCivic5 = pPlayer.getCivics(5)
+ iTotalHappy = pPlayer.calculateTotalCityHappiness() - pPlayer.calculateTotalCityUnhappiness()
+ iCityStability = 0
+ if pPlayer.getNumCities() == 0:
+ iHappyStability = 0
+ else:
+ iHappyStability = (
+ iTotalHappy / pPlayer.getNumCities()
+ ) # +k stability for an average city happiness of at least k
+ iCivHealthStability = 0
+ iHealthStability = 0
+ iHurryStability = 0
+ iMilitaryStability = 0
+ iWarWStability = 0
+ iReligionStability = 0
+ iCivicReligionInstability = 0
+ iCultureStability = 0
+
+ for pCity in cities.owner(iPlayer).entities():
+ # Absinthe: if your civ is healthy, bonus stability
+ # if one of your is cities is unhealthy, -1 stability
+ iCivHealthStability += pCity.goodHealth()
+ iCivHealthStability -= pCity.badHealth(False)
+ if pCity.goodHealth() - pCity.badHealth(False) < 0:
+ iHealthStability -= 1
+ if pCity.angryPopulation(0) > 0:
+ iHappyStability -= 2
+
+ # Absinthe: This is the "We desire religious freedom!" unhappiness, from civics - currently from the Religious Law civic
+ # also it is a negative counter with the current civic setup, so getReligionBadHappiness() == -1 with one non-state religion in the city
+ if pCity.getReligionBadHappiness() < 0:
+ if not gc.hasUP(
+ iPlayer, UniquePower.NO_INSTABILITY_WITH_FOREIGN_RELIGION
+ ): # Polish UP
+ iCivicReligionInstability += 1
+ if pCity.getHurryAngerModifier() > 0:
+ iHurryStability -= 1
+ if pCity.getNoMilitaryPercentAnger() > 0:
+ iMilitaryStability -= 1
+ # Absinthe: getWarWearinessPercentAnger is not a local variable for your cities, but a global one for your entire civ
+ # it would results in 1 instability for each city if there is an ongoing war, thus I added some modifications below
+ if pCity.getWarWearinessPercentAnger() > 10:
+ iWarWStability -= 1
+
+ bJewInstability = False
+ if (
+ iCivic4 != Civic.FREE_RELIGION
+ ): # Religious Tolerance negates stability penalties from non-state religions
+ if not gc.hasUP(
+ iPlayer, UniquePower.NO_INSTABILITY_WITH_FOREIGN_RELIGION
+ ): # Polish UP
+ if pCity.getNumForeignReligions() > 0:
+ # only calculate if Judaism is not the State Religion
+ if pPlayer.getStateReligion() != Religion.JUDAISM:
+ bJewInstability = True
+ if iCivic4 == Civic.PAGANISM: # Pagans are a bit more tolerant
+ iReligionStability -= 1
+ elif (
+ iPlayer == Civ.OTTOMAN
+ ): # Janissary UP - not necessarily a historical aspect of it, but important for gameplay
+ # elif ( gc.hasUP( iPlayer, UniquePower.FREE_UNITS_WITH_FOREIGN_RELIGIONS )):
+ iReligionStability -= 1
+ else:
+ iReligionStability -= 2
+ if (
+ pCity.getNumForeignReligions() > 1
+ ): # additional -1 stability for every further foreign religion
+ iReligionStability -= min(pCity.getNumForeignReligions() - 1, 3)
+
+ # Absinthe: Jewish Quarter reduces religion instability if Judaism is present in the city
+ if (
+ bJewInstability
+ and pCity.hasBuilding(Building.JEWISH_QUARTER)
+ and pCity.isHasReligion(Religion.JUDAISM)
+ ): # only if there are some religious penalties present in the city
+ iReligionStability += 1
+
+ # Absinthe: -1 stability if own culture is less than 40% of total culture in a city, -2 stability if less than 20%
+ iTotalCulture = pCity.countTotalCultureTimes100()
+ if (
+ (iTotalCulture > 0)
+ and ((pCity.getCulture(iPlayer) * 10000) / iTotalCulture < 40)
+ and not gc.hasUP(iPlayer, UniquePower.NO_UNHAPPINESS_WITH_FOREIGN_CULTURE)
+ ):
+ # Absinthe: 1 less instability with the Vassalage Civic, so only -1 with less than 20%, 0 otherwise
+ if iCivic5 != Civic.SUBJUGATION:
+ iCultureStability -= 1
+ if (pCity.getCulture(iPlayer) * 10000) / iTotalCulture < 20:
+ iCultureStability -= 1
+
+ # Absinthe: if your civ is healthy, bonus stability
+ if iCivHealthStability > 0:
+ iCivHealthStability = (
+ iCivHealthStability / pPlayer.getNumCities()
+ ) # +k stability for an average city health of at least k
+ iHealthStability += iCivHealthStability
+
+ # Absinthe: reduced value for getReligionBadHappiness, shouldn't add -1 for each city if almost all of them has multiple religions
+ # switching in and out of the civic won't result in that much fluctuation
+ iCivicReligionInstability = min(pPlayer.getNumCities() / 2, iCivicReligionInstability)
+
+ # Absinthe: persecution counter - cooldown is handled in Religions.checkTurn
+ # 1-3 means 1 instability, 4-6 means 2 instability, 7-9 means 3 instability, etc...
+ iProsecutionCount = pPlayer.getProsecutionCount()
+ if iProsecutionCount > 0:
+ iReligionStability -= (iProsecutionCount + 2) / 3
+
+ # Humans are far more competent then the AI, so the AI won't get all the penalties
+ if pPlayer.isHuman():
+ iCityStability += (
+ iHappyStability
+ + iHealthStability
+ + iReligionStability
+ - iCivicReligionInstability
+ + iHurryStability
+ + iCultureStability
+ + iMilitaryStability
+ )
+ iCityStability += max(iWarWStability / 3 - 1, -10) # max 10 instability from war weariness
+ iCityStability = min(
+ iCityStability, 8
+ ) # max 8 extra stability from cities - don't want to add too many bonuses for runaway civs
+ else:
+ iCityStability += max(iHappyStability, -5) + max(
+ iHealthStability, -5
+ ) # AI keeps very unhappy cities
+ iCityStability += max(
+ iReligionStability - iCivicReligionInstability + iHurryStability, -7
+ ) + max(iCultureStability, -5)
+ iCityStability += max(
+ iMilitaryStability + iWarWStability / 3, -3
+ ) # AI is also bad at handling war weariness
+ iCityStability = min(max(iCityStability, -10), 8)
+ iCityStability += pPlayer.getFaithBenefit(FaithPointBonusCategory.BOOST_STABILITY)
+ if pPlayer.getGoldenAgeTurns() > 0:
+ iCityStability += 8
+ # Absinthe: Westminster Abbey faith-stability effect
+ if pPlayer.countNumBuildings(Wonder.WESTMINSTER) > 0:
+ # would be better, if the stability bonus was also only applied for Divine Monarchy?
+ # if pPlayer.getCivics(0) == Civic.DIVINE_MONARCHY:
+ iFaith = pPlayer.getFaith()
+ iCityStability += iFaith / 20
+
+ pPlayer.setStabilityVary(StabilityCategory.CITIES, iCityStability)
+
+
+def recalcCivicCombos(iPlayer):
+ # Note: this is more or less the only place where Civics are referenced, yet referring them by number makes this hard to read
+ pPlayer = gc.getPlayer(iPlayer)
+ iCivicGovernment = pPlayer.getCivics(0)
+ iCivicLegal = pPlayer.getCivics(1)
+ iCivicLabor = pPlayer.getCivics(2)
+ iCivicEconomy = pPlayer.getCivics(3)
+ iCivicReligion = pPlayer.getCivics(4)
+ iCivicExpansion = pPlayer.getCivics(5)
+
+ lCivics = [
+ iCivicGovernment,
+ iCivicLegal,
+ iCivicLabor,
+ iCivicEconomy,
+ iCivicReligion,
+ iCivicExpansion,
+ ]
+ lCombinations = [
+ (iCivic1, iCivic2) for iCivic1 in lCivics for iCivic2 in lCivics if iCivic1 < iCivic2
+ ]
+
+ iCivicCombo = 0
+ # Calculate the combinations
+ for lCombination in lCombinations:
+ iComboValue = getCivicCombinationStability(lCombination[0], lCombination[1])
+ if (
+ iComboValue < 0
+ and pPlayer.getPicklefreeParameter(SpecialParameter.HAS_MAGNACARTA) == 1
+ ):
+ iComboValue = 0
+ iCivicCombo += iComboValue
+
+ if pPlayer.getPicklefreeParameter(SpecialParameter.HAS_STEPHANSDOM) == 1:
+ if iCivicGovernment in [
+ Civic.FEUDAL_MONARCHY,
+ Civic.DIVINE_MONARCHY,
+ Civic.LIMITE_DMONARCHY,
+ ]:
+ iCivicCombo += 2
+
+ if pPlayer.getPicklefreeParameter(SpecialParameter.HAS_UPPSALA_SHRINE) == 1:
+ if iCivicReligion == Civic.PAGANISM:
+ iCivicCombo += 3
+
+ if pPlayer.getPicklefreeParameter(SpecialParameter.HAS_KOUTOUBIA_MOSQUE) == 1:
+ if iCivicLegal == Civic.RELIGIOUS_LAW:
+ iCivicCombo += 4
+
+ if iCivicLegal == Civic.BUREAUCRACY: # Bureaucracy city cap
+ if (
+ iPlayer == Civ.NOVGOROD and pPlayer.getNumCities() > 6
+ ): # the penalties are halved for Novgorod
+ iBureaucracyCap = (6 - pPlayer.getNumCities()) / 2
+ else:
+ iBureaucracyCap = 6 - pPlayer.getNumCities()
+ if not pPlayer.isHuman(): # max -5 penalty for the AI
+ iBureaucracyCap = max(-5, iBureaucracyCap)
+ iCivicCombo += iBureaucracyCap
+
+ if iCivicGovernment == Civic.MERCHANT_REPUBLIC: # Merchant Republic city cap
+ if (
+ iPlayer == Civ.VENECIA and pPlayer.getNumCities() > 5
+ ): # the penalties are halved for Venice
+ iMerchantRepublicCap = (5 - pPlayer.getNumCities()) / 2
+ else:
+ iMerchantRepublicCap = 5 - pPlayer.getNumCities()
+ if not pPlayer.isHuman(): # max -5 penalty for the AI
+ iMerchantRepublicCap = max(-5, iMerchantRepublicCap)
+ iCivicCombo += iMerchantRepublicCap
+
+ pPlayer.setStabilityVary(StabilityCategory.CIVICS, iCivicCombo)
+
+
+def getCivicCombinationStability(iCivic0, iCivic1):
+ lCivics = set([iCivic0, iCivic1])
+
+ if Civic.FEUDAL_MONARCHY in lCivics:
+ if Civic.FEUDAL_LAW in lCivics:
+ return 3
+
+ if (
+ Civic.DIVINE_MONARCHY in lCivics
+ ): # Divine Monarchy should have an appropriate religious civic
+ if Civic.RELIGIOUS_LAW in lCivics:
+ return 2
+ if Civic.PAGANISM in lCivics:
+ return -4
+ if Civic.STATE_RELIGION in lCivics:
+ return 2
+ if Civic.THEOCRACY in lCivics:
+ return 3
+ if Civic.ORGANIZED_RELIGION in lCivics:
+ return 4
+ if Civic.FREE_RELIGION in lCivics:
+ return -3
+
+ if (
+ Civic.LIMITE_DMONARCHY in lCivics
+ ): # Constitutional Monarchy and Republic both like enlightened civics
+ if Civic.COMMON_LAW in lCivics:
+ return 3
+ if Civic.FREE_PEASANTRY in lCivics:
+ return 2
+ if Civic.FREE_LABOR in lCivics:
+ return 2
+
+ if (
+ Civic.MERCHANT_REPUBLIC in lCivics
+ ): # Constitutional Monarchy and Republic both like enlightened civics
+ if Civic.FEUDAL_LAW in lCivics:
+ return -3
+ if Civic.COMMON_LAW in lCivics:
+ return 3
+ if Civic.FREE_PEASANTRY in lCivics:
+ return 2
+ if Civic.FREE_LABOR in lCivics:
+ return 2
+ if Civic.TRADE_ECONOMY in lCivics:
+ return 4
+ if Civic.MERCANTILISM in lCivics:
+ return -4
+ if Civic.IMPERIALISM in lCivics:
+ return -2
+
+ if Civic.FEUDAL_LAW in lCivics:
+ if Civic.SERFDOM in lCivics:
+ return 3
+ if Civic.FREE_PEASANTRY in lCivics:
+ return -4
+ if Civic.MANORIALISM in lCivics:
+ return 2
+ if Civic.VASSALAGE in lCivics:
+ return 2
+
+ if Civic.RELIGIOUS_LAW in lCivics:
+ if Civic.PAGANISM in lCivics:
+ return -5
+ if Civic.THEOCRACY in lCivics:
+ return 5
+ if Civic.FREE_RELIGION in lCivics:
+ return -3
+
+ if Civic.COMMON_LAW in lCivics:
+ if Civic.SERFDOM in lCivics:
+ return -3
+ if Civic.FREE_LABOR in lCivics:
+ return 3
+ if Civic.THEOCRACY in lCivics:
+ return -4
+
+ if Civic.SERFDOM in lCivics:
+ if Civic.MANORIALISM in lCivics:
+ return 2
+ if Civic.TRADE_ECONOMY in lCivics:
+ return -3
+
+ if Civic.APPRENTICESHIP in lCivics:
+ if Civic.GUILDS in lCivics:
+ return 3
+
+ return 0
+
+
+def recalcEconomy(iPlayer):
+ pPlayer = gc.getPlayer(iPlayer)
+ iPopNum = pPlayer.getTotalPopulation()
+ iImports = pPlayer.calculateTotalImports(YieldTypes.YIELD_COMMERCE)
+ iExports = pPlayer.calculateTotalExports(YieldTypes.YIELD_COMMERCE)
+ # Absinthe: removed - why was Cordoba penalized in the first place?
+ # if iPlayer == Civ.CORDOBA:
+ # iImports /= 2
+ # iExports /= 2
+
+ iFinances = pPlayer.getFinancialPower()
+ iInflation = pPlayer.calculateInflatedCosts()
+ iProduction = pPlayer.calculateTotalYield(YieldTypes.YIELD_PRODUCTION)
+ # Absinthe: removed - Venice no longer has that weak production
+ # if iPlayer == Civ.VENECIA:
+ # iProduction += iPopNum # offset their weak production
+ iAgriculture = pPlayer.calculateTotalYield(YieldTypes.YIELD_FOOD)
+
+ iLargeCities = 0
+ for pCity in cities.owner(iPlayer).entities():
+ # Absinthe: production penalty removed - was a mistake to add a city-based modifier to the financial stability which is based on average per population
+ # if pCity.isProductionUnit():
+ # iUnit = pCity.getProductionUnit()
+ # if iUnit < Unit.WORKER or iUnit > Unit.ISLAMIC_MISSIONARY:
+ # iProductionPenalty -= 1
+ # elif pCity.isProductionBuilding():
+ # iBuilding = pCity.getProductionBuilding()
+ # if isWonder(iBuilding):
+ # iProductionPenalty -= 2
+ # else:
+ # iProductionPenalty -= 2
+ iCityPop = pCity.getPopulation()
+ if (
+ iCityPop > 10
+ ): # large cities should have production bonus buildings, drop by 10 percent
+ iProduction -= pCity.getYieldRate(YieldTypes.YIELD_PRODUCTION) / 10
+ iLargeCities += 1
+
+ iNumCities = pPlayer.getNumCities()
+ if iNumCities > 0:
+ iIndustrialStability = min(
+ max(2 * (2 * iAgriculture + iProduction) / iPopNum - 14, -3), 3
+ ) # this is 0 if the average yield per population is a little more than 2 food and 2 production (with bonuses)
+ if (
+ pPlayer.getPicklefreeParameter(SpecialParameter.HAS_ESCORIAL) == 1
+ ): # El Escorial no economic instability effect
+ iIndustrialStability = max(iIndustrialStability, 0)
+ iFinances = (
+ iFinances * (100 - 20 * iLargeCities / iNumCities) / 100
+ ) # between 80% and 100%, based on the number of large cities
+ iFinancialStability = min(
+ max((iFinances - iInflation + iImports + iExports) / iPopNum - 6, -4), 4
+ ) # this is 0 if the average financial power per population is around 6
+ # iFinancialPowerPerCity = ( iFinances - iInflation + iImports + iExports ) / iNumCities
+ if (
+ pPlayer.getPicklefreeParameter(SpecialParameter.HAS_ESCORIAL) == 1
+ ): # El Escorial no economic instability effect
+ iFinancialStability = max(iFinancialStability, 0)
+ pPlayer.setStabilityVary(
+ StabilityCategory.ECONOMY, iFinancialStability + iIndustrialStability
+ )
+ else:
+ pPlayer.setStabilityVary(StabilityCategory.ECONOMY, 0)
diff --git a/Assets/Python/StoredData.py b/Assets/Python/StoredData.py
index 4e523a4db..64b37b6a3 100644
--- a/Assets/Python/StoredData.py
+++ b/Assets/Python/StoredData.py
@@ -1,33 +1,13 @@
-from Core import civilizations, player
-from CoreTypes import Civ
-import cPickle as pickle
+from Core import civilizations
from MiscData import NUM_CRUSADES
-class CivData:
- def __init__(self, civ):
- self._civ = civ
- self.setup()
- self.save()
-
- def load(self):
- self.__dict__.update(pickle.loads(player(self._civ).getScriptData()))
-
- def save(self):
- player(self._civ).setScriptData(pickle.dumps(self.__dict__))
-
-
class GameData:
def __init__(self):
self.setup()
- def load(self):
- """Loads and unpickles script data"""
- self.__dict__.update(pickle.loads(player(Civ.BARBARIAN).getScriptData()))
-
- def save(self):
- """Pickles and saves script data"""
- player(Civ.BARBARIAN).setScriptData(pickle.dumps(self.__dict__))
+ def update(self, data):
+ self.__dict__.update(data)
def setup(self):
"""Initialise the global script data for usage."""
@@ -158,25 +138,5 @@ def setup(self):
self.lBaseStabilityLastTurn = [0] * civilizations().majors().len()
- self.save()
-
data = GameData()
-
-
-def get_data(key, subkey=None):
- if subkey is None:
- return data.__dict__[key]
- else:
- return data.__dict__[key][subkey]
-
-
-def set_data(key, value, subkey=None):
- if subkey is None:
- data.__dict__[key] = value
- else:
- data.__dict__[key][subkey] = value
-
-
-def mod_data(key, value=1, subkey=None):
- set_data(key, get_data(key, subkey) + value, subkey)
diff --git a/Assets/Python/UniquePowers.py b/Assets/Python/UniquePowers.py
new file mode 100644
index 000000000..c27cb88f0
--- /dev/null
+++ b/Assets/Python/UniquePowers.py
@@ -0,0 +1,320 @@
+# Rhye's and Fall of Civilization: Europe - Unique Powers (only a couple of them is here, most are handled in the .dll)
+from CvPythonExtensions import *
+from Core import (
+ civilization,
+ message_if_human,
+ player,
+ human,
+ turn,
+ year,
+ message,
+ text,
+ make_unit,
+ cities,
+ plots,
+ infos,
+)
+from CoreTypes import Building, Civ, SpecialParameter, Religion, Technology, UniquePower, Unit
+from RFCUtils import getMaster, getUniqueUnit
+from Consts import MessageData
+from PyUtils import choice
+from Events import handler
+
+gc = CyGlobalContext()
+
+
+@handler("cityAcquired")
+def ottoman_up_1(owner, player_id, city, bConquest, bTrade):
+ if gc.hasUP(player_id, UniquePower.FREE_UNITS_WITH_FOREIGN_RELIGIONS):
+ janissaryNewCityUP(player_id, city, bConquest)
+
+
+@handler("BeginPlayerTurn")
+def ottoman_up_2(iGameTurn, iPlayer):
+ # janissaryDraftUP
+ if gc.hasUP(iPlayer, UniquePower.FREE_UNITS_WITH_FOREIGN_RELIGIONS):
+ pPlayer = gc.getPlayer(iPlayer)
+ iStateReligion = pPlayer.getStateReligion()
+
+ iNewPoints = 0
+ for city in cities.owner(iPlayer).entities():
+ for iReligion in range(len(Religion)):
+ if iReligion != iStateReligion and city.isHasReligion(iReligion):
+ iNewPoints += city.getPopulation()
+ break
+
+ iOldPoints = pPlayer.getPicklefreeParameter(SpecialParameter.JANISSARY_POINTS)
+
+ iNextJanissary = 200
+ if pPlayer.isHuman():
+ iNextJanissary = 300
+
+ iTotalPoints = iOldPoints + iNewPoints
+ while iTotalPoints >= iNextJanissary:
+ pCity = cities.owner(iPlayer).random_entry()
+ if pCity is not None:
+ iTotalPoints -= iNextJanissary
+ make_unit(iPlayer, Unit.JANISSARY, pCity)
+ message_if_human(
+ iPlayer,
+ text("TXT_KEY_UNIT_NEW_JANISSARY") + " " + pCity.getName() + "!",
+ sound="AS2D_UNIT_BUILD_UNIQUE_UNIT",
+ button=gc.getUnitInfo(Unit.JANISSARY).getButton(),
+ color=MessageData.GREEN,
+ location=pCity,
+ )
+ pPlayer.setPicklefreeParameter(SpecialParameter.JANISSARY_POINTS, iTotalPoints)
+
+
+@handler("BeginPlayerTurn")
+def danish_up(iGameTurn, iPlayer):
+ if iPlayer == Civ.DENMARK:
+ lSoundCoords = [(60, 57), (60, 58)]
+
+ # Check if we control the Sound
+ bControlsSound = False
+ for tCoord in lSoundCoords:
+ pPlot = gc.getMap().plot(tCoord[0], tCoord[1])
+ if pPlot.calculateCulturalOwner() == iPlayer:
+ bControlsSound = True
+ break
+ if not bControlsSound:
+ return
+
+ iCities = getNumForeignCitiesOnBaltic(iPlayer)
+ iGold = iCities * 2
+ gc.getPlayer(iPlayer).changeGold(iGold)
+ message(iPlayer, text("TXT_KEY_UP_SOUND_TOLL", iGold), color=MessageData.GREEN)
+
+
+@handler("cityAcquired")
+def scottish_up(owner, player_id, city, bConquest, bTrade):
+ # against all players (including indies and barbs), but only on conquest
+ # only in cities with at least 20% Scottish culture
+ if owner == Civ.SCOTLAND and bConquest:
+ iTotalCulture = city.countTotalCultureTimes100()
+ if iTotalCulture == 0 or (city.getCulture(owner) * 10000) / iTotalCulture > 20:
+ defianceUP(owner)
+
+
+@handler("cityAcquired")
+def aragon_up_on_city_acquired(owner, player_id, city, bConquest, bTrade):
+ # Absinthe: Aragonese UP
+ # UP tile yields should be recalculated right away, in case the capital was conquered, or province number changed
+ if owner == Civ.ARAGON:
+ confederationUP(owner)
+ if player_id == Civ.ARAGON:
+ confederationUP(player_id)
+
+
+@handler("cityRazed")
+def aragon_up_on_city_razed(city, iPlayer):
+ # UP tile yields should be recalculated if your new city is razed
+ if iPlayer == Civ.ARAGON:
+ confederationUP(iPlayer)
+
+
+@handler("cityBuilt")
+def aragon_up_on_city_built(city):
+ # UP tile yields should be recalculated on city foundation
+ iPlayer = city.getOwner()
+ if iPlayer == Civ.ARAGON:
+ confederationUP(iPlayer)
+
+
+@handler("BeginPlayerTurn")
+def aragon_up_on_begin_player_turn(iGameTurn, iPlayer):
+ # safety check: probably redundant, calls from onBuildingBuilt, onCityBuilt, onCityAcquired and onCityRazed should be enough
+ if iPlayer == Civ.ARAGON:
+ confederationUP(iPlayer)
+
+
+@handler("buildingBuilt")
+def aragon_up_on_building_built(city, building_type):
+ # UP tile yields should be recalculated right away if a new Palace was built
+ iPlayer = city.getOwner()
+ if iPlayer == Civ.ARAGON and building_type == Building.PALACE:
+ confederationUP(iPlayer)
+
+
+@handler("cityBuilt")
+def portugal_up_on_city_built(city):
+ iPlayer = city.getOwner()
+ if iPlayer == Civ.PORTUGAL and civilization(Civ.PORTUGAL).has_tech(Technology.ASTRONOMY):
+ city.setHasRealBuilding(Building.PORTUGAL_FEITORIA, True)
+
+
+@handler("combatResult")
+def norway_up(winning_unit, losing_unit):
+ if winning_unit.getOwner() == Civ.NORWAY and turn() < year(1066) + 2:
+ if infos.unit(losing_unit).getDomainType() == DomainTypes.DOMAIN_SEA:
+ if losing_unit.getUnitType() != Unit.WORKBOAT:
+ player(Civ.NORWAY).setUHVCounter(0, player(Civ.NORWAY).getUHVCounter(0) + 2)
+ else:
+ player(Civ.NORWAY).setUHVCounter(0, player(Civ.NORWAY).getUHVCounter(0) + 1)
+
+
+# Absinthe: Arabian UP
+def faithUP(iPlayer, city):
+ pFaithful = gc.getPlayer(iPlayer)
+ iStateReligion = pFaithful.getStateReligion()
+ iTemple = 0
+ # Absinthe: shouldn't work on minor religions, to avoid exploit with spreading Judaism this way
+ if 0 <= iStateReligion <= 3:
+ if not city.isHasReligion(iStateReligion):
+ city.setHasReligion(iStateReligion, True, True, False)
+ pFaithful.changeFaith(1)
+
+ if iStateReligion == 0:
+ iTemple = Building.PROTESTANT_TEMPLE
+ elif iStateReligion == 1:
+ iTemple = Building.ISLAMIC_TEMPLE
+ elif iStateReligion == 2:
+ iTemple = Building.CATHOLIC_TEMPLE
+ elif iStateReligion == 3:
+ iTemple = Building.ORTHODOX_TEMPLE
+ if not city.hasBuilding(iTemple):
+ city.setHasRealBuilding(iTemple, True)
+ pFaithful.changeFaith(1)
+
+
+def janissaryNewCityUP(iPlayer, city, bConquest):
+ pPlayer = gc.getPlayer(iPlayer)
+ iStateReligion = pPlayer.getStateReligion()
+ for iReligion in range(len(Religion)):
+ if iReligion != iStateReligion and city.isHasReligion(iReligion):
+ iCityPopulation = city.getPopulation()
+ # more janissary points on conquest, less on flip and trade
+ if bConquest:
+ iJanissaryPoint = iCityPopulation * 9
+ else:
+ iJanissaryPoint = iCityPopulation * 4
+ iOldPoints = pPlayer.getPicklefreeParameter(SpecialParameter.JANISSARY_POINTS)
+ pPlayer.setPicklefreeParameter(
+ SpecialParameter.JANISSARY_POINTS, iOldPoints + iJanissaryPoint
+ )
+ break
+
+ # removed free janissary, probably too powerful to add a new janissary unit right on conquest
+ iIsHasForeignReligion = 0
+ if iIsHasForeignReligion:
+ make_unit(iPlayer, Unit.JANISSARY, city)
+ if iPlayer == human():
+ text_string = text("TXT_KEY_UNIT_NEW_JANISSARY") + " " + city.getName() + "!"
+ message(
+ iPlayer,
+ text_string,
+ sound="AS2D_UNIT_BUILD_UNIQUE_UNIT",
+ button=gc.getUnitInfo(Unit.JANISSARY).getButton(),
+ color=MessageData.GREEN,
+ location=city,
+ )
+
+
+def getNumForeignCitiesOnBaltic(iPlayer, bVassal=False):
+ lBalticRects = [
+ ((56, 52), (70, 57)),
+ ((62, 58), (74, 62)),
+ ((64, 63), (79, 66)),
+ ((64, 67), (71, 72)),
+ ]
+
+ # Count foreign coastal cities
+ iCities = 0
+ for start, end in lBalticRects:
+ for city in plots.rectangle(start, end).cities().coastal(5).not_owner(iPlayer).entities():
+ if not bVassal or city.getOwner() != getMaster(city.getOwner()) != iPlayer:
+ iCities += 1
+ return iCities
+
+
+# Absinthe: Aragonese UP
+def confederationUP(iPlayer):
+ pPlayer = gc.getPlayer(iPlayer)
+ capital = pPlayer.getCapitalCity()
+ iCapitalX = capital.getX()
+ iCapitalY = capital.getY()
+
+ # Collect all provinces
+ cityProvinces = []
+ for city in cities.owner(iPlayer).entities():
+ pProvince = city.getProvince()
+ cityProvinces.append(pProvince)
+ # Calculate unique provinces
+ uniqueProvinces = set(cityProvinces)
+ iProvinces = len(uniqueProvinces)
+
+ # Note that Aragon do not use any of its UHV counters, so we can safely use them here
+ # Do not recalculate if we have the same number of provinces as in the last check, and the capital has not changed
+ if (
+ iProvinces == pPlayer.getUHVCounter(1)
+ and pPlayer.getUHVCounter(2) == 100 * iCapitalX + iCapitalY
+ ):
+ return
+
+ # Store the province number for the next check
+ pPlayer.setUHVCounter(1, iProvinces)
+
+ # On capital change, reset yield for the previous capital's tile, also reset the commerce counter
+ if pPlayer.getUHVCounter(2) != 100 * iCapitalX + iCapitalY:
+ iOldCapitalX = pPlayer.getUHVCounter(2) / 100
+ iOldCapitalY = pPlayer.getUHVCounter(2) % 100
+ iProvinceCommerceLastBonus = pPlayer.getUHVCounter(0)
+ gc.getGame().setPlotExtraYield(iOldCapitalX, iOldCapitalY, 2, -iProvinceCommerceLastBonus)
+ # If there was a capital change, the discount should be 0 for the new capital's tile
+ pPlayer.setUHVCounter(0, 0)
+ # New capital's coordinates are stored for the next check
+ pPlayer.setUHVCounter(2, 100 * iCapitalX + iCapitalY)
+
+ # Update tile yield for the capital's plot
+ iProvinceCommerceLastBonus = pPlayer.getUHVCounter(0)
+ gc.getGame().setPlotExtraYield(iCapitalX, iCapitalY, 2, -iProvinceCommerceLastBonus)
+ iProvinceCommerceNextBonus = (
+ iProvinces * 2
+ ) # <- This number is the amount of extra commerce per province
+ gc.getGame().setPlotExtraYield(iCapitalX, iCapitalY, 2, iProvinceCommerceNextBonus)
+ # Tile yield is stored for the next check
+ pPlayer.setUHVCounter(0, iProvinceCommerceNextBonus)
+
+
+# Absinthe: Scottish UP
+def defianceUP(iPlayer):
+ pPlayer = gc.getPlayer(iPlayer)
+ # One ranged/gun class
+ RangedClass = getUniqueUnit(iPlayer, Unit.ARCHER)
+ lRangedList = [
+ Unit.LINE_INFANTRY,
+ Unit.MUSKETMAN,
+ Unit.LONGBOWMAN,
+ Unit.ARBALEST,
+ Unit.CROSSBOWMAN,
+ Unit.ARCHER,
+ ]
+ for iUnit in lRangedList:
+ if pPlayer.canTrain(getUniqueUnit(iPlayer, iUnit), False, False):
+ RangedClass = getUniqueUnit(iPlayer, iUnit)
+ break
+
+ # One polearm class
+ PolearmClass = getUniqueUnit(iPlayer, Unit.SPEARMAN)
+ lPolearmList = [Unit.LINE_INFANTRY, Unit.PIKEMAN, Unit.GUISARME]
+ for iUnit in lPolearmList:
+ if pPlayer.canTrain(getUniqueUnit(iPlayer, iUnit), False, False):
+ PolearmClass = getUniqueUnit(iPlayer, iUnit)
+ break
+
+ for city in cities.owner(iPlayer).entities():
+ # only in cities with at least 20% Scottish culture
+ iTotalCulture = city.countTotalCultureTimes100()
+ if iTotalCulture == 0 or (city.getCulture(iPlayer) * 10000) / iTotalCulture > 20:
+ make_unit(iPlayer, choice([RangedClass, PolearmClass]), city)
+ # interface message for the human player
+ if iPlayer == human():
+ text_string = text("TXT_KEY_UNIT_NEW_DEFENDER") + " " + city.getName() + "!"
+ message(
+ iPlayer,
+ text_string,
+ sound="AS2D_UNIT_BUILD_UNIQUE_UNIT",
+ color=MessageData.GREEN,
+ location=city,
+ )
diff --git a/Assets/Python/Victory.py b/Assets/Python/Victory.py
new file mode 100644
index 000000000..61ae34e86
--- /dev/null
+++ b/Assets/Python/Victory.py
@@ -0,0 +1,2113 @@
+from CvPythonExtensions import *
+from Core import (
+ civilization,
+ companies,
+ civilizations,
+ message,
+ human,
+ player,
+ plot,
+ show,
+ team,
+ text,
+ turn,
+ year,
+ plots,
+ cities,
+)
+from CoreTypes import (
+ Building,
+ City,
+ Civ,
+ Civic,
+ Colony,
+ Company,
+ Project,
+ ProvinceStatus,
+ Region,
+ Specialist,
+ StabilityCategory,
+ Religion,
+ Improvement,
+ Technology,
+ Bonus,
+ Wonder,
+ Province,
+)
+from LocationsData import CITIES, CIV_CAPITAL_LOCATIONS, REGIONS
+from PyUtils import rand
+from RFCUtils import calculateDistance, countAchievedGoals, getNumberCargoShips, getMostAdvancedCiv
+import UniquePowers
+from StoredData import data
+import random
+from Events import handler
+from Consts import MessageData
+
+gc = CyGlobalContext()
+
+
+tByzantiumControl = [
+ Province.CALABRIA,
+ Province.APULIA,
+ Province.DALMATIA,
+ Province.VERONA,
+ Province.LOMBARDY,
+ Province.LIGURIA,
+ Province.TUSCANY,
+ Province.LATIUM,
+ Province.CORSICA,
+ Province.SARDINIA,
+ Province.SICILY,
+ Province.TRIPOLITANIA,
+ Province.IFRIQIYA,
+]
+tByzantiumControlII = [
+ Province.COLONEA,
+ Province.ANTIOCHIA,
+ Province.CHARSIANON,
+ Province.CILICIA,
+ Province.ARMENIAKON,
+ Province.ANATOLIKON,
+ Province.PAPHLAGONIA,
+ Province.THRAKESION,
+ Province.OPSIKION,
+ Province.CONSTANTINOPLE,
+ Province.THRACE,
+ Province.THESSALONIKI,
+ Province.MOESIA,
+ Province.MACEDONIA,
+ Province.SERBIA,
+ Province.ARBERIA,
+ Province.EPIRUS,
+ Province.THESSALY,
+ Province.MOREA,
+]
+tFrankControl = [
+ Province.SWABIA,
+ Province.SAXONY,
+ Province.LORRAINE,
+ Province.ILE_DE_FRANCE,
+ Province.NORMANDY,
+ Province.PICARDY,
+ Province.AQUITAINE,
+ Province.PROVENCE,
+ Province.BURGUNDY,
+ Province.ORLEANS,
+ Province.CHAMPAGNE,
+ Province.CATALONIA,
+ Province.LOMBARDY,
+ Province.TUSCANY,
+]
+tArabiaControlI = [
+ Province.ARABIA,
+ Province.JERUSALEM,
+ Province.SYRIA,
+ Province.LEBANON,
+ Province.ANTIOCHIA,
+ Province.EGYPT,
+ Province.CYRENAICA,
+ Province.TRIPOLITANIA,
+ Province.IFRIQIYA,
+ Province.SICILY,
+ Province.CRETE,
+ Province.CYPRUS,
+]
+tArabiaControlII = [
+ Province.ARABIA,
+ Province.JERUSALEM,
+ Province.SYRIA,
+ Province.LEBANON,
+ Province.ANTIOCHIA,
+ Province.EGYPT,
+]
+tBulgariaControl = [
+ Province.CONSTANTINOPLE,
+ Province.THESSALONIKI,
+ Province.SERBIA,
+ Province.THRACE,
+ Province.MACEDONIA,
+ Province.MOESIA,
+ Province.ARBERIA,
+]
+tCordobaWonders = [
+ Wonder.ALHAMBRA,
+ Wonder.LA_MEZQUITA,
+ Wonder.GARDENS_AL_ANDALUS,
+]
+tCordobaIslamize = [
+ Province.GALICIA,
+ Province.CASTILE,
+ Province.LEON,
+ Province.LUSITANIA,
+ Province.CATALONIA,
+ Province.ARAGON,
+ Province.NAVARRE,
+ Province.VALENCIA,
+ Province.LA_MANCHA,
+ Province.ANDALUSIA,
+]
+tNorwayControl = [
+ Province.THE_ISLES,
+ Province.IRELAND,
+ Province.SCOTLAND,
+ Province.NORMANDY,
+ Province.SICILY,
+ Province.APULIA,
+ Province.CALABRIA,
+ Province.ICELAND,
+]
+tNorwayOutrank = [
+ Civ.SWEDEN,
+ Civ.DENMARK,
+ Civ.SCOTLAND,
+ Civ.ENGLAND,
+ Civ.GERMANY,
+ Civ.FRANCE,
+]
+# tNorseControl = [ Province.SICILY, Province.ICELAND, Province.NORTHUMBRIA, Province.SCOTLAND, Province.NORMANDY, Province.IRELAND, Province.NOVGOROD ]
+tVenetianControl = [
+ Province.EPIRUS,
+ Province.DALMATIA,
+ Province.VERONA,
+ Province.ARBERIA,
+]
+tVenetianControlII = [
+ Province.THESSALY,
+ Province.MOREA,
+ Province.CRETE,
+ Province.CYPRUS,
+]
+tBurgundyControl = [
+ Province.FLANDERS,
+ Province.PICARDY,
+ Province.PROVENCE,
+ Province.BURGUNDY,
+ Province.CHAMPAGNE,
+ Province.LORRAINE,
+]
+tBurgundyOutrank = [Civ.FRANCE, Civ.ENGLAND, Civ.GERMANY]
+tGermanyControl = [
+ Province.TUSCANY,
+ Province.LIGURIA,
+ Province.LOMBARDY,
+ Province.LORRAINE,
+ Province.SWABIA,
+ Province.SAXONY,
+ Province.BAVARIA,
+ Province.FRANCONIA,
+ Province.BRANDENBURG,
+ Province.HOLSTEIN,
+]
+tGermanyControlII = [
+ Province.AUSTRIA,
+ Province.FLANDERS,
+ Province.POMERANIA,
+ Province.SILESIA,
+ Province.BOHEMIA,
+ Province.MORAVIA,
+ Province.SWABIA,
+ Province.SAXONY,
+ Province.BAVARIA,
+ Province.FRANCONIA,
+ Province.BRANDENBURG,
+ Province.HOLSTEIN,
+]
+tKievControl = [
+ Province.KIEV,
+ Province.PODOLIA,
+ Province.PEREYASLAVL,
+ Province.SLOBODA,
+ Province.CHERNIGOV,
+ Province.VOLHYNIA,
+ Province.MINSK,
+ Province.POLOTSK,
+ Province.SMOLENSK,
+ Province.MOSCOW,
+ Province.MUROM,
+ Province.ROSTOV,
+ Province.NOVGOROD,
+ Province.VOLOGDA,
+]
+tHungaryControl = [
+ Province.AUSTRIA,
+ Province.CARINTHIA,
+ Province.MORAVIA,
+ Province.SILESIA,
+ Province.BOHEMIA,
+ Province.DALMATIA,
+ Province.BOSNIA,
+ Province.BANAT,
+ Province.WALLACHIA,
+ Province.MOLDOVA,
+]
+tHungaryControlII = [
+ Province.THRACE,
+ Province.MOESIA,
+ Province.MACEDONIA,
+ Province.THESSALONIKI,
+ Province.WALLACHIA,
+ Province.THESSALY,
+ Province.MOREA,
+ Province.EPIRUS,
+ Province.ARBERIA,
+ Province.SERBIA,
+ Province.BANAT,
+ Province.BOSNIA,
+ Province.DALMATIA,
+ Province.SLAVONIA,
+]
+tSpainConvert = [
+ Province.GALICIA,
+ Province.CASTILE,
+ Province.LEON,
+ Province.LUSITANIA,
+ Province.CATALONIA,
+ Province.ARAGON,
+ Province.NAVARRE,
+ Province.VALENCIA,
+ Province.LA_MANCHA,
+ Province.ANDALUSIA,
+]
+tPolishControl = [
+ Province.BOHEMIA,
+ Province.MORAVIA,
+ Province.UPPER_HUNGARY,
+ Province.PRUSSIA,
+ Province.LITHUANIA,
+ Province.LIVONIA,
+ Province.POLOTSK,
+ Province.MINSK,
+ Province.VOLHYNIA,
+ Province.PODOLIA,
+ Province.MOLDOVA,
+ Province.KIEV,
+]
+tGenoaControl = [
+ Province.CORSICA,
+ Province.SARDINIA,
+ Province.CRETE,
+ Province.RHODES,
+ Province.THRAKESION,
+ Province.CYPRUS,
+ Province.CRIMEA,
+]
+tEnglandControl = [
+ Province.AQUITAINE,
+ Province.LONDON,
+ Province.WALES,
+ Province.WESSEX,
+ Province.SCOTLAND,
+ Province.EAST_ANGLIA,
+ Province.MERCIA,
+ Province.NORTHUMBRIA,
+ Province.IRELAND,
+ Province.NORMANDY,
+ Province.BRETAGNE,
+ Province.ILE_DE_FRANCE,
+ Province.ORLEANS,
+ Province.PICARDY,
+]
+tPortugalControlI = [Province.AZORES, Province.CANARIES, Province.MADEIRA]
+tPortugalControlII = [Province.MOROCCO, Province.TETOUAN, Province.ORAN]
+tAustriaControl = [
+ Province.HUNGARY,
+ Province.UPPER_HUNGARY,
+ Province.AUSTRIA,
+ Province.CARINTHIA,
+ Province.BAVARIA,
+ Province.TRANSYLVANIA,
+ Province.PANNONIA,
+ Province.MORAVIA,
+ Province.SILESIA,
+ Province.BOHEMIA,
+]
+tOttomanControlI = [
+ Province.SERBIA,
+ Province.BOSNIA,
+ Province.BANAT,
+ Province.MACEDONIA,
+ Province.THRACE,
+ Province.MOESIA,
+ Province.CONSTANTINOPLE,
+ Province.ARBERIA,
+ Province.EPIRUS,
+ Province.THESSALONIKI,
+ Province.THESSALY,
+ Province.MOREA,
+ Province.COLONEA,
+ Province.ANTIOCHIA,
+ Province.CHARSIANON,
+ Province.CILICIA,
+ Province.ARMENIAKON,
+ Province.ANATOLIKON,
+ Province.PAPHLAGONIA,
+ Province.THRAKESION,
+ Province.OPSIKION,
+ Province.SYRIA,
+ Province.LEBANON,
+ Province.JERUSALEM,
+ Province.EGYPT,
+]
+tOttomanWonders = [
+ Wonder.TOPKAPI_PALACE,
+ Wonder.BLUE_MOSQUE,
+ Wonder.SELIMIYE_MOSQUE,
+ Wonder.TOMB_AL_WALID,
+]
+tOttomanControlII = [Province.AUSTRIA, Province.PANNONIA, Province.LESSER_POLAND]
+tMoscowControl = [
+ Province.DONETS,
+ Province.KUBAN,
+ Province.ZAPORIZHIA,
+ Province.SLOBODA,
+ Province.KIEV,
+ Province.MOLDOVA,
+ Province.CRIMEA,
+ Province.PEREYASLAVL,
+ Province.CHERNIGOV,
+ Province.SIMBIRSK,
+ Province.NIZHNYNOVGOROD,
+ Province.VOLOGDA,
+ Province.ROSTOV,
+ Province.NOVGOROD,
+ Province.KARELIA,
+ Province.SMOLENSK,
+ Province.POLOTSK,
+ Province.MINSK,
+ Province.VOLHYNIA,
+ Province.PODOLIA,
+ Province.MOSCOW,
+ Province.MUROM,
+]
+# tSwedenControlI = [ Province.GOTALAND, Province.SVEALAND, Province.NORRLAND, Province.SKANELAND, Province.GOTLAND, Province.OSTERLAND ]
+# tSwedenControlII = [ Province.SAXONY, Province.BRANDENBURG, Province.HOLSTEIN, Province.POMERANIA, Province.PRUSSIA, Province.GREATER_POLAND, Province.MASOVIA, Province.SUVALKIJA, Province.LITHUANIA, Province.LIVONIA, Province.ESTONIA, Province.SMOLENSK, Province.POLOTSK, Province.MINSK, Province.MUROM, Province.CHERNIGOV, Province.MOSCOW, Province.NOVGOROD, Province.ROSTOV ]
+tSwedenControl = [Province.NORRLAND, Province.OSTERLAND, Province.KARELIA]
+tNovgorodControl = [
+ Province.NOVGOROD,
+ Province.KARELIA,
+ Province.ESTONIA,
+ Province.LIVONIA,
+ Province.ROSTOV,
+ Province.VOLOGDA,
+ Province.OSTERLAND,
+]
+# tNovgorodControlII = [ Province.KARELIA, Province.VOLOGDA ]
+tMoroccoControl = [
+ Province.MOROCCO,
+ Province.MARRAKESH,
+ Province.FEZ,
+ Province.TETOUAN,
+ Province.ORAN,
+ Province.ALGIERS,
+ Province.IFRIQIYA,
+ Province.ANDALUSIA,
+ Province.VALENCIA,
+ Province.BALEARS,
+]
+tAragonControlI = [
+ Province.CATALONIA,
+ Province.VALENCIA,
+ Province.BALEARS,
+ Province.SICILY,
+]
+tAragonControlII = [
+ Province.CATALONIA,
+ Province.VALENCIA,
+ Province.ARAGON,
+ Province.BALEARS,
+ Province.CORSICA,
+ Province.SARDINIA,
+ Province.SICILY,
+ Province.CALABRIA,
+ Province.APULIA,
+ Province.PROVENCE,
+ Province.THESSALY,
+]
+tPrussiaControlI = [
+ Province.LITHUANIA,
+ Province.SUVALKIJA,
+ Province.LIVONIA,
+ Province.ESTONIA,
+ Province.POMERANIA,
+ Province.PRUSSIA,
+]
+tPrussiaDefeat = [
+ Civ.AUSTRIA,
+ Civ.MOSCOW,
+ Civ.GERMANY,
+ Civ.SWEDEN,
+ Civ.FRANCE,
+ Civ.CASTILE,
+]
+tScotlandControl = [
+ Province.SCOTLAND,
+ Province.THE_ISLES,
+ Province.IRELAND,
+ Province.WALES,
+ Province.BRETAGNE,
+]
+tDenmarkControlI = [
+ Province.DENMARK,
+ Province.SKANELAND,
+ Province.GOTALAND,
+ Province.SVEALAND,
+ Province.MERCIA,
+ Province.LONDON,
+ Province.EAST_ANGLIA,
+ Province.NORTHUMBRIA,
+]
+# tDenmarkControlII = [ Province.BRANDENBURG, Province.POMERANIA, Province.ESTONIA ]
+tDenmarkControlIII = [
+ Province.DENMARK,
+ Province.NORWAY,
+ Province.VESTFOLD,
+ Province.SKANELAND,
+ Province.GOTALAND,
+ Province.SVEALAND,
+ Province.NORRLAND,
+ Province.GOTLAND,
+ Province.OSTERLAND,
+ Province.ESTONIA,
+ Province.ICELAND,
+]
+
+# tHugeHungaryControl = ( 0, 23, 99, 72 )
+totalLand = gc.getMap().getLandPlots()
+
+
+@handler("GameStart")
+def setup():
+ # ignore AI goals
+ bIgnoreAI = gc.getDefineINT("NO_AI_UHV_CHECKS") == 1
+ data.bIgnoreAIUHV = bIgnoreAI
+ if bIgnoreAI:
+ for iPlayer in civilizations().majors().ids():
+ if human() != iPlayer:
+ setAllUHVFailed(iPlayer)
+
+
+def setAllUHVFailed(iCiv):
+ pPlayer = gc.getPlayer(iCiv)
+ for i in range(3):
+ pPlayer.setUHV(i, 0)
+
+
+def isIgnoreAI():
+ return data.bIgnoreAIUHV
+
+
+@handler("cityBuilt")
+def portugal_uhv_1(city):
+ # Portugal UHV 1: Settle 3 cities on the Azores, Canaries and Madeira and 2 in Morocco, Tetouan and Oran
+ iPlayer = city.getOwner()
+ if iPlayer == Civ.PORTUGAL:
+ if isPossibleUHV(iPlayer, 0, False):
+ iProv = city.getProvince()
+ if iProv in tPortugalControlI or iProv in tPortugalControlII:
+ iCounter = player(Civ.PORTUGAL).getUHVCounter(0)
+ iIslands = iCounter % 100
+ iAfrica = iCounter / 100
+ if iProv in tPortugalControlI:
+ iIslands += 1
+ else:
+ iAfrica += 1
+ if iIslands >= 3 and iAfrica >= 2:
+ wonUHV(Civ.PORTUGAL, 0)
+ player(Civ.PORTUGAL).setUHVCounter(0, iAfrica * 100 + iIslands)
+
+
+@handler("religionFounded")
+def onReligionFounded(iReligion, iFounder):
+ # Germany UHV 2: Start the Reformation (Found Protestantism)
+ if iReligion == Religion.PROTESTANTISM:
+ if iFounder == Civ.GERMANY:
+ wonUHV(Civ.GERMANY, 1)
+ else:
+ lostUHV(Civ.GERMANY, 1)
+
+
+@handler("cityAcquired")
+def onCityAcquired(owner, iNewOwner, city, bConquest, bTrade):
+ if not gc.getGame().isVictoryValid(7): # Victory 7 == historical
+ return
+
+ iPlayer = owner
+ iGameTurn = turn()
+
+ # Bulgaria UHV 3: Do not lose a city to Barbarians, Mongols, Byzantines, or Ottomans before 1396
+ if iPlayer == Civ.BULGARIA:
+ if isPossibleUHV(iPlayer, 2, False):
+ if iGameTurn <= year(1396):
+ if iNewOwner in [Civ.BARBARIAN, Civ.BYZANTIUM, Civ.OTTOMAN]:
+ # conquered and flipped cities always count
+ # for traded cities, there should be a distinction between traded in peace (gift) and traded in ending a war (peace negotiations)
+ # instead of that, we check if the civ is at peace when the trade happens
+ # TODO#BUG# unfortunately the trade deal just ending a war is taken into account as a peace deal - maybe check if there was a war in this turn, or the last couple turns?
+ if not bTrade:
+ lostUHV(Civ.BULGARIA, 2)
+ else:
+ bIsAtWar = False
+ for civ in civilizations().take(Civ.BYZANTIUM, Civ.OTTOMAN).alive():
+ if civilization(Civ.BULGARIA).at_war(civ):
+ bIsAtWar = True
+ if bIsAtWar:
+ lostUHV(Civ.BULGARIA, 2)
+
+ # Portugal UHV 2: Do not lose a city before 1640
+ elif iPlayer == Civ.PORTUGAL:
+ if isPossibleUHV(iPlayer, 1, False):
+ # conquered and flipped cities always count
+ # for traded cities, there should be a distinction between traded in peace (gift) and traded in ending a war (peace negotiations)
+ # instead of that, we check if the civ is at peace when the trade happens
+ # TODO#BUG# unfortunately the trade deal just ending a war is taken into account as a peace deal - maybe check if there was a war in this turn, or the last couple turns?
+ if not bTrade:
+ lostUHV(Civ.PORTUGAL, 1)
+ else:
+ bIsAtWar = False
+ for civ in civilizations().majors().alive():
+ if civilization(Civ.BULGARIA).at_war(civ):
+ bIsAtWar = True
+ break
+ if bIsAtWar:
+ lostUHV(Civ.PORTUGAL, 1)
+
+ # Norway UHV 1: Going Viking
+ elif iNewOwner == Civ.NORWAY and iGameTurn < year(1066) + 2:
+ # Absinthe: city is already reduced by 1 on city conquest, so city.getPopulation() is one less than the original size (unless it was already 1)
+ if bConquest:
+ if city.getPopulation() > 1:
+ player(Civ.NORWAY).setUHVCounter(
+ 0, player(Civ.NORWAY).getUHVCounter(0) + city.getPopulation() + 1
+ )
+ else:
+ player(Civ.NORWAY).setUHVCounter(
+ 0, player(Civ.NORWAY).getUHVCounter(0) + city.getPopulation()
+ )
+
+ # Poland UHV 3: Construct 3 Catholic and Orthodox Cathedrals, 2 Protestant Cathedrals, and have at least 2 Jewish Quarters in your cities
+ elif iNewOwner == Civ.POLAND:
+ if isPossibleUHV(iNewOwner, 2, False):
+ if city.hasBuilding(
+ Wonder.KAZIMIERZ
+ ): # you cannot acquire religious buildings on conquest, only wonders
+ iCounter = player(Civ.POLAND).getUHVCounter(2)
+ iCathCath = (iCounter / 10000) % 10
+ iOrthCath = (iCounter / 1000) % 10
+ iProtCath = (iCounter / 100) % 10
+ iJewishQu = 99
+ iCounter = iJewishQu + 100 * iProtCath + 1000 * iOrthCath + 10000 * iCathCath
+ player(Civ.POLAND).setUHVCounter(2, iCounter)
+ if iCathCath >= 3 and iOrthCath >= 2 and iProtCath >= 2 and iJewishQu >= 2:
+ wonUHV(Civ.POLAND, 2)
+
+ # Prussia UHV 2: Conquer two cities from each of Austria, Muscovy, Germany, Sweden, France and Spain between 1650 and 1763, if they are still alive
+ elif iNewOwner == Civ.PRUSSIA:
+ if isPossibleUHV(iNewOwner, 1, False):
+ if owner in tPrussiaDefeat and year(1650) <= iGameTurn <= year(1763):
+ lNumConq = []
+ iConqRaw = player(Civ.PRUSSIA).getUHVCounter(1)
+ bConq = True
+ for iI in range(len(tPrussiaDefeat)):
+ lNumConq.append((iConqRaw / pow(10, iI)) % 10)
+ if tPrussiaDefeat[iI] == owner:
+ lNumConq[iI] += 1
+ if lNumConq[iI] > 9:
+ # Prevent overflow
+ lNumConq[iI] = 9
+ if lNumConq[iI] < 2 and gc.getPlayer(tPrussiaDefeat[iI]).isAlive():
+ bConq = False
+
+ if bConq:
+ wonUHV(Civ.PRUSSIA, 1)
+
+ iConqRaw = 0
+ for iI in range(len(tPrussiaDefeat)):
+ iConqRaw += lNumConq[iI] * pow(10, iI)
+ player(Civ.PRUSSIA).setUHVCounter(1, iConqRaw)
+
+
+@handler("cityRazed")
+def onCityRazed(city, iPlayer):
+ # Sweden UHV 2: Raze 5 Catholic cities while being Protestant by 1660
+ if iPlayer == Civ.SWEDEN:
+ if isPossibleUHV(iPlayer, 1, False):
+ if civilization(Civ.SWEDEN).has_state_religion(
+ Religion.PROTESTANTISM
+ ) and city.isHasReligion(Religion.CATHOLICISM):
+ iRazed = player(Civ.SWEDEN).getUHVCounter(1) + 1
+ player(Civ.SWEDEN).setUHVCounter(1, iRazed)
+ if iRazed >= 5:
+ wonUHV(Civ.SWEDEN, 1)
+
+
+@handler("unitPillage")
+def onPillageImprovement(pUnit, iImprovement, iRoute, iOwner):
+ # Norway UHV 1: Going Viking
+ if pUnit.getOwner() == Civ.NORWAY and iRoute == -1 and turn() < year(1066) + 2:
+ if plot(pUnit).getOwner() != Civ.NORWAY:
+ player(Civ.NORWAY).setUHVCounter(0, player(Civ.NORWAY).getUHVCounter(0) + 1)
+
+
+@handler("techAcquired")
+def onTechAcquired(iTech, iTeam, iPlayer):
+ if not gc.getGame().isVictoryValid(7): # 7 == historical
+ return
+
+ # England UHV 3: Be the first to enter the Industrial age
+ if iTech == Technology.INDUSTRIAL_TECH:
+ if isPossibleUHV(Civ.ENGLAND, 2, False):
+ if iPlayer == Civ.ENGLAND:
+ wonUHV(Civ.ENGLAND, 2)
+ else:
+ lostUHV(Civ.ENGLAND, 2)
+
+
+@handler("buildingBuilt")
+def onBuildingBuilt(city, building_type):
+ if not gc.getGame().isVictoryValid(7): # 7 == historical
+ return
+
+ iPlayer = player(city)
+ # Kiev UHV 1: Build 2 Orthodox cathedrals and 8 Orthodox monasteries by 1250
+ if iPlayer == Civ.KIEV:
+ if isPossibleUHV(iPlayer, 0, False):
+ if building_type in [
+ Building.ORTHODOX_MONASTERY,
+ Building.ORTHODOX_CATHEDRAL,
+ ]:
+ iBuildSoFar = player(Civ.KIEV).getUHVCounter(0)
+ iCathedralCounter = iBuildSoFar % 100
+ iMonasteryCounter = iBuildSoFar / 100
+ if building_type == Building.ORTHODOX_MONASTERY:
+ iMonasteryCounter += 1
+ else:
+ iCathedralCounter += 1
+ if iCathedralCounter >= 2 and iMonasteryCounter >= 8:
+ wonUHV(Civ.KIEV, 0)
+ player(Civ.KIEV).setUHVCounter(0, 100 * iMonasteryCounter + iCathedralCounter)
+
+ # Poland UHV 3: Construct 3 Catholic and Orthodox Cathedrals, 2 Protestant Cathedrals, and have at least 2 Jewish Quarters in your cities
+ # HHG: Polish UHV3 now uses Wonder Kazimierz with maximum value 99, and all other buildings have boundary checks
+ elif iPlayer == Civ.POLAND:
+ if isPossibleUHV(iPlayer, 2, False):
+ lBuildingList = [
+ Building.CATHOLIC_CATHEDRAL,
+ Building.ORTHODOX_CATHEDRAL,
+ Building.PROTESTANT_CATHEDRAL,
+ Building.JEWISH_QUARTER,
+ Wonder.KAZIMIERZ,
+ ]
+ if building_type in lBuildingList:
+ iCounter = player(Civ.POLAND).getUHVCounter(2)
+ iCathCath = (iCounter / 10000) % 10
+ iOrthCath = (iCounter / 1000) % 10
+ iProtCath = (iCounter / 100) % 10
+ iJewishQu = iCounter % 100
+ if building_type == Building.CATHOLIC_CATHEDRAL and iCathCath < 9:
+ iCathCath += 1
+ elif building_type == Building.ORTHODOX_CATHEDRAL and iOrthCath < 9:
+ iOrthCath += 1
+ elif building_type == Building.PROTESTANT_CATHEDRAL and iProtCath < 9:
+ iProtCath += 1
+ elif building_type == Wonder.KAZIMIERZ:
+ iJewishQu = 99
+ elif building_type == Building.JEWISH_QUARTER and iJewishQu < 99:
+ iJewishQu += 1
+ if iCathCath >= 3 and iOrthCath >= 3 and iProtCath >= 2 and iJewishQu >= 2:
+ wonUHV(Civ.POLAND, 2)
+ iCounter = iJewishQu + 100 * iProtCath + 1000 * iOrthCath + 10000 * iCathCath
+ player(Civ.POLAND).setUHVCounter(2, iCounter)
+
+ # Cordoba UHV 2: Build the Alhambra, the Gardens of Al-Andalus, and La Mezquita by 1309
+ if building_type in tCordobaWonders:
+ if isPossibleUHV(Civ.CORDOBA, 1, False):
+ if iPlayer == Civ.CORDOBA:
+ iWondersBuilt = player(Civ.CORDOBA).getUHVCounter(1)
+ player(Civ.CORDOBA).setUHVCounter(1, iWondersBuilt + 1)
+ if iWondersBuilt == 2: # so we already had 2 wonders, and this is the 3rd one
+ wonUHV(Civ.CORDOBA, 1)
+ else:
+ lostUHV(Civ.CORDOBA, 1)
+
+ # Ottoman UHV 2: Construct the Topkapi Palace, the Blue Mosque, the Selimiye Mosque and the Tomb of Al-Walid by 1616
+ if building_type in tOttomanWonders:
+ if isPossibleUHV(Civ.OTTOMAN, 1, False):
+ if iPlayer == Civ.OTTOMAN:
+ iWondersBuilt = player(Civ.OTTOMAN).getUHVCounter(1)
+ player(Civ.OTTOMAN).setUHVCounter(1, iWondersBuilt + 1)
+ if iWondersBuilt == 3: # so we already had 3 wonders, and this is the 4th one
+ wonUHV(Civ.OTTOMAN, 1)
+ else:
+ lostUHV(Civ.OTTOMAN, 1)
+
+
+@handler("projectBuilt")
+def onProjectBuilt(city, project):
+ iPlayer = city.getOwner()
+ bColony = isProjectAColony(project)
+ # Absinthe: note that getProjectCount (thus getNumRealColonies too) won't count the latest project/colony
+ # (which was currently built) if called from this function
+ # way more straightforward, and also faster to use the UHVCounters for the UHV checks
+
+ # Venice UHV 3: Be the first to build a Colony from the Age of Discovery (Vinland is from the Viking Age)
+ if isPossibleUHV(Civ.VENECIA, 2, False):
+ if project != Colony.VINLAND:
+ if bColony:
+ if iPlayer == Civ.VENECIA:
+ wonUHV(Civ.VENECIA, 2)
+ else:
+ lostUHV(Civ.VENECIA, 2)
+
+ # France UHV 3: Build 5 Colonies
+ if iPlayer == Civ.FRANCE:
+ if isPossibleUHV(iPlayer, 2, False):
+ if bColony:
+ player(Civ.FRANCE).setUHVCounter(2, player(Civ.FRANCE).getUHVCounter(2) + 1)
+ if player(Civ.FRANCE).getUHVCounter(2) >= 5:
+ wonUHV(Civ.FRANCE, 2)
+
+ # England UHV 2: Build 7 Colonies
+ elif iPlayer == Civ.ENGLAND:
+ if isPossibleUHV(iPlayer, 1, False):
+ if bColony:
+ player(Civ.ENGLAND).setUHVCounter(1, player(Civ.ENGLAND).getUHVCounter(1) + 1)
+ if player(Civ.ENGLAND).getUHVCounter(1) >= 7:
+ wonUHV(Civ.ENGLAND, 1)
+
+ # Spain UHV 2: Have more Colonies than any other nation in 1588 (while having at least 3)
+ # this is only for the Main Screen counter
+ elif iPlayer == Civ.CASTILE:
+ player(Civ.CASTILE).setUHVCounter(1, player(Civ.CASTILE).getUHVCounter(1) + 1)
+
+ # Portugal UHV 3: Build 5 Colonies
+ elif iPlayer == Civ.PORTUGAL:
+ if isPossibleUHV(iPlayer, 2, False):
+ if bColony:
+ player(Civ.PORTUGAL).setUHVCounter(2, player(Civ.PORTUGAL).getUHVCounter(2) + 1)
+ if player(Civ.PORTUGAL).getUHVCounter(2) >= 5:
+ wonUHV(Civ.PORTUGAL, 2)
+
+ # Dutch UHV 2: Build 3 Colonies and complete both Trading Companies
+ elif iPlayer == Civ.DUTCH:
+ if isPossibleUHV(iPlayer, 1, False):
+ if bColony:
+ player(Civ.DUTCH).setUHVCounter(1, player(Civ.DUTCH).getUHVCounter(1) + 1)
+ if player(Civ.DUTCH).getUHVCounter(1) >= 3:
+ iWestCompany = team(Civ.DUTCH).getProjectCount(Project.WEST_INDIA_COMPANY)
+ iEastCompany = team(Civ.DUTCH).getProjectCount(Project.EAST_INDIA_COMPANY)
+ # if the companies are already built previously, or currently being built (one of them is the current project)
+ if project == Project.WEST_INDIA_COMPANY or iWestCompany >= 1:
+ if project == Project.EAST_INDIA_COMPANY or iEastCompany >= 1:
+ wonUHV(Civ.DUTCH, 1)
+
+ # Denmark UHV 3: Build 3 Colonies and complete both Trading Companies
+ elif iPlayer == Civ.DENMARK:
+ if isPossibleUHV(iPlayer, 2, False):
+ if bColony:
+ player(Civ.DENMARK).setUHVCounter(2, player(Civ.DENMARK).getUHVCounter(2) + 1)
+ if player(Civ.DENMARK).getUHVCounter(2) >= 3:
+ iWestCompany = team(Civ.DENMARK).getProjectCount(Project.WEST_INDIA_COMPANY)
+ iEastCompany = team(Civ.DENMARK).getProjectCount(Project.EAST_INDIA_COMPANY)
+ # if the companies are already built previously, or currently being built (one of them is the current project)
+ if project == Project.WEST_INDIA_COMPANY or iWestCompany == 1:
+ if project == Project.EAST_INDIA_COMPANY or iEastCompany == 1:
+ wonUHV(Civ.DENMARK, 2)
+
+
+def getOwnedLuxes(pPlayer):
+ lBonus = [
+ Bonus.SHEEP,
+ Bonus.DYE,
+ Bonus.FUR,
+ Bonus.GEMS,
+ Bonus.GOLD,
+ Bonus.INCENSE,
+ Bonus.IVORY,
+ Bonus.SILK,
+ Bonus.SILVER,
+ Bonus.SPICES,
+ Bonus.WINE,
+ Bonus.HONEY,
+ Bonus.WHALE,
+ Bonus.AMBER,
+ Bonus.COTTON,
+ Bonus.COFFEE,
+ Bonus.TEA,
+ Bonus.TOBACCO,
+ ]
+ iCount = 0
+ for iBonus in lBonus:
+ iCount += pPlayer.countOwnedBonuses(iBonus)
+ return iCount
+
+
+def getOwnedGrain(pPlayer):
+ iCount = 0
+ iCount += pPlayer.countOwnedBonuses(Bonus.WHEAT)
+ iCount += pPlayer.countOwnedBonuses(Bonus.BARLEY)
+ return iCount
+
+
+def isProjectAColony(iProject):
+ if iProject >= len(Project):
+ return True
+ else:
+ return False
+
+
+def getNumRealColonies(iPlayer):
+ pPlayer = gc.getPlayer(iPlayer)
+ tPlayer = gc.getTeam(pPlayer.getTeam())
+ iCount = 0
+ for col in Colony:
+ if tPlayer.getProjectCount(col) > 0:
+ iCount += 1
+ return iCount
+
+
+def getTerritoryPercentEurope(iPlayer, bReturnTotal=False):
+ iTotal = 0
+ iCount = 0
+ for plot in plots.all().land().not_provinces(*REGIONS[Region.NOT_EUROPE]).entities():
+ iTotal += 1
+ if plot.getOwner() == iPlayer:
+ iCount += 1
+ if bReturnTotal:
+ return iCount, iTotal
+ return iCount
+
+
+def checkByzantium(iGameTurn):
+
+ # UHV 1: Own at least 6 cities in Calabria, Apulia, Dalmatia, Verona, Lombardy, Liguria, Tuscany, Latium, Corsica, Sardinia, Sicily, Tripolitania and Ifriqiya provinces in 632
+ if iGameTurn == year(632):
+ if isPossibleUHV(Civ.BYZANTIUM, 0, True):
+ iNumCities = 0
+ for iProv in tByzantiumControl:
+ iNumCities += player(Civ.BYZANTIUM).getProvinceCityCount(iProv)
+ if iNumCities >= 6:
+ wonUHV(Civ.BYZANTIUM, 0)
+ else:
+ lostUHV(Civ.BYZANTIUM, 0)
+
+ # UHV 2: Control Constantinople, Thrace, Thessaloniki, Moesia, Macedonia, Serbia, Arberia, Epirus, Thessaly, Morea, Colonea, Antiochia, Charsianon, Cilicia, Armeniakon, Anatolikon, Paphlagonia, Thrakesion and Opsikion in 1282
+ elif iGameTurn == year(1282):
+ if isPossibleUHV(Civ.BYZANTIUM, 1, True):
+ if checkProvincesStates(Civ.BYZANTIUM, tByzantiumControlII):
+ wonUHV(Civ.BYZANTIUM, 1)
+ else:
+ lostUHV(Civ.BYZANTIUM, 1)
+
+ # UHV 3: Make Constantinople the largest and most cultured city while being the richest empire in the world in 1453
+ elif iGameTurn == year(1453):
+ if isPossibleUHV(Civ.BYZANTIUM, 2, True):
+ x, y = CIV_CAPITAL_LOCATIONS[Civ.BYZANTIUM]
+ iGold = player(Civ.BYZANTIUM).getGold()
+ bMost = True
+ for iCiv in civilizations().majors().ids():
+ if iCiv != Civ.BYZANTIUM and gc.getPlayer(iCiv).isAlive():
+ if gc.getPlayer(iCiv).getGold() > iGold:
+ bMost = False
+ break
+ if (
+ gc.isLargestCity(x, y)
+ and gc.isTopCultureCity(x, y)
+ and gc.getMap().plot(x, y).getPlotCity().getOwner() == Civ.BYZANTIUM
+ and bMost
+ ):
+ wonUHV(Civ.BYZANTIUM, 2)
+ else:
+ lostUHV(Civ.BYZANTIUM, 2)
+
+
+def checkFrankia(iGameTurn):
+
+ # UHV 1: Achieve Charlemagne's Empire by 840
+ if isPossibleUHV(Civ.FRANCE, 0, True):
+ if checkProvincesStates(Civ.FRANCE, tFrankControl):
+ wonUHV(Civ.FRANCE, 0)
+ if iGameTurn == year(840):
+ expireUHV(Civ.FRANCE, 0)
+
+ # UHV 2: Control Jerusalem in 1291
+ elif iGameTurn == year(1291):
+ if isPossibleUHV(Civ.FRANCE, 1, True):
+ pJPlot = gc.getMap().plot(*CITIES[City.JERUSALEM])
+ if pJPlot.isCity():
+ if pJPlot.getPlotCity().getOwner() == Civ.FRANCE:
+ wonUHV(Civ.FRANCE, 1)
+ else:
+ lostUHV(Civ.FRANCE, 1)
+ else:
+ lostUHV(Civ.FRANCE, 1)
+
+ # UHV 3: Build 5 Colonies
+ # handled in the onProjectBuilt function
+
+
+def checkArabia(iGameTurn):
+
+ # UHV 1: Control all territories from Tunisia to Asia Minor in 850
+ if iGameTurn == year(850):
+ if isPossibleUHV(Civ.ARABIA, 0, True):
+ if checkProvincesStates(Civ.ARABIA, tArabiaControlI):
+ wonUHV(Civ.ARABIA, 0)
+ else:
+ lostUHV(Civ.ARABIA, 0)
+
+ # UHV 2: Control the Levant and Egypt in 1291AD while being the most advanced civilization
+ elif iGameTurn == year(1291):
+ if isPossibleUHV(Civ.ARABIA, 1, True):
+ iMostAdvancedCiv = getMostAdvancedCiv()
+ if (
+ checkProvincesStates(Civ.ARABIA, tArabiaControlII)
+ and iMostAdvancedCiv == Civ.ARABIA
+ ):
+ wonUHV(Civ.ARABIA, 1)
+ else:
+ lostUHV(Civ.ARABIA, 1)
+
+ # UHV 3: Spread Islam to at least 35% of the population of Europe
+ if isPossibleUHV(Civ.ARABIA, 2, True):
+ iPerc = gc.getGame().calculateReligionPercent(Religion.ISLAM)
+ if iPerc >= 35:
+ wonUHV(Civ.ARABIA, 2)
+
+
+def checkBulgaria(iGameTurn):
+
+ # UHV 1: Conquer Moesia, Thrace, Macedonia, Serbia, Arberia, Thessaloniki and Constantinople by 917
+ if isPossibleUHV(Civ.BULGARIA, 0, True):
+ if checkProvincesStates(Civ.BULGARIA, tBulgariaControl):
+ wonUHV(Civ.BULGARIA, 0)
+ if iGameTurn == year(917):
+ expireUHV(Civ.BULGARIA, 0)
+
+ # UHV 2: Accumulate at least 100 Orthodox Faith Points by 1259
+ if isPossibleUHV(Civ.BULGARIA, 1, True):
+ if (
+ civilization(Civ.BULGARIA).has_state_religion(Religion.ORTHODOXY)
+ and player(Civ.BULGARIA).getFaith() >= 100
+ ):
+ wonUHV(Civ.BULGARIA, 1)
+ if iGameTurn == year(1259):
+ expireUHV(Civ.BULGARIA, 1)
+
+ # UHV 3: Do not lose a city to Barbarians, Mongols, Byzantines, or Ottomans before 1396
+ # Controlled in the onCityAcquired function
+ elif iGameTurn == year(1396):
+ if isPossibleUHV(Civ.BULGARIA, 2, True):
+ wonUHV(Civ.BULGARIA, 2)
+
+
+def checkCordoba(iGameTurn):
+
+ # UHV 1: Make Cordoba the largest city in the world in 961
+ if iGameTurn == year(961):
+ if isPossibleUHV(Civ.CORDOBA, 0, True):
+ x, y = CIV_CAPITAL_LOCATIONS[Civ.CORDOBA]
+ if (
+ gc.isLargestCity(x, y)
+ and gc.getMap().plot(x, y).getPlotCity().getOwner() == Civ.CORDOBA
+ ):
+ wonUHV(Civ.CORDOBA, 0)
+ else:
+ lostUHV(Civ.CORDOBA, 0)
+
+ # UHV 2: Build the Alhambra, the Gardens of Al-Andalus, and La Mezquita by 1309
+ # Controlled in the onBuildingBuilt function
+ elif iGameTurn == year(1309):
+ expireUHV(Civ.CORDOBA, 1)
+
+ # UHV 3: Make sure Islam is present in every city in the Iberian peninsula in 1492
+ elif iGameTurn == year(1492):
+ if isPossibleUHV(Civ.CORDOBA, 2, True):
+ bIslamized = True
+ for iProv in tCordobaIslamize:
+ if not player(Civ.CORDOBA).provinceIsSpreadReligion(iProv, Religion.ISLAM):
+ bIslamized = False
+ break
+ if bIslamized:
+ wonUHV(Civ.CORDOBA, 2)
+ else:
+ lostUHV(Civ.CORDOBA, 2)
+
+
+def checkNorway(iGameTurn):
+
+ # Old UHV1: explore all water tiles
+ # if ( iGameTurn == year(1009) and pNorway.getUHV( 0 ) == -1 ):
+ # if ( gc.canSeeAllTerrain( iNorway, Terrain.OCEAN ) ):
+ # wonUHV( iNorway, 0 )
+ # else:
+ # lostUHV( iNorway, 0 )
+
+ # UHV 1: Gain 100 Viking Points and build Vinland by 1066
+ # Viking points counted in the onCityAcquired, onPillageImprovement and onCombatResult functions
+ if isPossibleUHV(Civ.NORWAY, 0, True):
+ if (
+ player(Civ.NORWAY).getUHVCounter(0) >= 100
+ and team(Civ.NORWAY).getProjectCount(Colony.VINLAND) >= 1
+ ):
+ wonUHV(Civ.NORWAY, 0)
+ if iGameTurn == year(1066):
+ expireUHV(Civ.NORWAY, 0)
+
+ # UHV 2: Conquer The Isles, Ireland, Scotland, Normandy, Sicily, Apulia, Calabria and Iceland by 1194
+ if iGameTurn <= year(1194):
+ if isPossibleUHV(Civ.NORWAY, 1, True):
+ if checkProvincesStates(Civ.NORWAY, tNorwayControl):
+ wonUHV(Civ.NORWAY, 1)
+ if iGameTurn == year(1194):
+ expireUHV(Civ.NORWAY, 1)
+
+ # UHV 3: Have a higher score than Sweden, Denmark, Scotland, England, Germany and France in 1320
+ elif iGameTurn == year(1320):
+ if isPossibleUHV(Civ.NORWAY, 2, True):
+ iNorwayRank = gc.getGame().getTeamRank(Civ.NORWAY)
+ bIsOnTop = True
+ for iTestPlayer in tNorwayOutrank:
+ if gc.getGame().getTeamRank(iTestPlayer) < iNorwayRank:
+ bIsOnTop = False
+ break
+ if bIsOnTop:
+ wonUHV(Civ.NORWAY, 2)
+ else:
+ lostUHV(Civ.NORWAY, 2)
+
+
+def checkDenmark(iGameTurn):
+
+ # UHV 1: Control Denmark, Skaneland, G�taland, Svealand, Mercia, London, Northumbria and East Anglia in 1050
+ if iGameTurn == year(1050):
+ if isPossibleUHV(Civ.DENMARK, 0, True):
+ if checkProvincesStates(Civ.DENMARK, tDenmarkControlI):
+ wonUHV(Civ.DENMARK, 0)
+ else:
+ lostUHV(Civ.DENMARK, 0)
+
+ # UHV 2: Control Denmark, Norway, Vestfold, Skaneland, G�taland, Svealand, Norrland, Gotland, �sterland, Estonia and Iceland in 1523
+ elif iGameTurn == year(1523):
+ if isPossibleUHV(Civ.DENMARK, 1, True):
+ if checkProvincesStates(Civ.DENMARK, tDenmarkControlIII):
+ wonUHV(Civ.DENMARK, 1)
+ else:
+ lostUHV(Civ.DENMARK, 1)
+
+ # UHV 3: Build 3 Colonies and complete both Trading Companies
+ # handled in the onProjectBuilt function
+
+
+def checkVenecia(iGameTurn):
+
+ # UHV 1: Conquer the Adriatic by 1004
+ if isPossibleUHV(Civ.VENECIA, 0, True):
+ if checkProvincesStates(Civ.VENECIA, tVenetianControl):
+ wonUHV(Civ.VENECIA, 0)
+ if iGameTurn == year(1004):
+ expireUHV(Civ.VENECIA, 0)
+
+ # UHV 2: Conquer Constantinople, Thessaly, Morea, Crete and Cyprus by 1204
+ if isPossibleUHV(Civ.VENECIA, 1, True):
+ if (
+ player(Civ.VENECIA).getProvinceCurrentState(Province.CONSTANTINOPLE)
+ >= ProvinceStatus.CONQUER
+ ):
+ if checkProvincesStates(Civ.VENECIA, tVenetianControlII):
+ wonUHV(Civ.VENECIA, 1)
+ if iGameTurn == year(1204):
+ expireUHV(Civ.VENECIA, 1)
+
+ # UHV 3: Be the first to build a Colony from the Age of Discovery
+ # UHV 3: Vinland is from the Viking Age, all other Colonies are from the Age of Discovery
+ # handled in the onProjectBuilt function
+
+
+def checkBurgundy(iGameTurn):
+
+ # UHV 1: Produce 12,000 culture points in your cities by 1336
+ # The counter should be updated until the deadline for the challenge UHVs, even after UHV completion
+ if iGameTurn < year(1336) + 2:
+ iCulture = (
+ player(Civ.BURGUNDY).getUHVCounter(0) + player(Civ.BURGUNDY).countCultureProduced()
+ )
+ player(Civ.BURGUNDY).setUHVCounter(0, iCulture)
+ if isPossibleUHV(Civ.BURGUNDY, 0, True):
+ if iCulture >= 12000:
+ wonUHV(Civ.BURGUNDY, 0)
+ if iGameTurn == year(1336):
+ expireUHV(Civ.BURGUNDY, 0)
+
+ # UHV 2: Control Burgundy, Provence, Picardy, Flanders, Champagne and Lorraine in 1376
+ elif iGameTurn == year(1376):
+ if isPossibleUHV(Civ.BURGUNDY, 1, True):
+ if checkProvincesStates(Civ.BURGUNDY, tBurgundyControl):
+ wonUHV(Civ.BURGUNDY, 1)
+ else:
+ lostUHV(Civ.BURGUNDY, 1)
+
+ # UHV 3: Have a higher score than France, England and Germany in 1473
+ elif iGameTurn == year(1473):
+ if isPossibleUHV(Civ.BURGUNDY, 2, True):
+ iBurgundyRank = gc.getGame().getTeamRank(Civ.BURGUNDY)
+ bIsOnTop = True
+ for iTestPlayer in tBurgundyOutrank:
+ if gc.getGame().getTeamRank(iTestPlayer) < iBurgundyRank:
+ bIsOnTop = False
+ break
+ if bIsOnTop:
+ wonUHV(Civ.BURGUNDY, 2)
+ else:
+ lostUHV(Civ.BURGUNDY, 2)
+
+
+def checkGermany(iGameTurn):
+
+ # Old UHVs: Have most Catholic FPs in 1077 (Walk to Canossa)
+ # Have 3 vassals
+
+ # UHV 1: Control Lorraine, Swabia, Saxony, Bavaria, Franconia, Brandenburg, Holstein, Lombardy, Liguria and Tuscany in 1167
+ if iGameTurn == year(1167):
+ if isPossibleUHV(Civ.GERMANY, 0, True):
+ if checkProvincesStates(Civ.GERMANY, tGermanyControl):
+ wonUHV(Civ.GERMANY, 0)
+ else:
+ lostUHV(Civ.GERMANY, 0)
+
+ # UHV 2: Start the Reformation (Found Protestantism)
+ # Controlled in the onReligionFounded function
+
+ # UHV 3: Control Swabia, Saxony, Bavaria, Franconia, Brandenburg, Holstein, Flanders, Pomerania, Silesia, Bohemia, Moravia and Austria in 1648
+ elif iGameTurn == year(1648):
+ if isPossibleUHV(Civ.GERMANY, 2, True):
+ if checkProvincesStates(Civ.GERMANY, tGermanyControlII):
+ wonUHV(Civ.GERMANY, 2)
+ else:
+ lostUHV(Civ.GERMANY, 2)
+
+
+def checkNovgorod(iGameTurn):
+
+ # UHV 1: Control Novgorod, Karelia, Estonia, Livonia, Rostov, Vologda and Osterland in 1284
+ if iGameTurn == year(1284):
+ if isPossibleUHV(Civ.NOVGOROD, 0, True):
+ if checkProvincesStates(Civ.NOVGOROD, tNovgorodControl):
+ wonUHV(Civ.NOVGOROD, 0)
+ else:
+ lostUHV(Civ.NOVGOROD, 0)
+
+ # UHV 2: Control eleven sources of fur by 1397
+ if isPossibleUHV(Civ.NOVGOROD, 1, True):
+ if player(Civ.NOVGOROD).countCultBorderBonuses(Bonus.FUR) >= 11:
+ wonUHV(Civ.NOVGOROD, 1)
+ if iGameTurn == year(1397):
+ expireUHV(Civ.NOVGOROD, 1)
+
+ # UHV 3: Control the province of Moscow or have Muscovy as a vassal in 1478
+ if iGameTurn == year(1478):
+ if isPossibleUHV(Civ.NOVGOROD, 2, True):
+ if (
+ player(Civ.NOVGOROD).getProvinceCurrentState(Province.MOSCOW)
+ >= ProvinceStatus.CONQUER
+ ):
+ wonUHV(Civ.NOVGOROD, 2)
+ elif civilization(Civ.MOSCOW).is_alive() and civilization(Civ.MOSCOW).is_vassal(
+ Civ.NOVGOROD
+ ):
+ wonUHV(Civ.NOVGOROD, 2)
+ else:
+ lostUHV(Civ.NOVGOROD, 2)
+
+
+def checkKiev(iGameTurn):
+
+ # UHV 1: Build 2 Orthodox cathedrals and 8 Orthodox monasteries by 1250
+ # Controlled in the onBuildingBuilt function
+ if iGameTurn == year(1250) + 1:
+ expireUHV(Civ.KIEV, 0)
+
+ # UHV 2: Control 10 provinces out of Kiev, Podolia, Pereyaslavl, Sloboda, Chernigov, Volhynia, Minsk, Polotsk, Smolensk, Moscow, Murom, Rostov, Novgorod and Vologda in 1288
+ elif iGameTurn == year(1288):
+ if isPossibleUHV(Civ.KIEV, 1, True):
+ iConq = 0
+ for iProv in tKievControl:
+ if player(Civ.KIEV).getProvinceCurrentState(iProv) >= ProvinceStatus.CONQUER:
+ iConq += 1
+ if iConq >= 10:
+ wonUHV(Civ.KIEV, 1)
+ else:
+ lostUHV(Civ.KIEV, 1)
+
+ # UHV 3: Produce 25000 food by 1300
+ # The counter should be updated until the deadline for the challenge UHVs, even after UHV completion
+ if iGameTurn < year(1300) + 2:
+ iFood = player(Civ.KIEV).getUHVCounter(2) + player(Civ.KIEV).calculateTotalYield(
+ YieldTypes.YIELD_FOOD
+ )
+ player(Civ.KIEV).setUHVCounter(2, iFood)
+ if isPossibleUHV(Civ.KIEV, 2, True):
+ if iFood > 25000:
+ wonUHV(Civ.KIEV, 2)
+ if iGameTurn == year(1300):
+ expireUHV(Civ.KIEV, 2)
+
+
+def checkHungary(iGameTurn):
+
+ # UHV 1: Control Austria, Carinthia, Moravia, Silesia, Bohemia, Dalmatia, Bosnia, Banat, Wallachia and Moldova in 1490
+ if iGameTurn == year(1490):
+ if isPossibleUHV(Civ.HUNGARY, 0, True):
+ if checkProvincesStates(Civ.HUNGARY, tHungaryControl):
+ wonUHV(Civ.HUNGARY, 0)
+ else:
+ lostUHV(Civ.HUNGARY, 0)
+
+ # UHV 2: Allow no Ottoman cities in Europe in 1541
+ elif iGameTurn == year(1541):
+ if isPossibleUHV(Civ.HUNGARY, 1, True):
+ bClean = True
+ if civilization(Civ.OTTOMAN).is_alive():
+ for iProv in tHungaryControlII:
+ if player(Civ.OTTOMAN).getProvinceCityCount(iProv) > 0:
+ bClean = False
+ break
+ if bClean:
+ wonUHV(Civ.HUNGARY, 1)
+ else:
+ lostUHV(Civ.HUNGARY, 1)
+
+ # UHV 3: Be the first to adopt Free Religion
+ if isPossibleUHV(Civ.HUNGARY, 2, True):
+ iReligiousCivic = player(Civ.HUNGARY).getCivics(4)
+ if iReligiousCivic == Civic.FREE_RELIGION:
+ wonUHV(Civ.HUNGARY, 2)
+ else:
+ for iPlayer in civilizations().majors().ids():
+ pPlayer = gc.getPlayer(iPlayer)
+ if pPlayer.isAlive() and pPlayer.getCivics(4) == Civic.FREE_RELIGION:
+ lostUHV(Civ.HUNGARY, 2)
+
+
+def checkSpain(iGameTurn):
+
+ # UHV 1: Reconquista (make sure Catholicism is the only religion present in every city in the Iberian peninsula in 1492)
+ if iGameTurn == year(1492):
+ if isPossibleUHV(Civ.CASTILE, 0, True):
+ bConverted = True
+ for iProv in tSpainConvert:
+ if not player(Civ.CASTILE).provinceIsConvertReligion(iProv, Religion.CATHOLICISM):
+ bConverted = False
+ break
+ if bConverted:
+ wonUHV(Civ.CASTILE, 0)
+ else:
+ lostUHV(Civ.CASTILE, 0)
+
+ # UHV 2: Have more Colonies than any other nation in 1588, while having at least 3
+ elif iGameTurn == year(1588):
+ if isPossibleUHV(Civ.CASTILE, 1, True):
+ bMost = True
+ iSpainColonies = getNumRealColonies(Civ.CASTILE)
+ for iPlayer in civilizations().majors().ids():
+ if iPlayer != Civ.CASTILE:
+ pPlayer = gc.getPlayer(iPlayer)
+ if pPlayer.isAlive() and getNumRealColonies(iPlayer) >= iSpainColonies:
+ bMost = False
+ if bMost and iSpainColonies >= 3:
+ wonUHV(Civ.CASTILE, 1)
+ else:
+ lostUHV(Civ.CASTILE, 1)
+
+ # UHV 3: Ensure that Catholic nations have more population and more land than any other religion in 1648
+ elif iGameTurn == year(1648):
+ if isPossibleUHV(Civ.CASTILE, 2, True):
+ if player(Civ.CASTILE).getStateReligion() != Religion.CATHOLICISM:
+ lostUHV(Civ.CASTILE, 2)
+ else:
+ lLand = [0, 0, 0, 0, 0, 0] # Prot, Islam, Cath, Orth, Jew, Pagan
+ lPop = [0, 0, 0, 0, 0, 0]
+ for iPlayer in civilizations().majors().ids():
+ pPlayer = gc.getPlayer(iPlayer)
+ iStateReligion = pPlayer.getStateReligion()
+ if iStateReligion > -1:
+ lLand[iStateReligion] += pPlayer.getTotalLand()
+ lPop[iStateReligion] += pPlayer.getTotalPopulation()
+ else:
+ lLand[5] += pPlayer.getTotalLand()
+ lPop[5] += pPlayer.getTotalPopulation()
+ # The Barbarian civ counts as Pagan, Independent cities are included separately, based on the religion of the population
+ lLand[5] += civilizations().barbarian().unwrap().player.getTotalLand()
+ lPop[5] += civilizations().barbarian().unwrap().player.getTotalPopulation()
+ for iIndyCiv in [
+ Civ.INDEPENDENT,
+ Civ.INDEPENDENT_2,
+ Civ.INDEPENDENT_3,
+ Civ.INDEPENDENT_4,
+ ]:
+ for pCity in cities.owner(iIndyCiv).entities():
+ pIndyCiv = gc.getPlayer(iIndyCiv)
+ iAverageCityLand = pIndyCiv.getTotalLand() / pIndyCiv.getNumCities()
+ if pCity.getReligionCount() == 0:
+ lLand[5] += iAverageCityLand
+ lPop[5] += pCity.getPopulation()
+ else:
+ for iReligion in range(len(Religion)):
+ if pCity.isHasReligion(iReligion):
+ lLand[iReligion] += iAverageCityLand / pCity.getReligionCount()
+ lPop[iReligion] += (
+ pCity.getPopulation() / pCity.getReligionCount()
+ )
+
+ iCathLand = lLand[Religion.CATHOLICISM]
+ iCathPop = lPop[Religion.CATHOLICISM]
+
+ bWon = True
+ for iReligion in range(len(Religion) + 1):
+ if iReligion != Religion.CATHOLICISM:
+ if lLand[iReligion] >= iCathLand:
+ bWon = False
+ break
+ if lPop[iReligion] >= iCathPop:
+ bWon = False
+ break
+
+ if bWon:
+ wonUHV(Civ.CASTILE, 2)
+ else:
+ lostUHV(Civ.CASTILE, 2)
+
+
+def checkScotland(iGameTurn):
+
+ # UHV 1: Have 10 Forts and 4 Castles by 1296
+ if isPossibleUHV(Civ.SCOTLAND, 0, True):
+ iForts = player(Civ.SCOTLAND).getImprovementCount(Improvement.FORT)
+ iCastles = player(Civ.SCOTLAND).countNumBuildings(Building.CASTLE)
+ if iForts >= 10 and iCastles >= 4:
+ wonUHV(Civ.SCOTLAND, 0)
+ if iGameTurn == year(1296):
+ expireUHV(Civ.SCOTLAND, 0)
+
+ # UHV 2: Have 1500 Attitude Points with France by 1560 (Attitude Points are added every turn depending on your relations)
+ if isPossibleUHV(Civ.SCOTLAND, 1, True):
+ if civilization(Civ.FRANCE).is_alive():
+ # Being at war with France gives a big penalty (and ignores most bonuses!)
+ if civilization(Civ.SCOTLAND).at_war(Civ.FRANCE):
+ iScore = -10
+ else:
+ # -1 for Furious 0 for Annoyed 1 for Cautious 2 for Pleased 3 for Friendly
+ iScore = player(Civ.FRANCE).AI_getAttitude(Civ.SCOTLAND) - 1
+ # Agreements
+ if team(Civ.FRANCE).isOpenBorders(Civ.SCOTLAND):
+ iScore += 1
+ if team(Civ.FRANCE).isDefensivePact(Civ.SCOTLAND):
+ iScore += 2
+ # Imports/Exports
+ iTrades = 0
+ iTrades += player(Civ.SCOTLAND).getNumTradeBonusImports(Civ.FRANCE)
+ iTrades += player(Civ.FRANCE).getNumTradeBonusImports(Civ.SCOTLAND)
+ iScore += iTrades / 2
+ # Common Wars
+ for iEnemy in civilizations().majors().ids():
+ if iEnemy in [Civ.SCOTLAND, Civ.FRANCE]:
+ continue
+ if team(Civ.FRANCE).isAtWar(iEnemy) and team(Civ.SCOTLAND).isAtWar(iEnemy):
+ iScore += 2
+ # Different religion from France also gives a penalty, same religion gives a bonus (but only if both have a state religion)
+ if (
+ civilization(Civ.SCOTLAND).has_a_state_religion()
+ and civilization(Civ.FRANCE).has_a_state_religion()
+ ):
+ if (
+ civilization(Civ.SCOTLAND).state_religion()
+ != civilization(Civ.FRANCE).state_religion()
+ ):
+ iScore -= 3
+ elif (
+ civilization(Civ.SCOTLAND).state_religion()
+ == civilization(Civ.FRANCE).state_religion()
+ ):
+ iScore += 1
+ iOldScore = player(Civ.SCOTLAND).getUHVCounter(1)
+ iNewScore = iOldScore + iScore
+ player(Civ.SCOTLAND).setUHVCounter(1, iNewScore)
+ if iNewScore >= 1500:
+ wonUHV(Civ.SCOTLAND, 1)
+ if iGameTurn == year(1560):
+ expireUHV(Civ.SCOTLAND, 1)
+
+ # UHV 3: Control Scotland, The Isles, Ireland, Wales, Brittany and Galicia in 1700
+ elif iGameTurn == year(1700):
+ if isPossibleUHV(Civ.SCOTLAND, 2, True):
+ if checkProvincesStates(Civ.SCOTLAND, tScotlandControl):
+ wonUHV(Civ.SCOTLAND, 2)
+ else:
+ lostUHV(Civ.SCOTLAND, 2)
+
+
+def checkPoland(iGameTurn):
+
+ # Old UHVs: Don't lose cities until 1772 or conquer Russia until 1772
+ # Vassalize Russia, Germany and Austria
+
+ # UHV 1: Food production between 1500 and 1520
+ if year(1500) <= iGameTurn <= year(1520):
+ if isPossibleUHV(Civ.POLAND, 0, True):
+ iAgriculturePolish = player(Civ.POLAND).calculateTotalYield(YieldTypes.YIELD_FOOD)
+ bFood = True
+ for iPlayer in civilizations().majors().ids():
+ if (
+ gc.getPlayer(iPlayer).calculateTotalYield(YieldTypes.YIELD_FOOD)
+ > iAgriculturePolish
+ ):
+ bFood = False
+ break
+ if bFood:
+ wonUHV(Civ.POLAND, 0)
+ if iGameTurn == year(1520) + 1:
+ expireUHV(Civ.POLAND, 0)
+
+ # UHV 2: Own at least 12 cities in the given provinces in 1569
+ elif iGameTurn == year(1569):
+ if isPossibleUHV(Civ.POLAND, 1, True):
+ iNumCities = 0
+ for iProv in tPolishControl:
+ iNumCities += player(Civ.POLAND).getProvinceCityCount(iProv)
+ if iNumCities >= 12:
+ wonUHV(Civ.POLAND, 1)
+ else:
+ lostUHV(Civ.POLAND, 1)
+
+ # UHV 3: Construct 3 Catholic and Orthodox Cathedrals, 2 Protestant Cathedrals, and have at least 2 Jewish Quarters in your cities
+ # Controlled in the onBuildingBuilt and onCityAcquired functions
+
+
+def checkGenoa(iGameTurn):
+
+ # UHV 1: Control Corsica, Sardinia, Crete, Rhodes, Thrakesion, Cyprus and Crimea in 1400
+ if iGameTurn == year(1400):
+ if isPossibleUHV(Civ.GENOA, 0, True):
+ if checkProvincesStates(Civ.GENOA, tGenoaControl):
+ wonUHV(Civ.GENOA, 0)
+ else:
+ lostUHV(Civ.GENOA, 0)
+
+ # UHV 2: Have the largest total amount of commerce from foreign Trade Route Exports and Imports in 1566
+ # UHV 2: Export is based on your cities' trade routes with foreign cities, import is based on foreign cities' trade routes with your cities
+ elif iGameTurn == year(1566):
+ if isPossibleUHV(Civ.GENOA, 1, True):
+ iGenoaTrade = player(Civ.GENOA).calculateTotalImports(
+ YieldTypes.YIELD_COMMERCE
+ ) + player(Civ.GENOA).calculateTotalExports(YieldTypes.YIELD_COMMERCE)
+ bLargest = True
+ for iPlayer in civilizations().majors().ids():
+ if iPlayer != Civ.GENOA:
+ pPlayer = gc.getPlayer(iPlayer)
+ if (
+ pPlayer.calculateTotalImports(YieldTypes.YIELD_COMMERCE)
+ + pPlayer.calculateTotalExports(YieldTypes.YIELD_COMMERCE)
+ > iGenoaTrade
+ ):
+ bLargest = False
+ break
+ if bLargest:
+ wonUHV(Civ.GENOA, 1)
+ else:
+ lostUHV(Civ.GENOA, 1)
+
+ # UHV 3: Have 8 Banks and own all Bank of St. George cities in 1625
+ elif iGameTurn == year(1625):
+ if isPossibleUHV(Civ.GENOA, 2, True):
+ iBanks = 0
+ for city in cities.owner(Civ.GENOA).entities():
+ if (
+ city.getNumRealBuilding(Building.BANK) > 0
+ or city.getNumRealBuilding(Building.GENOA_BANK) > 0
+ or city.getNumRealBuilding(Building.ENGLISH_ROYAL_EXCHANGE) > 0
+ ):
+ iBanks += 1
+ iCompanyCities = player(Civ.GENOA).countCorporations(Company.ST_GEORGE)
+ if iBanks >= 8 and iCompanyCities == companies[Company.ST_GEORGE].limit:
+ wonUHV(Civ.GENOA, 2)
+ else:
+ lostUHV(Civ.GENOA, 2)
+
+
+def checkMorocco(iGameTurn):
+
+ # UHV 1: Control Morocco, Marrakesh, Fez, Tetouan, Oran, Algiers, Ifriqiya, Andalusia, Valencia and the Balearic Islands in 1248
+ if iGameTurn == year(1248):
+ if isPossibleUHV(Civ.MOROCCO, 0, True):
+ if checkProvincesStates(Civ.MOROCCO, tMoroccoControl):
+ wonUHV(Civ.MOROCCO, 0)
+ else:
+ lostUHV(Civ.MOROCCO, 0)
+
+ # UHV 2: Have 5000 culture in each of three cities in 1465
+ elif iGameTurn == year(1465):
+ if isPossibleUHV(Civ.MOROCCO, 1, True):
+ iGoodCities = 0
+ for city in cities.owner(Civ.MOROCCO).entities():
+ if city.getCulture(Civ.MOROCCO) >= 5000:
+ iGoodCities += 1
+ if iGoodCities >= 3:
+ wonUHV(Civ.MOROCCO, 1)
+ else:
+ lostUHV(Civ.MOROCCO, 1)
+
+ # UHV 3: Destroy or vassalize Portugal, Spain, and Aragon by 1578
+ if year(1164) <= iGameTurn <= year(1578):
+ if isPossibleUHV(Civ.MOROCCO, 2, True):
+ bConq = True
+ if (
+ (
+ civilization(Civ.CASTILE).is_alive()
+ and not civilization(Civ.CASTILE).is_vassal(Civ.MOROCCO)
+ )
+ or (
+ civilization(Civ.PORTUGAL).is_alive()
+ and not civilization(Civ.PORTUGAL).is_vassal(Civ.MOROCCO)
+ )
+ or (
+ civilization(Civ.ARAGON).is_alive()
+ and not civilization(Civ.ARAGON).is_vassal(Civ.MOROCCO)
+ )
+ ):
+ bConq = False
+
+ if bConq:
+ wonUHV(Civ.MOROCCO, 2)
+ if iGameTurn == year(1578) + 1:
+ expireUHV(Civ.MOROCCO, 2)
+
+
+def checkEngland(iGameTurn):
+
+ # UHV 1: Control London, Wessex, East Anglia, Mercia, Northumbria, Scotland, Wales, Ireland, Normandy, Picardy, Bretagne, Il-de-France, Aquitania and Orleans in 1452
+ if iGameTurn == year(1452):
+ if isPossibleUHV(Civ.ENGLAND, 0, True):
+ if checkProvincesStates(Civ.ENGLAND, tEnglandControl):
+ wonUHV(Civ.ENGLAND, 0)
+ else:
+ lostUHV(Civ.ENGLAND, 0)
+
+ # UHV 2: Build 7 Colonies
+ # Controlled in the onProjectBuilt function
+
+ # UHV 3: Be the first to enter the Industrial age
+ # Controlled in the onTechAcquired function
+
+
+def checkPortugal(iGameTurn):
+
+ # UHV 1: Settle 3 cities on the Azores, Canaries and Madeira and 2 in Morocco, Tetouan and Oran
+ # Controlled in the onCityBuilt function
+
+ # UHV 2: Do not lose a city before 1640
+ # Controlled in the onCityAcquired function
+ if iGameTurn == year(1640):
+ if isPossibleUHV(Civ.PORTUGAL, 1, True):
+ wonUHV(Civ.PORTUGAL, 1)
+
+ # UHV 3: Build 5 Colonies
+ # Controlled in the onProjectBuilt function
+
+
+def checkAragon(iGameTurn):
+
+ # UHV 1: Control Catalonia, Valencia, Balears and Sicily in 1282
+ if iGameTurn == year(1282):
+ if isPossibleUHV(Civ.ARAGON, 0, True):
+ if checkProvincesStates(Civ.ARAGON, tAragonControlI):
+ wonUHV(Civ.ARAGON, 0)
+ else:
+ lostUHV(Civ.ARAGON, 0)
+
+ # UHV 2: Have 12 Consulates of the Sea and 30 Trade Ships in 1444
+ # UHV 2: Ships with at least one cargo space count as Trade Ships
+ elif iGameTurn == year(1444):
+ if isPossibleUHV(Civ.ARAGON, 1, True):
+ iPorts = player(Civ.ARAGON).countNumBuildings(Building.ARAGON_SEAPORT)
+ iCargoShips = getNumberCargoShips(Civ.ARAGON)
+ if iPorts >= 12 and iCargoShips >= 30:
+ wonUHV(Civ.ARAGON, 1)
+ else:
+ lostUHV(Civ.ARAGON, 1)
+
+ # UHV 3: Control Catalonia, Valencia, Aragon, Balears, Corsica, Sardinia, Sicily, Calabria, Apulia, Provence and Thessaly in 1474
+ elif iGameTurn == year(1474):
+ if isPossibleUHV(Civ.ARAGON, 2, True):
+ if checkProvincesStates(Civ.ARAGON, tAragonControlII):
+ wonUHV(Civ.ARAGON, 2)
+ else:
+ lostUHV(Civ.ARAGON, 2)
+
+
+def checkPrussia(iGameTurn):
+
+ # UHV 1: Control Prussia, Suvalkija, Lithuania, Livonia, Estonia, and Pomerania in 1410
+ if iGameTurn == year(1410):
+ if isPossibleUHV(Civ.PRUSSIA, 0, True):
+ if checkProvincesStates(Civ.PRUSSIA, tPrussiaControlI):
+ wonUHV(Civ.PRUSSIA, 0)
+ else:
+ lostUHV(Civ.PRUSSIA, 0)
+
+ # UHV 2: Conquer two cities from each of Austria, Muscovy, Germany, Sweden, France and Spain between 1650 and 1763, if they are still alive
+ # Controlled in the onCityAcquired function
+ if iGameTurn == year(1763) + 1:
+ expireUHV(Civ.PRUSSIA, 1)
+
+ # UHV 3: Settle a total of 15 Great People in your capital
+ # UHV 3: Great People can be settled in any combination, Great Generals included
+ if isPossibleUHV(Civ.PRUSSIA, 2, True):
+ pCapital = player(Civ.PRUSSIA).getCapitalCity()
+ iGPStart = gc.getInfoTypeForString("SPECIALIST_GREAT_PRIEST")
+ iGPEnd = gc.getInfoTypeForString("SPECIALIST_GREAT_SPY")
+ iGPeople = 0
+ for iType in range(iGPStart, iGPEnd + 1):
+ iGPeople += pCapital.getFreeSpecialistCount(iType)
+ if iGPeople >= 15:
+ wonUHV(Civ.PRUSSIA, 2)
+
+
+def checkLithuania(iGameTurn):
+
+ # UHV 1: Accumulate 2500 Culture points without declaring a state religion before 1386
+ # The counter should be updated until the deadline for the challenge UHVs, even after UHV completion
+ if iGameTurn < year(1386) + 2:
+ iCulture = (
+ player(Civ.LITHUANIA).getUHVCounter(0) + player(Civ.LITHUANIA).countCultureProduced()
+ )
+ player(Civ.LITHUANIA).setUHVCounter(0, iCulture)
+ if isPossibleUHV(Civ.LITHUANIA, 0, True):
+ if civilization(Civ.LITHUANIA).has_a_state_religion():
+ lostUHV(Civ.LITHUANIA, 0)
+ else:
+ if iCulture >= 2500:
+ wonUHV(Civ.LITHUANIA, 0)
+ if iGameTurn == year(1386):
+ expireUHV(Civ.LITHUANIA, 0)
+
+ # UHV 2: Control the most territory in Europe in 1430
+ elif iGameTurn == year(1430):
+ if isPossibleUHV(Civ.LITHUANIA, 1, True):
+ bMost = True
+ iCount = getTerritoryPercentEurope(Civ.LITHUANIA)
+ for iOtherPlayer in civilizations().majors().ids():
+ if not gc.getPlayer(iOtherPlayer).isAlive() or iOtherPlayer == Civ.LITHUANIA:
+ continue
+ iOtherCount = getTerritoryPercentEurope(iOtherPlayer)
+ if iOtherCount >= iCount:
+ bMost = False
+ break
+ if bMost:
+ wonUHV(Civ.LITHUANIA, 1)
+ else:
+ lostUHV(Civ.LITHUANIA, 1)
+
+ # UHV 3: Destroy or Vassalize Muscovy, Novgorod and Prussia by 1795
+ if year(1380) <= iGameTurn <= year(1795):
+ if isPossibleUHV(Civ.LITHUANIA, 2, True):
+ bConq = True
+ if (
+ (
+ civilization(Civ.MOSCOW).is_alive()
+ and not civilization(Civ.MOSCOW).is_vassal(Civ.LITHUANIA)
+ )
+ or (
+ civilization(Civ.NOVGOROD).is_alive()
+ and not civilization(Civ.NOVGOROD).is_vassal(Civ.LITHUANIA)
+ )
+ or (
+ civilization(Civ.PRUSSIA).is_alive()
+ and not civilization(Civ.PRUSSIA).is_vassal(Civ.LITHUANIA)
+ )
+ ):
+ bConq = False
+
+ if bConq:
+ wonUHV(Civ.LITHUANIA, 2)
+ if iGameTurn == year(1795) + 1:
+ expireUHV(Civ.LITHUANIA, 2)
+
+
+def checkAustria(iGameTurn):
+
+ # UHV 1: Control all of medieval Austria, Hungary and Bohemia in 1617
+ if iGameTurn == year(1617):
+ if isPossibleUHV(Civ.AUSTRIA, 0, True):
+ if checkProvincesStates(Civ.AUSTRIA, tAustriaControl):
+ wonUHV(Civ.AUSTRIA, 0)
+ else:
+ lostUHV(Civ.AUSTRIA, 0)
+
+ # UHV 2: Have 3 vassals in 1700
+ elif iGameTurn == year(1700):
+ if isPossibleUHV(Civ.AUSTRIA, 1, True):
+ iCount = 0
+ for iPlayer in civilizations().majors().ids():
+ if iPlayer == Civ.AUSTRIA:
+ continue
+ pPlayer = gc.getPlayer(iPlayer)
+ if pPlayer.isAlive():
+ if gc.getTeam(pPlayer.getTeam()).isVassal(team(Civ.AUSTRIA).getID()):
+ iCount += 1
+ if iCount >= 3:
+ wonUHV(Civ.AUSTRIA, 1)
+ else:
+ lostUHV(Civ.AUSTRIA, 1)
+
+ # UHV 3: Have the highest score in 1780
+ elif iGameTurn == year(1780):
+ if isPossibleUHV(Civ.AUSTRIA, 2, True):
+ if gc.getGame().getTeamRank(Civ.AUSTRIA) == 0:
+ wonUHV(Civ.AUSTRIA, 2)
+ else:
+ lostUHV(Civ.AUSTRIA, 2)
+
+
+def checkTurkey(iGameTurn):
+
+ # UHV 1: Control Constantinople, the Balkans, Anatolia, the Levant and Egypt in 1517
+ if iGameTurn == year(1517):
+ if isPossibleUHV(Civ.OTTOMAN, 0, True):
+ if checkProvincesStates(Civ.OTTOMAN, tOttomanControlI):
+ wonUHV(Civ.OTTOMAN, 0)
+ else:
+ lostUHV(Civ.OTTOMAN, 0)
+
+ # UHV 2: Construct the Topkapi Palace, the Blue Mosque, the Selimiye Mosque and the Tomb of Al-Walid by 1616
+ # Controlled in the onBuildingBuilt function
+ elif iGameTurn == year(1616):
+ expireUHV(Civ.OTTOMAN, 1)
+
+ # UHV 3: Conquer Austria, Pannonia and Lesser Poland by 1683
+ if isPossibleUHV(Civ.OTTOMAN, 2, True):
+ if checkProvincesStates(Civ.OTTOMAN, tOttomanControlII):
+ wonUHV(Civ.OTTOMAN, 2)
+ if iGameTurn == year(1683):
+ expireUHV(Civ.OTTOMAN, 2)
+
+
+def checkMoscow(iGameTurn):
+
+ # UHV 1: Free Eastern Europe from the Mongols (Make sure there are no Mongol (or any other Barbarian) cities in Russia and Ukraine in 1482)
+ if iGameTurn == year(1482):
+ if isPossibleUHV(Civ.MOSCOW, 0, True):
+ bClean = True
+ for iProv in tMoscowControl:
+ if civilizations().barbarian().unwrap().player.getProvinceCityCount(iProv) > 0:
+ bClean = False
+ break
+ if bClean:
+ wonUHV(Civ.MOSCOW, 0)
+ else:
+ lostUHV(Civ.MOSCOW, 0)
+
+ # UHV 2: Control at least 25% of Europe
+ if isPossibleUHV(Civ.MOSCOW, 1, True):
+ totalLand = gc.getMap().getLandPlots()
+ RussianLand = player(Civ.MOSCOW).getTotalLand()
+ if totalLand > 0:
+ landPercent = (RussianLand * 100.0) / totalLand
+ else:
+ landPercent = 0.0
+ if landPercent >= 25:
+ wonUHV(Civ.MOSCOW, 1)
+
+ # UHV 3: Get into warm waters (Conquer Constantinople or control an Atlantic Access resource)
+ if isPossibleUHV(Civ.MOSCOW, 2, True):
+ if player(Civ.MOSCOW).countCultBorderBonuses(Bonus.ACCESS) > 0:
+ wonUHV(Civ.MOSCOW, 2)
+ elif (
+ gc.getMap().plot(*CIV_CAPITAL_LOCATIONS[Civ.BYZANTIUM]).getPlotCity().getOwner()
+ == Civ.MOSCOW
+ ):
+ wonUHV(Civ.MOSCOW, 2)
+
+
+def checkSweden(iGameTurn):
+
+ # Old UHVs: Conquer Gotaland, Svealand, Norrland, Skaneland, Gotland and Osterland in 1600
+ # Don't lose any cities to Poland, Lithuania or Russia before 1700
+ # Have 15 cities in Saxony, Brandenburg, Holstein, Pomerania, Prussia, Greater Poland, Masovia, Suvalkija, Lithuania, Livonia, Estonia, Smolensk, Polotsk, Minsk, Murom, Chernigov, Moscow, Novgorod and Rostov in 1750
+
+ # UHV 1: Have six cities in Norrland, Osterland and Karelia in 1323
+ if iGameTurn == year(1323):
+ if isPossibleUHV(Civ.SWEDEN, 0, True):
+ iNumCities = 0
+ for iProv in tSwedenControl:
+ iNumCities += player(Civ.SWEDEN).getProvinceCityCount(iProv)
+ if iNumCities >= 6:
+ wonUHV(Civ.SWEDEN, 0)
+ else:
+ lostUHV(Civ.SWEDEN, 0)
+
+ # UHV 2: Raze 5 Catholic cities while being Protestant by 1660
+ # Controlled in the onCityRazed function
+ elif iGameTurn == year(1660):
+ expireUHV(Civ.SWEDEN, 1)
+
+ # UHV 3: Control every coastal city on the Baltic Sea in 1750
+ elif iGameTurn == year(1750):
+ if isPossibleUHV(Civ.SWEDEN, 2, True):
+ if UniquePowers.getNumForeignCitiesOnBaltic(Civ.SWEDEN, True) > 0:
+ lostUHV(Civ.SWEDEN, 2)
+ else:
+ wonUHV(Civ.SWEDEN, 2)
+
+
+def checkDutch(iGameTurn):
+
+ # UHV 1: Settle 5 Great Merchants in Amsterdam by 1750
+ if isPossibleUHV(Civ.DUTCH, 0, True):
+ pPlot = gc.getMap().plot(*CIV_CAPITAL_LOCATIONS[Civ.DUTCH])
+ if pPlot.isCity():
+ city = pPlot.getPlotCity()
+ if (
+ city.getFreeSpecialistCount(Specialist.GREAT_MERCHANT) >= 5
+ and city.getOwner() == Civ.DUTCH
+ ):
+ wonUHV(Civ.DUTCH, 0)
+ if iGameTurn == year(1750):
+ expireUHV(Civ.DUTCH, 0)
+
+ # UHV 2: Build 3 Colonies and complete both Trading Companies
+ # Controlled in the onProjectBuilt function
+
+ # UHV 3: Become the richest country in Europe
+ if isPossibleUHV(Civ.DUTCH, 2, True):
+ iGold = player(Civ.DUTCH).getGold()
+ bMost = True
+ for iCiv in civilizations().majors().ids():
+ if iCiv == Civ.DUTCH:
+ continue
+ pPlayer = gc.getPlayer(iCiv)
+ if pPlayer.isAlive():
+ if pPlayer.getGold() > iGold:
+ bMost = False
+ break
+ if bMost:
+ wonUHV(Civ.DUTCH, 2)
+
+
+def checkProvincesStates(iPlayer, tProvinces):
+ pPlayer = gc.getPlayer(iPlayer)
+ for iProv in tProvinces:
+ if pPlayer.getProvinceCurrentState(iProv) < ProvinceStatus.CONQUER:
+ return False
+ return True
+
+
+def wonUHV(iCiv, iUHV):
+ pCiv = gc.getPlayer(iCiv)
+ pCiv.setUHV(iUHV, 1)
+ pCiv.changeStabilityBase(StabilityCategory.EXPANSION, 3)
+ if human() == iCiv:
+ if iUHV == 0:
+ sText = "first"
+ elif iUHV == 1:
+ sText = "second"
+ elif iUHV == 2:
+ sText = "third"
+ show(text("TXT_KEY_VICTORY_UHV_GOAL_WON", sText))
+
+
+def lostUHV(iCiv, iUHV):
+ pCiv = gc.getPlayer(iCiv)
+ pCiv.setUHV(iUHV, 0)
+ if human() == iCiv:
+ if iUHV == 0:
+ sText = "first"
+ elif iUHV == 1:
+ sText = "second"
+ elif iUHV == 2:
+ sText = "third"
+ show(text("TXT_KEY_VICTORY_UHV_GOAL_LOST", sText))
+
+
+def switchUHV(iNewCiv, iOldCiv):
+ pPlayer = gc.getPlayer(iNewCiv)
+ for i in range(3):
+ pPlayer.setUHV(i, -1)
+ if isIgnoreAI():
+ setAllUHVFailed(iOldCiv)
+
+
+def isPossibleUHV(iCiv, iUHV, bAlreadyAIChecked):
+ pCiv = gc.getPlayer(iCiv)
+ if pCiv.getUHV(iUHV) != -1:
+ return False
+ if not pCiv.isAlive():
+ return False
+
+ if not bAlreadyAIChecked:
+ if iCiv != human() and isIgnoreAI(): # Skip calculations if no AI UHV option is enabled
+ return False
+
+ return True
+
+
+def expireUHV(iCiv, iUHV):
+ # UHVs have to expire on the given deadline, even if the civ is not alive currently (would be an issue on respawns otherwise)
+ # if isPossibleUHV(iCiv, iUHV, True):
+ pCiv = gc.getPlayer(iCiv)
+ if pCiv.getUHV(iUHV) == -1:
+ lostUHV(iCiv, iUHV)
+
+
+def set1200UHVDone(iCiv):
+ if iCiv == Civ.BYZANTIUM:
+ player(Civ.BYZANTIUM).setUHV(0, 1)
+ elif iCiv == Civ.FRANCE:
+ player(Civ.FRANCE).setUHV(0, 1)
+ elif iCiv == Civ.ARABIA:
+ player(Civ.ARABIA).setUHV(0, 1)
+ elif iCiv == Civ.BULGARIA:
+ player(Civ.BULGARIA).setUHV(0, 1)
+ elif iCiv == Civ.VENECIA: # Venice gets conquerors near Constantinople for 2nd UHV
+ player(Civ.VENECIA).setUHV(0, 1)
+ elif iCiv == Civ.GERMANY:
+ player(Civ.GERMANY).setUHV(0, 1)
+ elif iCiv == Civ.NORWAY:
+ player(Civ.NORWAY).setUHV(0, 1)
+ elif iCiv == Civ.DENMARK:
+ player(Civ.DENMARK).setUHV(0, 1)
+ elif iCiv == Civ.SCOTLAND:
+ player(Civ.SCOTLAND).setUHVCounter(1, 100)
+
+
+@handler("BeginPlayerTurn")
+def checkPlayerTurn(iGameTurn, iPlayer):
+ switchConditionsPerCiv = {
+ Civ.BYZANTIUM: checkByzantium,
+ Civ.FRANCE: checkFrankia,
+ Civ.ARABIA: checkArabia,
+ Civ.BULGARIA: checkBulgaria,
+ Civ.CORDOBA: checkCordoba,
+ Civ.VENECIA: checkVenecia,
+ Civ.BURGUNDY: checkBurgundy,
+ Civ.GERMANY: checkGermany,
+ Civ.NOVGOROD: checkNovgorod,
+ Civ.NORWAY: checkNorway,
+ Civ.KIEV: checkKiev,
+ Civ.HUNGARY: checkHungary,
+ Civ.CASTILE: checkSpain,
+ Civ.DENMARK: checkDenmark,
+ Civ.SCOTLAND: checkScotland,
+ Civ.POLAND: checkPoland,
+ Civ.GENOA: checkGenoa,
+ Civ.MOROCCO: checkMorocco,
+ Civ.ENGLAND: checkEngland,
+ Civ.PORTUGAL: checkPortugal,
+ Civ.ARAGON: checkAragon,
+ Civ.SWEDEN: checkSweden,
+ Civ.PRUSSIA: checkPrussia,
+ Civ.LITHUANIA: checkLithuania,
+ Civ.AUSTRIA: checkAustria,
+ Civ.OTTOMAN: checkTurkey,
+ Civ.MOSCOW: checkMoscow,
+ Civ.DUTCH: checkDutch,
+ }
+
+ pPlayer = gc.getPlayer(iPlayer)
+ if iPlayer != human() and isIgnoreAI():
+ return
+ if not gc.getGame().isVictoryValid(7): # 7 == historical
+ return
+ if not pPlayer.isAlive():
+ return
+ if iPlayer >= civilizations().main().len():
+ return
+
+ switchConditionsPerCiv[iPlayer](iGameTurn)
+
+ # Generic checks:
+ if not pPlayer.getUHV2of3():
+ if (
+ countAchievedGoals(iPlayer) >= 2
+ ): # in case the last 2 goals were achieved in the same turn
+ # intermediate bonus
+ pPlayer.setUHV2of3(True)
+ if pPlayer.getNumCities() > 0: # this check is needed, otherwise game crashes
+ capital = pPlayer.getCapitalCity()
+ # 3Miro: Golden Age after 2/3 victories
+ capital.setHasRealBuilding(Building.TRIUMPHAL_ARCH, True)
+ if pPlayer.isHuman():
+ message(
+ iPlayer, text("TXT_KEY_VICTORY_INTERMEDIATE"), color=MessageData.PURPLE
+ )
+ for iCiv in civilizations().majors().ids():
+ if iCiv != iPlayer:
+ pCiv = gc.getPlayer(iCiv)
+ if pCiv.isAlive():
+ iAttitude = pCiv.AI_getAttitude(iPlayer)
+ if iAttitude != 0:
+ pCiv.AI_setAttitudeExtra(iPlayer, iAttitude - 1)
+
+ # Absinthe: maximum 3 of your rivals declare war on you
+ lCivs = [
+ iCiv
+ for iCiv in civilizations().main().ids()
+ if iCiv != iPlayer and gc.getPlayer(iCiv).isAlive()
+ ]
+ iWarCounter = 0
+ # we run through a randomized list of all available civs
+ random.shuffle(lCivs)
+ for iCiv in lCivs:
+ pCiv = gc.getPlayer(iCiv)
+ teamCiv = gc.getTeam(pCiv.getTeam())
+ # skip civ if it's vassal (safety check for own vassals, want to look for the master for other vassals)
+ if teamCiv.isAVassal():
+ continue
+ if teamCiv.canDeclareWar(pPlayer.getTeam()):
+ if pCiv.canContact(iPlayer) and not teamCiv.isAtWar(iPlayer):
+ iModifier = 0
+ # bigger chance for civs which hate you
+ if pCiv.AI_getAttitude(iPlayer) == 0:
+ iModifier += 3
+ elif pCiv.AI_getAttitude(iPlayer) == 1:
+ iModifier += 1
+ elif pCiv.AI_getAttitude(iPlayer) == 3:
+ iModifier -= 1
+ elif pCiv.AI_getAttitude(iPlayer) == 4:
+ iModifier -= 3
+ # bigger chance for close civs
+ PlayerCapital = gc.getPlayer(iPlayer).getCapitalCity()
+ CivCapital = gc.getPlayer(iCiv).getCapitalCity()
+ iDistance = calculateDistance(
+ CivCapital.getX(),
+ CivCapital.getY(),
+ PlayerCapital.getX(),
+ PlayerCapital.getY(),
+ )
+ if iDistance < 20:
+ iModifier += 2
+ elif iDistance < 40:
+ iModifier += 1
+ # bigger chance for big civs
+ if pCiv.getNumCities() > 19:
+ iModifier += 4
+ elif pCiv.getNumCities() > 14:
+ iModifier += 3
+ elif pCiv.getNumCities() > 9:
+ iModifier += 2
+ elif pCiv.getNumCities() > 4:
+ iModifier += 1
+ iRndnum = rand(7)
+ if iRndnum + iModifier > 6:
+ teamCiv.declareWar(pPlayer.getTeam(), True, -1)
+ iWarCounter += 1
+ if iWarCounter == 3:
+ break
+ if iWarCounter > 0:
+ message(
+ iPlayer,
+ text("TXT_KEY_VICTORY_RIVAL_CIVS"),
+ color=MessageData.LIGHT_RED,
+ )
+
+ if gc.getGame().getWinner() == -1:
+ if pPlayer.getUHV(0) == 1 and pPlayer.getUHV(1) == 1 and pPlayer.getUHV(2) == 1:
+ gc.getGame().setWinner(iPlayer, 7) # Historical Victory
diff --git a/Assets/Python/Wonders.py b/Assets/Python/Wonders.py
new file mode 100644
index 000000000..de35a5b7f
--- /dev/null
+++ b/Assets/Python/Wonders.py
@@ -0,0 +1,757 @@
+import random
+from CvPythonExtensions import *
+from Core import (
+ city,
+ civilization,
+ civilizations,
+ human,
+ message,
+ message_if_human,
+ player,
+ text,
+ year,
+ cities,
+)
+from CoreTypes import (
+ Building,
+ Civ,
+ Improvement,
+ Project,
+ Promotion,
+ Specialist,
+ StabilityCategory,
+ Unit,
+ Wonder,
+)
+from PyUtils import choice, percentage_chance, rand
+from RFCUtils import getBaseUnit, getUniqueBuilding, getUniqueUnit
+from Events import handler
+from StoredData import data
+from Consts import MessageData, iLighthouseEarthQuake
+
+gc = CyGlobalContext()
+
+
+@handler("cityAcquired")
+def krak_des_chevaliers_acquired(owner, player, city, bConquest, bTrade):
+ # Sedna17: code for Krak des Chevaliers
+ if bConquest:
+ iNewOwner = city.getOwner()
+ pNewOwner = gc.getPlayer(iNewOwner)
+ if pNewOwner.countNumBuildings(Wonder.KRAK_DES_CHEVALIERS) > 0:
+ city.setHasRealBuilding(getUniqueBuilding(iNewOwner, Building.WALLS), True)
+ # Absinthe: if the Castle building were built with the Krak, then it should add stability
+ # the safety checks are probably unnecessary, as Castle buildings are destroyed on conquest (theoretically)
+ if not (
+ city.isHasBuilding(Building.SPANISH_CITADEL)
+ or city.isHasBuilding(Building.MOSCOW_KREMLIN)
+ or city.isHasBuilding(Building.HUNGARIAN_STRONGHOLD)
+ or city.isHasBuilding(Building.CASTLE)
+ ):
+ city.setHasRealBuilding(getUniqueBuilding(iNewOwner, Building.CASTLE), True)
+ pNewOwner.changeStabilityBase(StabilityCategory.EXPANSION, 1)
+
+
+@handler("BeginGameTurn")
+def remove_lighthouse(iGameTurn):
+ # Absinthe: Remove the Great Lighthouse, message for the human player if the city is visible
+ if iGameTurn == year(1323) - 40 + data.lEventRandomness[iLighthouseEarthQuake]:
+ for iPlayer in civilizations().drop(Civ.BARBARIAN).ids():
+ bFound = 0
+ for city in cities.owner(iPlayer).entities():
+ if city.isHasBuilding(Wonder.GREAT_LIGHTHOUSE):
+ city.setHasRealBuilding(Wonder.GREAT_LIGHTHOUSE, False)
+ GLcity = city
+ bFound = 1
+ if bFound and human() == iPlayer:
+ pPlayer = gc.getPlayer(iPlayer)
+ iTeam = pPlayer.getTeam()
+ if GLcity.isRevealed(iTeam, False):
+ message(
+ iPlayer,
+ text("TXT_KEY_BUILDING_GREAT_LIGHTHOUSE_REMOVED"),
+ color=MessageData.RED,
+ )
+
+
+@handler("combatResult")
+def gediminas_tower_effect(pWinner, pLoser):
+ # Absinthe: Gediminas Tower wonder effect: extra city defence on unit win in the city
+ pPlayer = gc.getPlayer(pWinner.getOwner())
+ if pPlayer.countNumBuildings(Wonder.GEDIMINAS_TOWER) > 0:
+ pPlot = pWinner.plot()
+ if pPlot.isCity():
+ pCity = pPlot.getPlotCity()
+ if pCity.getNumActiveBuilding(Wonder.GEDIMINAS_TOWER):
+ pCity.changeDefenseDamage(-10)
+
+
+@handler("improvementBuilt")
+def stephansdom_effect(iImprovement, iX, iY):
+ if iImprovement == Improvement.COTTAGE:
+ pPlot = CyMap().plot(iX, iY)
+ iOwner = pPlot.getOwner()
+ # if there is an owner
+ if iOwner >= 0:
+ pOwner = gc.getPlayer(iOwner)
+ if pOwner.countNumBuildings(Wonder.STEPHANSDOM) > 0:
+ pPlot.setImprovementType(Improvement.HAMLET)
+
+
+@handler("buildingBuilt")
+def leaning_tower_effect(city, building_type):
+ if building_type == Wonder.LEANING_TOWER:
+ iX = city.getX()
+ iY = city.getY()
+ iUnit = Unit.GREAT_PROPHET + rand(7)
+ player(city).initUnit(
+ iUnit,
+ iX,
+ iY,
+ UnitAITypes(gc.getUnitInfo(iUnit).getDefaultUnitAIType()),
+ DirectionTypes.NO_DIRECTION,
+ )
+ if player().isExisting():
+ szText = (
+ text("TXT_KEY_BUILDING_LEANING_TOWER_EFFECT")
+ + " "
+ + gc.getUnitInfo(iUnit).getDescription()
+ )
+ message(
+ human(),
+ szText,
+ event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
+ color=MessageData.LIGHT_BLUE,
+ )
+
+
+def leaning_tower_effect_1200AD():
+ iGP = rand(7)
+ pFlorentia = city(54, 32)
+ iSpecialist = Specialist.GREAT_PROPHET + iGP
+ pFlorentia.setFreeSpecialistCount(iSpecialist, 1)
+
+
+@handler("buildingBuilt")
+def bibliothecas_corviniana_effect(city, building_type):
+ iPlayer = city.getOwner()
+ pPlayer = gc.getPlayer(iPlayer)
+ if building_type == Wonder.BIBLIOTHECA_CORVINIANA:
+ # techs known by the owner civ
+ iTeam = pPlayer.getTeam()
+ pTeam = gc.getTeam(iTeam)
+ lBuilderKnownTechs = []
+ for iTech in xrange(gc.getNumTechInfos()): # type: ignore
+ if pTeam.isHasTech(iTech):
+ lBuilderKnownTechs.append(iTech)
+
+ # techs known by the other civs
+ lOthersKnownTechs = []
+ for iLoopPlayer in civilizations().majors().ids():
+ pLoopPlayer = gc.getPlayer(iLoopPlayer)
+ iLoopTeam = pLoopPlayer.getTeam()
+ pLoopTeam = gc.getTeam(iLoopTeam)
+ # only for known civs
+ if iLoopPlayer != iPlayer and pTeam.isHasMet(iLoopTeam):
+ for iTech in xrange(gc.getNumTechInfos()): # type: ignore
+ if pLoopTeam.isHasTech(iTech):
+ lOthersKnownTechs.append(iTech)
+
+ # collecting the not known techs which are available for at least one other civ
+ # note that we can have the same tech multiple times
+ lPotentialTechs = []
+ for iTech in lOthersKnownTechs:
+ if iTech not in lBuilderKnownTechs:
+ lPotentialTechs.append(iTech)
+
+ if len(lPotentialTechs) > 0:
+ # converting to a set (and then back to a list), as sets only keep unique elements
+ lUniquePotentialTechs = list(set(lPotentialTechs))
+
+ # randomizing the order of the techs
+ random.shuffle(lPotentialTechs)
+
+ # adding the techs, with message for the human player
+ if len(lUniquePotentialTechs) == 1:
+ # add the first instance of the single tech, with message for the human player
+ iChosenTech = lPotentialTechs[0]
+ pTeam.setHasTech(iChosenTech, True, iPlayer, False, True)
+ if iPlayer == human():
+ sText = text(
+ "TXT_KEY_BUILDING_BIBLIOTHECA_CORVINIANA_EFFECT",
+ gc.getTechInfo(iChosenTech).getDescription(),
+ )
+ message(iPlayer, sText, force=True, color=MessageData.LIGHT_BLUE)
+ elif len(lUniquePotentialTechs) > 1:
+ # add two different random techs, with message for the human player
+ for tech in random.sample(lPotentialTechs, 2):
+ pTeam.setHasTech(tech, True, iPlayer, False, True)
+ if iPlayer == human():
+ sText = text(
+ "TXT_KEY_BUILDING_BIBLIOTHECA_CORVINIANA_EFFECT",
+ gc.getTechInfo(tech).getDescription(),
+ )
+ message(iPlayer, sText, force=True, color=MessageData.LIGHT_BLUE)
+
+
+@handler("buildingBuilt")
+def kalmar_castle_effect(city, building_type):
+ iPlayer = city.getOwner()
+ pPlayer = gc.getPlayer(iPlayer)
+ if building_type == Wonder.KALMAR_CASTLE:
+ for neighbour in civilization(iPlayer).location.neighbours:
+ iNeighbour = neighbour
+ pNeighbour = gc.getPlayer(iNeighbour)
+ if pNeighbour.isAlive() and iPlayer != iNeighbour:
+ pPlayer.AI_changeAttitudeExtra(iNeighbour, 3)
+ pNeighbour.AI_changeAttitudeExtra(iPlayer, 3)
+
+
+@handler("buildingBuilt")
+def grand_arsenal_effect(city, building_type):
+ iPlayer = city.getOwner()
+ pPlayer = gc.getPlayer(iPlayer)
+ if building_type == Wonder.GRAND_ARSENAL:
+ iX = city.getX()
+ iY = city.getY()
+ for _ in range(3):
+ # should we have Galleass for all civs, or use the getUniqueUnit function in RFCUtils?
+ pNewUnit = pPlayer.initUnit(
+ Unit.VENICE_GALLEAS,
+ iX,
+ iY,
+ UnitAITypes(gc.getUnitInfo(Unit.VENICE_GALLEAS).getDefaultUnitAIType()),
+ DirectionTypes.DIRECTION_SOUTH,
+ )
+ pNewUnit.setExperience(6, -1)
+ for iPromo in [
+ Promotion.COMBAT,
+ Promotion.LEADERSHIP,
+ Promotion.NAVIGATION,
+ ]:
+ pNewUnit.setHasPromotion(iPromo, True)
+
+
+@handler("buildingBuilt")
+def magellan_voyage_effect(city, building_type):
+ iPlayer = city.getOwner()
+ pPlayer = gc.getPlayer(iPlayer)
+ if building_type == Wonder.MAGELLANS_VOYAGE:
+ iTeam = pPlayer.getTeam()
+ pTeam = gc.getTeam(iTeam)
+ pTeam.changeExtraMoves(gc.getInfoTypeForString("DOMAIN_SEA"), 2)
+
+
+@handler("buildingBuilt")
+def st_catherine_monastery_effect(city, building_type):
+ iPlayer = city.getOwner()
+ pPlayer = gc.getPlayer(iPlayer)
+ if building_type == Wonder.ST_CATHERINE_MONASTERY:
+ iX = city.getX()
+ iY = city.getY()
+ for i in range(2):
+ pPlayer.initUnit(
+ Unit.HOLY_RELIC,
+ iX,
+ iY,
+ UnitAITypes.NO_UNITAI,
+ DirectionTypes.DIRECTION_SOUTH,
+ )
+ message_if_human(
+ iPlayer,
+ text("TXT_KEY_BUILDING_SAINT_CATHERINE_MONASTERY_EFFECT"),
+ color=MessageData.LIGHT_BLUE,
+ )
+
+
+@handler("buildingBuilt")
+def al_azhar_university_effect_on_building_built(city, building_type):
+ iPlayer = city.getOwner()
+ pPlayer = gc.getPlayer(iPlayer)
+ if building_type == Wonder.ALAZHAR:
+ iTeam = pPlayer.getTeam()
+ pTeam = gc.getTeam(iTeam)
+ for iTech in xrange(gc.getNumTechInfos()):
+ if gc.getTechInfo(iTech).getAdvisorType() == gc.getInfoTypeForString(
+ "ADVISOR_RELIGION"
+ ) and not pTeam.isHasTech(iTech):
+ research_cost = pTeam.getResearchCost(iTech)
+ pTeam.changeResearchProgress(
+ iTech,
+ min(research_cost - pTeam.getResearchProgress(iTech), research_cost / 2),
+ iPlayer,
+ )
+
+
+@handler("cityAcquired")
+def al_azhar_university_effect_on_city_acquired(
+ iPreviousOwner, iNewOwner, pCity, bConquest, bTrade
+):
+ pPreviousOwner = gc.getPlayer(iPreviousOwner)
+ pNewOwner = gc.getPlayer(iNewOwner)
+ if pCity.getNumActiveBuilding(Wonder.ALAZHAR):
+ iPreviousTeam = pPreviousOwner.getTeam()
+ pPreviousTeam = gc.getTeam(iPreviousTeam)
+ iNewTeam = pNewOwner.getTeam()
+ pNewTeam = gc.getTeam(iNewTeam)
+ for iTech in xrange(gc.getNumTechInfos()):
+ if gc.getTechInfo(iTech).getAdvisorType() == gc.getInfoTypeForString(
+ "ADVISOR_RELIGION"
+ ):
+ if not pPreviousTeam.isHasTech(iTech):
+ research_cost = pPreviousTeam.getResearchCost(iTech)
+ pPreviousTeam.changeResearchProgress(
+ iTech,
+ max(-pPreviousTeam.getResearchProgress(iTech), -research_cost / 5),
+ iPreviousOwner,
+ )
+ if not pNewTeam.isHasTech(iTech):
+ research_cost = pNewTeam.getResearchCost(iTech)
+ pNewTeam.changeResearchProgress(
+ iTech,
+ min(
+ research_cost - pNewTeam.getResearchProgress(iTech),
+ research_cost / 5,
+ ),
+ iNewOwner,
+ )
+
+
+@handler("cityRazed")
+def remove_al_azhar_university_effect_on_city_razed(city, iPlayer):
+ if city.getNumActiveBuilding(Wonder.ALAZHAR):
+ pPlayer = gc.getPlayer(iPlayer)
+ iTeam = pPlayer.getTeam()
+ pTeam = gc.getTeam(iTeam)
+ for iTech in xrange(gc.getNumTechInfos()):
+ if not pTeam.isHasTech(iTech):
+ if gc.getTechInfo(iTech).getAdvisorType() == gc.getInfoTypeForString(
+ "ADVISOR_RELIGION"
+ ):
+ pTeam.changeResearchProgress(
+ iTech,
+ max(
+ -pPreviousTeam.getResearchProgress(iTech), # type: ignore
+ -pTeam.getResearchCost(iTech) / 5,
+ ),
+ iPlayer,
+ )
+
+
+@handler("buildingBuilt")
+def sistine_chapel_effect(city, building_type):
+ iPlayer = city.getOwner()
+ pPlayer = gc.getPlayer(iPlayer)
+ if building_type == Wonder.SISTINE_CHAPEL:
+ for city in cities.owner(iPlayer).entities():
+ if city.getNumWorldWonders() > 0:
+ city.changeFreeSpecialistCount(gc.getInfoTypeForString("SPECIALIST_ARTIST"), 1)
+ elif isWorldWonderClass(gc.getBuildingInfo(building_type).getBuildingClassType()):
+ # if the given civ already had the Sistine Chapel, and built another wonder in a new city
+ if pPlayer.countNumBuildings(Wonder.SISTINE_CHAPEL) > 0:
+ if city.getNumWorldWonders() == 1:
+ city.changeFreeSpecialistCount(gc.getInfoTypeForString("SPECIALIST_ARTIST"), 1)
+
+
+@handler("cityAcquired")
+def sistine_chapel_effect_on_city_acquired(iPreviousOwner, iNewOwner, pCity, bConquest, bTrade):
+ pPreviousOwner = gc.getPlayer(iPreviousOwner)
+ pNewOwner = gc.getPlayer(iNewOwner)
+ if pCity.getNumActiveBuilding(Wonder.SISTINE_CHAPEL):
+ for loopCity in cities.owner(iPreviousOwner).entities():
+ if loopCity.getNumWorldWonders() > 0:
+ loopCity.changeFreeSpecialistCount(
+ gc.getInfoTypeForString("SPECIALIST_ARTIST"), -1
+ )
+ for loopCity in cities.owner(iNewOwner).entities():
+ if loopCity.getNumWorldWonders() > 0 and not loopCity.getNumActiveBuilding(
+ Wonder.SISTINE_CHAPEL
+ ):
+ loopCity.changeFreeSpecialistCount(gc.getInfoTypeForString("SPECIALIST_ARTIST"), 1)
+ elif pCity.getNumWorldWonders() > 0:
+ if pPreviousOwner.countNumBuildings(Wonder.SISTINE_CHAPEL) > 0:
+ pCity.changeFreeSpecialistCount(gc.getInfoTypeForString("SPECIALIST_ARTIST"), -1)
+ elif pNewOwner.countNumBuildings(Wonder.SISTINE_CHAPEL) > 0:
+ pCity.changeFreeSpecialistCount(gc.getInfoTypeForString("SPECIALIST_ARTIST"), 1)
+
+
+@handler("cityRazed")
+def remove_sistine_chapel_effect_on_city_razed(city, iPlayer):
+ if city.getNumActiveBuilding(Wonder.SISTINE_CHAPEL):
+ for loopCity in cities.owner(iPlayer).entities():
+ if loopCity.getNumWorldWonders() > 0:
+ loopCity.changeFreeSpecialistCount(
+ gc.getInfoTypeForString("SPECIALIST_ARTIST"), -1
+ )
+
+
+@handler("buildingBuilt")
+def jasna_gora_effect_on_building_built(city, building_type):
+ iPlayer = city.getOwner()
+ if building_type == Wonder.JASNA_GORA:
+ for city in cities.owner(iPlayer).entities():
+ jasna_gora_effect(city)
+
+
+@handler("cityBuilt")
+def jasna_gora_effect_on_city_built(city):
+ iPlayer = city.getOwner()
+ pPlayer = gc.getPlayer(iPlayer)
+ if pPlayer.countNumBuildings(Wonder.JASNA_GORA) > 0:
+ jasna_gora_effect(city)
+
+
+@handler("cityAcquired")
+def jasna_gora_effect_on_city_acquired(iPreviousOwner, iNewOwner, pCity, bConquest, bTrade):
+ pPreviousOwner = gc.getPlayer(iPreviousOwner)
+ pNewOwner = gc.getPlayer(iNewOwner)
+
+ if pCity.getNumActiveBuilding(Wonder.JASNA_GORA):
+ for city in cities.owner(iPreviousOwner).entities():
+ remove_jasna_gora_effect(city)
+ for city in cities.owner(iNewOwner).entities():
+ jasna_gora_effect(city)
+ elif pPreviousOwner.countNumBuildings(Wonder.JASNA_GORA) > 0:
+ remove_jasna_gora_effect(pCity)
+ elif pNewOwner.countNumBuildings(Wonder.JASNA_GORA) > 0:
+ jasna_gora_effect(pCity)
+
+
+@handler("cityRazed")
+def remove_jasna_gora_effect_on_city_razed(city, iPlayer):
+ if city.getNumActiveBuilding(Wonder.JASNA_GORA):
+ for city in cities.owner(iPlayer).entities():
+ remove_jasna_gora_effect(city)
+
+
+def jasna_gora_effect(city):
+ _jasna_gora_effect(city, True)
+
+
+def remove_jasna_gora_effect(city):
+ _jasna_gora_effect(city, False)
+
+
+def _jasna_gora_effect(city, apply):
+ if apply:
+ value = 1
+ else:
+ value = 0
+ for building_class in [
+ "BUILDINGCLASS_CATHOLIC_TEMPLE",
+ "BUILDINGCLASS_ORTHODOX_TEMPLE",
+ "BUILDINGCLASS_PROTESTANT_TEMPLE",
+ "BUILDINGCLASS_ISLAMIC_TEMPLE",
+ ]:
+ city.setBuildingCommerceChange(
+ gc.getInfoTypeForString(building_class),
+ CommerceTypes.COMMERCE_CULTURE,
+ value,
+ )
+
+
+@handler("buildingBuilt")
+def kizil_kule_effect_on_building_built(city, building_type):
+ iPlayer = city.getOwner()
+ if building_type == Wonder.KIZIL_KULE:
+ for city in cities.owner(iPlayer).entities():
+ kizil_kule_effect(city)
+
+
+@handler("cityBuilt")
+def kizil_kule_effect_on_city_built(city):
+ iPlayer = city.getOwner()
+ pPlayer = gc.getPlayer(iPlayer)
+ if pPlayer.countNumBuildings(Wonder.KIZIL_KULE) > 0:
+ kizil_kule_effect(city)
+
+
+@handler("cityAcquired")
+def kizil_kule_effect_on_city_acquired(iPreviousOwner, iNewOwner, pCity, bConquest, bTrade):
+ pPreviousOwner = gc.getPlayer(iPreviousOwner)
+ pNewOwner = gc.getPlayer(iNewOwner)
+ if pCity.getNumActiveBuilding(Wonder.KIZIL_KULE):
+ for _city in cities.owner(iPreviousOwner).entities():
+ remove_kizil_kule_effect(_city)
+ for _city in cities.owner(iNewOwner).entities():
+ kizil_kule_effect(_city)
+ elif pPreviousOwner.countNumBuildings(Wonder.KIZIL_KULE) > 0:
+ remove_kizil_kule_effect(pCity)
+ elif pNewOwner.countNumBuildings(Wonder.KIZIL_KULE) > 0:
+ kizil_kule_effect(pCity)
+
+
+@handler("cityRazed")
+def remove_kizil_kule_effect_on_city_razed(city, iPlayer):
+ if city.getNumActiveBuilding(Wonder.KIZIL_KULE):
+ for _city in cities.owner(iPlayer).entities():
+ remove_kizil_kule_effect(_city)
+
+
+def kizil_kule_effect(city):
+ _kizil_kule_effect(city, 2)
+
+
+def remove_kizil_kule_effect(city):
+ _kizil_kule_effect(city, 0)
+
+
+def _kizil_kule_effect(city, value):
+ city.setBuildingYieldChange(
+ gc.getInfoTypeForString("BUILDINGCLASS_HARBOR"), YieldTypes.YIELD_COMMERCE, value
+ )
+
+
+@handler("buildingBuilt")
+def samogitian_alkas_effect_on_building_built(city, building_type):
+ iPlayer = city.getOwner()
+ if building_type == Wonder.SAMOGITIAN_ALKAS:
+ for city in cities.owner(iPlayer).entities():
+ samogitian_alkas_effect(city)
+
+
+@handler("cityBuilt")
+def samogitian_alkas_effect_on_city_built(city):
+ iPlayer = city.getOwner()
+ pPlayer = gc.getPlayer(iPlayer)
+ if pPlayer.countNumBuildings(Wonder.SAMOGITIAN_ALKAS) > 0:
+ samogitian_alkas_effect(city)
+
+
+@handler("cityAcquired")
+def samogitian_alkas_effect_on_city_acquired(iPreviousOwner, iNewOwner, pCity, bConquest, bTrade):
+ pPreviousOwner = gc.getPlayer(iPreviousOwner)
+ pNewOwner = gc.getPlayer(iNewOwner)
+ if pCity.getNumActiveBuilding(Wonder.SAMOGITIAN_ALKAS):
+ for _city in cities.owner(iPreviousOwner).entities():
+ remove_samogitian_alkas_effect(_city)
+ for _city in cities.owner(iNewOwner).entities():
+ samogitian_alkas_effect(_city)
+ elif pPreviousOwner.countNumBuildings(Wonder.SAMOGITIAN_ALKAS) > 0:
+ remove_samogitian_alkas_effect(pCity)
+ elif pNewOwner.countNumBuildings(Wonder.SAMOGITIAN_ALKAS) > 0:
+ samogitian_alkas_effect(pCity)
+
+
+@handler("cityRazed")
+def remove_samogitian_alkas_effect_on_city_razed(city, iPlayer):
+ if city.getNumActiveBuilding(Wonder.SAMOGITIAN_ALKAS):
+ for _city in cities.owner(iPlayer).entities():
+ remove_samogitian_alkas_effect(_city)
+
+
+def samogitian_alkas_effect(city):
+ _samogitian_alkas_effect(city, 2)
+
+
+def remove_samogitian_alkas_effect(city):
+ _samogitian_alkas_effect(city, 0)
+
+
+def _samogitian_alkas_effect(city, value):
+ city.setBuildingCommerceChange(
+ gc.getInfoTypeForString("BUILDINGCLASS_PAGAN_SHRINE"),
+ CommerceTypes.COMMERCE_RESEARCH,
+ value,
+ )
+
+
+@handler("buildingBuilt")
+def magna_carta_effect_on_building_built(city, building_type):
+ iPlayer = city.getOwner()
+ if building_type == Wonder.MAGNA_CARTA:
+ for city in cities.owner(iPlayer).entities():
+ magna_carta_effect(city)
+
+
+@handler("cityBuilt")
+def magna_carta_effect_on_city_built(city):
+ iPlayer = city.getOwner()
+ pPlayer = gc.getPlayer(iPlayer)
+ if pPlayer.countNumBuildings(Wonder.MAGNA_CARTA) > 0:
+ magna_carta_effect(city)
+
+
+@handler("cityAcquired")
+def magna_carta_effect_on_city_acquired(iPreviousOwner, iNewOwner, pCity, bConquest, bTrade):
+ pPreviousOwner = gc.getPlayer(iPreviousOwner)
+ pNewOwner = gc.getPlayer(iNewOwner)
+ if pCity.getNumActiveBuilding(Wonder.MAGNA_CARTA):
+ for _city in cities.owner(iPreviousOwner).entities():
+ remove_magna_carta_effect(_city)
+ for _city in cities.owner(iNewOwner).entities():
+ magna_carta_effect(_city)
+ elif pPreviousOwner.countNumBuildings(Wonder.MAGNA_CARTA) > 0:
+ remove_magna_carta_effect(pCity)
+ elif pNewOwner.countNumBuildings(Wonder.MAGNA_CARTA) > 0:
+ magna_carta_effect(pCity)
+
+
+@handler("cityRazed")
+def remove_magna_carta_effect_on_city_razed(city, iPlayer):
+ if city.getNumActiveBuilding(Wonder.MAGNA_CARTA):
+ for _city in cities.owner(iPlayer).entities():
+ remove_magna_carta_effect(_city)
+
+
+def magna_carta_effect(city):
+ _magna_carta_effect(city, 2)
+
+
+def remove_magna_carta_effect(city):
+ _magna_carta_effect(city, 0)
+
+
+def _magna_carta_effect(city, value):
+ city.setBuildingCommerceChange(
+ gc.getInfoTypeForString("BUILDINGCLASS_COURTHOUSE"),
+ CommerceTypes.COMMERCE_CULTURE,
+ value,
+ )
+
+
+@handler("projectBuilt")
+def onProjectBuilt(pCity, iProjectType):
+ iPlayer = pCity.getOwner()
+ pPlayer = gc.getPlayer(iPlayer)
+ if iProjectType >= len(Project):
+ if pPlayer.countNumBuildings(Wonder.TORRE_DEL_ORO) > 0:
+ # 70% chance for a 3 turn Golden Age
+ if percentage_chance(70, strict=True):
+ pPlayer.changeGoldenAgeTurns(3)
+ message_if_human(
+ iPlayer,
+ text("TXT_KEY_PROJECT_COLONY_GOLDEN_AGE"),
+ color=MessageData.GREEN,
+ )
+
+
+@handler("unitBuilt")
+def topkapi_palace_effect(city, unit):
+ iPlayer = unit.getOwner()
+ pPlayer = gc.getPlayer(iPlayer)
+ iUnitType = unit.getUnitType()
+ iTeam = pPlayer.getTeam()
+ pTeam = gc.getTeam(iTeam)
+
+ if pTeam.isTrainVassalUU():
+ l_vassalUU = []
+ iDefaultUnit = getBaseUnit(iUnitType)
+ for iLoopPlayer in civilizations().majors().ids():
+ pLoopPlayer = gc.getPlayer(iLoopPlayer)
+ if pLoopPlayer.isAlive():
+ if gc.getTeam(pLoopPlayer.getTeam()).isVassal(iTeam):
+ iUniqueUnit = getUniqueUnit(iLoopPlayer, iUnitType)
+ if iUniqueUnit != iDefaultUnit:
+ l_vassalUU.append(iUniqueUnit)
+ if l_vassalUU: # Only convert if vassal UU is possible
+ iPlayerUU = getUniqueUnit(iPlayer, iUnitType)
+ if iPlayerUU != iDefaultUnit:
+ # double chance for the original UU
+ l_vassalUU.append(iPlayerUU)
+ l_vassalUU.append(iPlayerUU)
+ iUnit = choice(l_vassalUU)
+ pNewUnit = pPlayer.initUnit(
+ iUnit,
+ unit.getX(),
+ unit.getY(),
+ UnitAITypes.NO_UNITAI,
+ DirectionTypes.NO_DIRECTION,
+ )
+ pNewUnit.convert(unit)
+ # message if it was changed to a vassal UU
+ if iUnit != iPlayerUU and iUnit != iDefaultUnit:
+ if human() == iPlayer:
+ szText = text(
+ "TXT_KEY_BUILDING_TOPKAPI_PALACE_EFFECT",
+ gc.getUnitInfo(iUnit).getDescription(),
+ gc.getUnitInfo(iPlayerUU).getDescription(),
+ )
+ message(
+ human(),
+ szText,
+ event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
+ button=gc.getUnitInfo(iUnit).getButton(),
+ color=MessageData.LIGHT_BLUE,
+ location=city,
+ )
+
+
+@handler("unitBuilt")
+def brandenburg_gate_effect(city, unit):
+ iPlayer = unit.getOwner()
+ pPlayer = gc.getPlayer(iPlayer)
+ if unit.getUnitCombatType() != -1:
+ if pPlayer.countNumBuildings(Wonder.BRANDENBURG_GATE) > 0:
+ unit.changeExperience(
+ (
+ 2
+ * city.getAddedFreeSpecialistCount(
+ gc.getInfoTypeForString("SPECIALIST_GREAT_GENERAL")
+ )
+ ),
+ 999,
+ False,
+ False,
+ False,
+ )
+
+
+@handler("unitBuilt")
+def selimiye_mosque_effect(city, unit):
+ iPlayer = unit.getOwner()
+ pPlayer = gc.getPlayer(iPlayer)
+ if pPlayer.countNumBuildings(Wonder.SELIMIYE_MOSQUE) > 0:
+ if pPlayer.isGoldenAge():
+ unit.changeExperience(unit.getExperience(), 999, False, False, False)
+
+
+@handler("greatPersonBorn")
+def louvre_effect(pUnit, iPlayer, pCity):
+ pPlayer = gc.getPlayer(iPlayer)
+ if pPlayer.countNumBuildings(Wonder.LOUVRE) > 0:
+ for loopCity in cities.owner(iPlayer).entities():
+ # bigger boost for the GP city and the Louvre city
+ if loopCity.getNumActiveBuilding(Wonder.LOUVRE) or pCity == loopCity:
+ loopCity.changeCulture(iPlayer, min(300, loopCity.getCultureThreshold() / 5), True)
+ else:
+ loopCity.changeCulture(
+ iPlayer, min(100, loopCity.getCultureThreshold() / 10), True
+ )
+
+
+@handler("greatPersonBorn")
+def peterhof_palace_effect(pUnit, iPlayer, pCity):
+ pPlayer = gc.getPlayer(iPlayer)
+ if pPlayer.countNumBuildings(Wonder.PETERHOF_PALACE) > 0:
+ if percentage_chance(70, strict=True):
+ if pUnit.getUnitType() == Unit.GREAT_SCIENTIST:
+ pCity.changeFreeSpecialistCount(gc.getInfoTypeForString("SPECIALIST_SCIENTIST"), 1)
+ elif pUnit.getUnitType() == Unit.GREAT_PROPHET:
+ pCity.changeFreeSpecialistCount(gc.getInfoTypeForString("SPECIALIST_PRIEST"), 1)
+ elif pUnit.getUnitType() == Unit.GREAT_ARTIST:
+ pCity.changeFreeSpecialistCount(gc.getInfoTypeForString("SPECIALIST_ARTIST"), 1)
+ elif pUnit.getUnitType() == Unit.GREAT_MERCHANT:
+ pCity.changeFreeSpecialistCount(gc.getInfoTypeForString("SPECIALIST_MERCHANT"), 1)
+ elif pUnit.getUnitType() == Unit.GREAT_ENGINEER:
+ pCity.changeFreeSpecialistCount(gc.getInfoTypeForString("SPECIALIST_ENGINEER"), 1)
+ elif pUnit.getUnitType() == Unit.GREAT_SPY:
+ pCity.changeFreeSpecialistCount(gc.getInfoTypeForString("SPECIALIST_SPY"), 1)
+
+
+@handler("vassalState")
+def onVassalState(iMaster, iVassal, bVassal):
+ if bVassal:
+ MasterTeam = gc.getTeam(iMaster)
+ for iPlayer in civilizations().majors().ids():
+ pPlayer = gc.getPlayer(iPlayer)
+ if (
+ pPlayer.getTeam() == iMaster
+ and pPlayer.countNumBuildings(Wonder.IMPERIAL_DIET) > 0
+ ):
+ pPlayer.changeGoldenAgeTurns(3)
+ message_if_human(
+ iPlayer,
+ text("TXT_KEY_BUILDING_IMPERIAL_DIET_EFFECT"),
+ color=MessageData.LIGHT_BLUE,
+ )
diff --git a/Assets/Python/components/AIWars.py b/Assets/Python/components/AIWars.py
deleted file mode 100644
index 7b0844909..000000000
--- a/Assets/Python/components/AIWars.py
+++ /dev/null
@@ -1,288 +0,0 @@
-# Rhye's and Fall of Civilization: Europe - AI Wars
-
-from CvPythonExtensions import *
-from Consts import INDEPENDENT_CIVS
-from Core import (
- civilization,
- civilizations,
- get_data_from_upside_down_map,
- get_scenario_start_turn,
- is_independent_civ,
- is_major_civ,
- turn,
- year,
- plots,
-)
-from CoreTypes import Civ
-from PyUtils import rand
-from RFCUtils import (
- getMaster,
- getPlagueCountdown,
- isAVassal,
- minorCoreWars,
- minorWars,
- restorePeaceAI,
- restorePeaceHuman,
-)
-from StoredData import data
-from WarMapData import WARS_MAP
-
-gc = CyGlobalContext()
-
-iMinIntervalEarly = 15
-iMaxIntervalEarly = 30
-iMinIntervalLate = 40
-iMaxIntervalLate = 60
-iThreshold = 100
-iMinValue = 30
-
-
-class AIWars:
- def getAttackingCivsArray(self, iCiv):
- return data.lAttackingCivsArray[iCiv]
-
- def setAttackingCivsArray(self, iCiv, iNewValue):
- data.lAttackingCivsArray[iCiv] = iNewValue
-
- def setup(self):
- iTurn = get_scenario_start_turn() # only check from the start turn of the scenario
- data.iNextTurnAIWar = iTurn + rand(iMaxIntervalEarly - iMinIntervalEarly)
-
- def checkTurn(self, iGameTurn):
- if iGameTurn > 20:
- # Absinthe: automatically turn peace on between independent cities and all the major civs
- turn_peace_human_mapper = {
- Civ.INDEPENDENT: 9,
- Civ.INDEPENDENT_2: 4,
- Civ.INDEPENDENT_3: 14,
- Civ.INDEPENDENT_4: 19,
- }
- for civ, value in turn_peace_human_mapper.items():
- if iGameTurn % 20 == value:
- restorePeaceHuman(civ)
-
- turn_peace_ai_mapper = {
- Civ.INDEPENDENT: 0,
- Civ.INDEPENDENT_2: 9,
- Civ.INDEPENDENT_3: 18,
- Civ.INDEPENDENT_4: 27,
- }
- for civ, value in turn_peace_ai_mapper.items():
- if iGameTurn % 36 == value:
- restorePeaceAI(civ, False)
-
- # Absinthe: automatically turn war on between independent cities and some AI major civs
- # runned on the 2nd turn after restorePeaceAI()
- turn_minor_wars_mapper = {
- Civ.INDEPENDENT: 2,
- Civ.INDEPENDENT_2: 11,
- Civ.INDEPENDENT_3: 20,
- Civ.INDEPENDENT_4: 29,
- }
- for civ, value in turn_minor_wars_mapper.items():
- if iGameTurn % 36 == value:
- minorWars(civ, iGameTurn)
-
- # Absinthe: declare war sooner / more frequently if there is an Indy city inside the core area
- # so the AI will declare war much sooner after an indy city appeared in it's core
- turn_minor_core_wars_mapper = {
- Civ.INDEPENDENT: 10,
- Civ.INDEPENDENT_2: 7,
- Civ.INDEPENDENT_3: 4,
- Civ.INDEPENDENT_4: 1,
- }
- for civ, value in turn_minor_core_wars_mapper.items():
- if iGameTurn % 12 == value:
- minorCoreWars(civ, iGameTurn)
-
- # Absinthe: Venice always seeks war with an Independent Ragusa - should help AI Venice significantly
- if iGameTurn % 9 == 2:
- pVenice = gc.getPlayer(Civ.VENECIA)
- if pVenice.isAlive() and not pVenice.isHuman():
- pRagusaPlot = gc.getMap().plot(64, 28)
- if pRagusaPlot.isCity():
- pRagusaCity = pRagusaPlot.getPlotCity()
- iOwner = pRagusaCity.getOwner()
- if is_independent_civ(iOwner):
- # Absinthe: probably better to use declareWar instead of setAtWar
- teamVenice = gc.getTeam(pVenice.getTeam())
- teamVenice.declareWar(iOwner, False, WarPlanTypes.WARPLAN_LIMITED)
-
- # Absinthe: Kingdom of Hungary should try to dominate Sisak/Zagreb if it's independent
- if iGameTurn > year(1000) and iGameTurn % 7 == 3:
- pHungary = gc.getPlayer(Civ.HUNGARY)
- if pHungary.isAlive() and not pHungary.isHuman():
- pZagrebPlot = gc.getMap().plot(62, 34)
- if pZagrebPlot.isCity():
- pZagrebCity = pZagrebPlot.getPlotCity()
- iOwner = pZagrebCity.getOwner()
- if is_independent_civ(iOwner):
- # Absinthe: probably better to use declareWar instead of setAtWar
- teamHungary = gc.getTeam(pHungary.getTeam())
- teamHungary.declareWar(iOwner, False, WarPlanTypes.WARPLAN_LIMITED)
-
- if iGameTurn == data.iNextTurnAIWar:
- iMinInterval = iMinIntervalEarly
- iMaxInterval = iMaxIntervalEarly
-
- # skip if already in a world war
- iCiv, iTargetCiv = self.pickCivs()
- if 0 <= iTargetCiv <= civilizations().drop(Civ.BARBARIAN).len():
- if iTargetCiv != Civ.POPE and iCiv != Civ.POPE and iCiv != iTargetCiv:
- self.initWar(iCiv, iTargetCiv, iGameTurn, iMaxInterval, iMinInterval)
- return
- data.iNextTurnAIWar = iGameTurn + iMinInterval + rand(iMaxInterval - iMinInterval)
-
- def pickCivs(self):
- iCiv = self.chooseAttackingPlayer()
- if iCiv != -1:
- if is_major_civ(iCiv):
- iTargetCiv = self.checkGrid(iCiv)
- return (iCiv, iTargetCiv)
- else:
- return (-1, -1)
-
- def initWar(self, iCiv, iTargetCiv, iGameTurn, iMaxInterval, iMinInterval):
- # Absinthe: don't declare if couldn't do it otherwise
- teamAgressor = gc.getTeam(gc.getPlayer(iCiv).getTeam())
- if teamAgressor.canDeclareWar(iTargetCiv):
- gc.getTeam(gc.getPlayer(iCiv).getTeam()).declareWar(iTargetCiv, True, -1)
- data.iNextTurnAIWar = iGameTurn + iMinInterval + rand(iMaxInterval - iMinInterval)
- # Absinthe: if not, next try will come the 1/2 of this time later
- else:
- data.iNextTurnAIWar = iGameTurn + (
- iMinInterval + rand(iMaxInterval - iMinInterval) / 2
- )
-
- def chooseAttackingPlayer(self):
- # finding max teams ever alive (countCivTeamsEverAlive() doesn't work as late human starting civ gets killed every turn)
- iMaxCivs = civilizations().majors().len()
- for i in civilizations().majors().ids():
- j = civilizations().main().len() - i
- if gc.getPlayer(j).isAlive():
- iMaxCivs = j
- break
-
- if gc.getGame().countCivPlayersAlive() <= 2:
- return -1
- else:
- iRndnum = rand(iMaxCivs)
- iAlreadyAttacked = -100
- iMin = 100
- iCiv = -1
- for i in range(iRndnum, iRndnum + iMaxCivs):
- iLoopCiv = i % iMaxCivs
- if gc.getPlayer(iLoopCiv).isAlive() and not gc.getPlayer(iLoopCiv).isHuman():
- if (
- getPlagueCountdown(iLoopCiv) >= -10 and getPlagueCountdown(iLoopCiv) <= 0
- ): # civ is not under plague or quit recently from it
- iAlreadyAttacked = self.getAttackingCivsArray(iLoopCiv)
- if isAVassal(iLoopCiv):
- iAlreadyAttacked += 1 # less likely to attack
- # check if a world war is already in place:
- iNumAlreadyWar = 0
- tLoopCiv = gc.getTeam(gc.getPlayer(iLoopCiv).getTeam())
- for kLoopCiv in civilizations().majors().ids():
- if tLoopCiv.isAtWar(kLoopCiv):
- iNumAlreadyWar += 1
- if iNumAlreadyWar >= 4:
- iAlreadyAttacked += 2 # much less likely to attack
- elif iNumAlreadyWar >= 2:
- iAlreadyAttacked += 1 # less likely to attack
-
- if iAlreadyAttacked < iMin:
- iMin = iAlreadyAttacked
- iCiv = iLoopCiv
- if iAlreadyAttacked != -100:
- self.setAttackingCivsArray(iCiv, iAlreadyAttacked + 1)
- return iCiv
- else:
- return -1
-
- def checkGrid(self, iCiv):
- pCiv = gc.getPlayer(iCiv)
- pTeam = gc.getTeam(pCiv.getTeam())
- lTargetCivs = [0] * civilizations().drop(Civ.BARBARIAN).len()
-
- # set alive civs to 1 to differentiate them from dead civs
- for iLoopPlayer in civilizations().drop(Civ.BARBARIAN).ids():
- if iLoopPlayer == iCiv:
- continue
- if pTeam.isAtWar(iLoopPlayer): # if already at war with iCiv then it remains 0
- continue
- pLoopPlayer = gc.getPlayer(iLoopPlayer)
- iLoopTeam = pLoopPlayer.getTeam()
- pLoopTeam = gc.getTeam(iLoopTeam)
- if (
- iLoopPlayer < civilizations().majors().len()
- ): # if master or vassal of iCiv then it remains 0
- if pLoopTeam.isVassal(iCiv) or pTeam.isVassal(iLoopPlayer):
- continue
- if pLoopPlayer.isAlive() and pTeam.isHasMet(iLoopTeam):
- lTargetCivs[iLoopPlayer] = 1
-
- for plot in plots().all().not_owner(iCiv).not_owner(Civ.BARBARIAN).entities():
- if lTargetCivs[plot.getOwner()] > 0:
- iValue = get_data_from_upside_down_map(WARS_MAP, iCiv, plot)
- if plot.getOwner() in INDEPENDENT_CIVS:
- iValue /= 3
- lTargetCivs[plot.getOwner()] += iValue
-
- # normalization
- iMaxTempValue = max(lTargetCivs)
- if iMaxTempValue > 0:
- for civ in civilizations().drop(Civ.BARBARIAN).ids():
- if lTargetCivs[civ] > 0:
- lTargetCivs[civ] = lTargetCivs[civ] * 500 / iMaxTempValue
-
- for iLoopCiv in civilizations().drop(Civ.BARBARIAN).ids():
- if iLoopCiv == iCiv:
- continue
-
- if lTargetCivs[iLoopCiv] <= 0:
- continue
-
- # add a random value
- if lTargetCivs[iLoopCiv] <= iThreshold:
- lTargetCivs[iLoopCiv] += rand(100)
- else:
- lTargetCivs[iLoopCiv] += rand(300)
- # balanced with attitude
- attitude = 2 * (pCiv.AI_getAttitude(iLoopCiv) - 2)
- if attitude > 0:
- lTargetCivs[iLoopCiv] /= attitude
- # exploit plague
- if (
- getPlagueCountdown(iLoopCiv) > 0
- or getPlagueCountdown(iLoopCiv) < -10
- and not turn() <= civilization(iLoopCiv).date.birth + 20
- ):
- lTargetCivs[iLoopCiv] *= 3
- lTargetCivs[iLoopCiv] /= 2
-
- # balanced with master's attitude
- iMaster = getMaster(iCiv)
- if iMaster != -1:
- attitude = 2 * (gc.getPlayer(iMaster).AI_getAttitude(iLoopCiv) - 2)
- if attitude > 0:
- lTargetCivs[iLoopCiv] /= attitude
-
- # if already at war
- if not pTeam.isAtWar(iLoopCiv):
- # consider peace counter
- iCounter = min(7, max(1, pTeam.AI_getAtPeaceCounter(iLoopCiv)))
- if iCounter <= 7:
- lTargetCivs[iLoopCiv] *= 20 + 10 * iCounter
- lTargetCivs[iLoopCiv] /= 100
-
- # if under pact
- if pTeam.isDefensivePact(iLoopCiv):
- lTargetCivs[iLoopCiv] /= 4
-
- # find max
- iMaxValue = max(lTargetCivs)
- iTargetCiv = lTargetCivs.index(iMaxValue)
-
- if iMaxValue >= iMinValue:
- return iTargetCiv
- return -1
diff --git a/Assets/Python/components/Barbs.py b/Assets/Python/components/Barbs.py
deleted file mode 100644
index 3e543f401..000000000
--- a/Assets/Python/components/Barbs.py
+++ /dev/null
@@ -1,3643 +0,0 @@
-# Rhye's and Fall of Civilization: Europe - Barbarian units and cities
-
-from CvPythonExtensions import *
-from Consts import INDEPENDENT_CIVS, MessageData
-from Core import (
- civilizations,
- message,
- event_popup,
- human,
- location,
- make_unit,
- make_units,
- text,
- turn,
- cities,
- plots,
-)
-from CoreTypes import Civ, Civic, Religion, Technology, Unit, Province
-from PyUtils import percentage, percentage_chance, rand, random_entry, choice
-from RFCUtils import (
- cultureManager,
- flipCity,
- flipUnitsInCityAfter,
- flipUnitsInCitySecession,
- forcedInvasion,
- outerInvasion,
- outerSeaSpawn,
- squareSearch,
-)
-from TimelineData import DateTurn
-from StoredData import data
-
-
-gc = CyGlobalContext()
-
-
-# Independent and barbarians city spawns
-# Key: tCity = variations (coordinates, actual city name, chance), owner, population size, defender type, number of defenders, religion, workers
-# Notes: Indy cities start with zero-sized culture, barbs with normal culture
-# Added some initial food reserves on founding cities, so even independents won't shrink on their first turn anymore
-# Barbarian cities start with 2 additional defender units
-# Walls (and other buildings) can be added with the onCityBuilt function, in RiseAndFall.py
-# 500 AD
-tTangier = (
- [((27, 16), "Tangier", 100)],
- Civ.INDEPENDENT_2,
- 1,
- Unit.CORDOBAN_BERBER,
- 2,
- -1,
- 0,
-)
-tBordeaux = ([((37, 38), "Burdigala", 100)], Civ.BARBARIAN, 2, Unit.ARCHER, 0, -1, 0)
-tAlger = (
- [((40, 16), "Alger", 60), ((34, 13), "Tlemcen", 40)],
- Civ.INDEPENDENT_3,
- 1,
- Unit.ARCHER,
- 1,
- Religion.CATHOLICISM,
- 0,
-)
-tBarcelona = (
- [((40, 28), "Barcino", 100)],
- Civ.INDEPENDENT_2,
- 1,
- Unit.ARCHER,
- 1,
- -1,
- 0,
-)
-tToulouse = (
- [((41, 34), "Tolosa", 30), ((40, 34), "Tolosa", 30), ((42, 32), "Narbo", 40)],
- Civ.BARBARIAN,
- 1,
- Unit.ARCHER,
- 0,
- -1,
- 0,
-)
-tMarseilles = (
- [((46, 32), "Massilia", 50), ((46, 33), "Aquae Sextiae", 50)],
- Civ.INDEPENDENT,
- 1,
- Unit.ARCHER,
- 1,
- Religion.CATHOLICISM,
- 0,
-)
-tNantes = (
- [((36, 43), "Naoned", 50), ((35, 43), "Gwened", 30), ((37, 44), "Roazhon", 20)],
- Civ.INDEPENDENT_2,
- 1,
- Unit.ARCHER,
- 1,
- -1,
- 0,
-)
-tCaen = (
- [((40, 47), "Caen", 100)],
- Civ.INDEPENDENT_4,
- 2,
- Unit.ARCHER,
- 1,
- Religion.CATHOLICISM,
- 1,
-)
-tLyon = (
- [((46, 37), "Lyon", 100)],
- Civ.INDEPENDENT_3,
- 2,
- Unit.ARCHER,
- 2,
- Religion.CATHOLICISM,
- 1,
-)
-tTunis = ([((49, 17), "Tunis", 100)], Civ.INDEPENDENT_4, 2, Unit.ARCHER, 1, -1, 0)
-tYork = ([((39, 59), "Eboracum", 100)], Civ.INDEPENDENT_4, 1, Unit.ARCHER, 2, -1, 1)
-tLondon = (
- [((41, 52), "Londinium", 100)],
- Civ.INDEPENDENT,
- 2,
- Unit.ARCHER,
- 2,
- Religion.CATHOLICISM,
- 0,
-)
-tMilan = (
- [((52, 37), "Mediolanum", 100)],
- Civ.INDEPENDENT,
- 2,
- Unit.ARCHER,
- 2,
- Religion.CATHOLICISM,
- 0,
-)
-tFlorence = (
- [((54, 32), "Florentia", 40), ((53, 32), "Pisae", 40), ((57, 31), "Ankon", 20)],
- Civ.INDEPENDENT_2,
- 2,
- Unit.ARCHER,
- 2,
- Religion.CATHOLICISM,
- 0,
-)
-tTripoli = ([((54, 8), "Tripoli", 100)], Civ.BARBARIAN, 1, Unit.ARCHER, 1, -1, 0)
-tAugsburg = (
- [((55, 41), "Augsburg", 100)],
- Civ.INDEPENDENT_3,
- 1,
- Unit.ARCHER,
- 2,
- -1,
- 0,
-)
-tNapoli = (
- [((59, 24), "Neapolis", 40), ((60, 25), "Beneventum", 40), ((62, 24), "Tarentum", 20)],
- Civ.INDEPENDENT,
- 2,
- Unit.ARCHER,
- 1,
- -1,
- 0,
-)
-tRagusa = (
- [((64, 28), "Ragusa", 100)],
- Civ.INDEPENDENT_2,
- 1,
- Unit.ARCHER,
- 2,
- Religion.CATHOLICISM,
- 0,
-)
-tSeville = ([((27, 21), "Hispalis", 100)], Civ.INDEPENDENT_4, 1, Unit.ARCHER, 2, -1, 0)
-tPalermo = (
- [((55, 19), "Palermo", 60), ((58, 17), "Syracuse", 40)],
- Civ.INDEPENDENT_3,
- 2,
- Unit.ARCHER,
- 1,
- Religion.CATHOLICISM,
- 1,
-)
-# 552 AD
-tInverness = (
- [((37, 67), "Inbhir Nis", 50), ((37, 65), "Scaig", 50)],
- Civ.BARBARIAN,
- 1,
- Unit.ARCHER,
- 1,
- -1,
- 0,
-) # reduced to town on spawn of Scotland
-# 600 AD
-tRhodes = (
- [((80, 13), "Rhodes", 100)],
- Civ.INDEPENDENT_2,
- 1,
- Unit.ARCHER,
- 1,
- Religion.ORTHODOXY,
- 0,
-)
-# 640 AD
-tNorwich = (
- [((43, 55), "Norwich", 100)],
- Civ.INDEPENDENT_3,
- 1,
- Unit.ARCHER,
- 1,
- -1,
- 1,
-) # reduced to town on spawn of England
-# 670 AD
-tKairouan = (
- [((48, 14), "Kairouan", 100)],
- Civ.INDEPENDENT_2,
- 1,
- Unit.ARCHER,
- 1,
- Religion.ISLAM,
- 0,
-)
-# 680 AD
-tToledo = (
- [((30, 27), "Toledo", 100)],
- Civ.BARBARIAN,
- 1,
- Unit.ARCHER,
- 1,
- Religion.CATHOLICISM,
- 1,
-)
-tLeicester = (
- [((39, 56), "Ligeraceaster", 100)],
- Civ.INDEPENDENT,
- 1,
- Unit.ARCHER,
- 1,
- -1,
- 0,
-) # reduced to town on spawn of England
-# 700 AD
-tValencia = (
- [((36, 25), "Valencia", 100)],
- Civ.INDEPENDENT,
- 1,
- Unit.ARCHER,
- 1,
- Religion.CATHOLICISM,
- 1,
-)
-tPamplona = (
- [((35, 32), "Pamplona", 70), ((34, 33), "Pamplona", 30)],
- Civ.INDEPENDENT_4,
- 1,
- Unit.CROSSBOWMAN,
- 2,
- -1,
- 0,
-)
-tLubeck = (
- [((57, 54), "Liubice", 40), ((57, 53), "Liubice", 60)],
- Civ.INDEPENDENT_2,
- 1,
- Unit.ARCHER,
- 2,
- -1,
- 1,
-)
-tPorto = (
- [((23, 31), "Portucale", 100)],
- Civ.INDEPENDENT_3,
- 1,
- Unit.CROSSBOWMAN,
- 2,
- Religion.CATHOLICISM,
- 0,
-)
-tDublin = (
- [((32, 58), "Teamhair", 100)],
- Civ.BARBARIAN,
- 1,
- Unit.SPEARMAN,
- 1,
- Religion.CATHOLICISM,
- 1,
-) # Hill of Tara, later becomes Dublin
-tDownpatrick = (
- [((33, 61), "Rath Celtair", 20), ((29, 60), "Cruiachain", 30), ((29, 56), "Caisel", 50)],
- Civ.BARBARIAN,
- 1,
- Unit.ARCHER,
- 0,
- -1,
- 1,
-) # Cruiachain = Rathcroghan, later becomes Sligo; Caisel = Cashel, later becomes Cork
-# 760 AD
-tTonsberg = (
- [((57, 65), "Tonsberg", 100)],
- Civ.INDEPENDENT_3,
- 1,
- Unit.ARCHER,
- 2,
- -1,
- 0,
-)
-# 768 AD
-tRaska = ([((68, 28), "Ras", 100)], Civ.INDEPENDENT_2, 1, Unit.ARCHER, 2, -1, 1)
-# 780 AD
-tFez = ([((29, 12), "Fes", 100)], Civ.INDEPENDENT_4, 1, Unit.CROSSBOWMAN, 2, -1, 1)
-# 800 AD
-tMilanR = (
- [((52, 37), "Milano", 100)],
- Civ.INDEPENDENT,
- 4,
- Unit.ARCHER,
- 2,
- Religion.CATHOLICISM,
- 0,
-) # respawn, in case it was razed
-# tFlorenceR = ( [ ((54, 32), "Firenze", 100) ], Civ.INDEPENDENT_2, 4, Unit.ARCHER, 2, Religion.CATHOLICISM, 0 ) #respawn, doesn't work with the multiple options in 500AD
-tPrague = (
- [((60, 44), "Praha", 100)],
- Civ.INDEPENDENT,
- 1,
- Unit.CROSSBOWMAN,
- 2,
- Religion.CATHOLICISM,
- 1,
-)
-tKursk = ([((90, 48), "Kursk", 100)], Civ.INDEPENDENT_4, 1, Unit.ARCHER, 2, -1, 0)
-tCalais = (
- [((44, 50), "Calais", 50), ((45, 50), "Dunkerque", 50)],
- Civ.INDEPENDENT_3,
- 1,
- Unit.CROSSBOWMAN,
- 2,
- -1,
- 0,
-)
-tNidaros = (
- [((57, 71), "Nidaros", 100)],
- Civ.INDEPENDENT_3,
- 1,
- Unit.ARCHER,
- 1,
- -1,
- 1,
-) # Trondheim
-tUppsala = (
- [((65, 66), "Uppsala", 100)],
- Civ.INDEPENDENT_4,
- 1,
- Unit.ARCHER,
- 2,
- -1,
- 1,
-) # reduced to town on spawn of Sweden
-tBeloozero = (
- [((87, 65), "Beloozero", 100)],
- Civ.INDEPENDENT_4,
- 1,
- Unit.CROSSBOWMAN,
- 1,
- -1,
- 1,
-)
-tZagreb = (
- [((62, 34), "Sisak", 100)],
- Civ.INDEPENDENT,
- 2,
- Unit.ARCHER,
- 2,
- -1,
- 0,
-) # many Slavic princes reigned from Sisak in the 9th century, great for gameplay (buffer zone between Venice and Hungary)
-# 850 AD
-tBrennabor = (
- [((59, 50), "Brennabor", 50), ((60, 50), "Brennabor", 50)],
- Civ.BARBARIAN,
- 1,
- Unit.ARCHER,
- 2,
- -1,
- 0,
-) # Brandenburg or Berlin
-# 860 AD
-# tEdinburgh = ( [ ((37, 63), "Eidyn Dun", 100) ], Civ.BARBARIAN, 1, Unit.ARCHER, 1, -1, 0)
-# 880 AD
-tApulum = (
- [((73, 35), "Belograd", 80), ((73, 37), "Napoca", 20)],
- Civ.INDEPENDENT,
- 1,
- Unit.ARCHER,
- 2,
- -1,
- 0,
-) # Gyulafehérvár or Kolozsvár
-# 900 AD
-tTvanksta = (
- [((69, 53), "Tvanksta", 100)],
- Civ.INDEPENDENT_4,
- 1,
- Unit.CROSSBOWMAN,
- 2,
- -1,
- 0,
-) # Königsberg
-tKrakow = (
- [((68, 44), "Krakow", 100)],
- Civ.INDEPENDENT_3,
- 1,
- Unit.CROSSBOWMAN,
- 2,
- Religion.CATHOLICISM,
- 0,
-)
-tRiga = (
- [((74, 58), "Riga", 100)],
- Civ.INDEPENDENT,
- 2,
- Unit.CROSSBOWMAN,
- 2,
- -1,
- 1,
-) # maybe call it Duna in the early pediod (Duna is the name of a sheltered natural harbor near Riga)
-tWales = (
- [((36, 54), "Caerdydd", 50), ((35, 57), "Aberffraw", 50)],
- Civ.BARBARIAN,
- 1,
- Unit.ARCHER,
- 1,
- -1,
- 1,
-) # Cardiff and Caernarfon
-tVisby = (
- [((67, 60), "Visby", 100)],
- Civ.INDEPENDENT_2,
- 1,
- Unit.CROSSBOWMAN,
- 1,
- -1,
- 0,
-) # used to spawn in 1393 in the old system
-# 911 AD
-tCaenR = (
- [((40, 47), "Caen", 100)],
- Civ.INDEPENDENT_2,
- 1,
- Unit.CROSSBOWMAN,
- 2,
- Religion.CATHOLICISM,
- 0,
-) # respawn, on the establishment of the Duchy of Normandy
-# 960 AD
-tMinsk = ([((79, 52), "Minsk", 100)], Civ.INDEPENDENT_3, 1, Unit.CROSSBOWMAN, 2, -1, 0)
-tSmolensk = (
- [((84, 55), "Smolensk", 100)],
- Civ.INDEPENDENT_4,
- 1,
- Unit.CROSSBOWMAN,
- 1,
- -1,
- 0,
-)
-# 988 AD
-tDublinR = (
- [((32, 58), "Dubh Linn", 100)],
- Civ.BARBARIAN,
- 1,
- Unit.CROSSBOWMAN,
- 1,
- Religion.CATHOLICISM,
- 1,
-) # respawn, on the traditional Irish foundation date of Dublin
-# 1010 AD
-tYaroslavl = (
- [((92, 61), "Yaroslavl", 100)],
- Civ.INDEPENDENT_3,
- 1,
- Unit.CROSSBOWMAN,
- 1,
- -1,
- 0,
-)
-# 1050 AD
-tGroningen = (
- [((52, 54), "Groningen", 100)],
- Civ.INDEPENDENT_2,
- 1,
- Unit.CROSSBOWMAN,
- 2,
- Religion.CATHOLICISM,
- 0,
-)
-tKalmar = (
- [((64, 60), "Kalmar", 100)],
- Civ.INDEPENDENT_2,
- 2,
- Unit.CROSSBOWMAN,
- 1,
- Religion.CATHOLICISM,
- 1,
-)
-# 1060 AD
-# tMus = ( [ ((99, 21), "Mus", 100) ], Civ.BARBARIAN, 1, Unit.SELJUK_CROSSBOW, 2, -1, 0) #out of the map, not that important to represent the Seljuk/Timurid invasions this way
-# 1110 AD
-tGraz = (
- [((61, 37), "Graz", 100)],
- Civ.INDEPENDENT_3,
- 2,
- Unit.CROSSBOWMAN,
- 2,
- Religion.CATHOLICISM,
- 0,
-)
-# 1124 AD
-tHalych = (
- [((77, 41), "Halych", 100)],
- Civ.INDEPENDENT_2,
- 2,
- Unit.CROSSBOWMAN,
- 2,
- Religion.ORTHODOXY,
- 0,
-)
-# 1200 AD
-tRigaR = (
- [((74, 58), "Riga", 100)],
- Civ.INDEPENDENT,
- 3,
- Unit.CROSSBOWMAN,
- 2,
- -1,
- 1,
-) # respawn
-# tSaraiBatu = ( [ ((99, 40), "Sarai Batu", 100) ], Civ.BARBARIAN, 1, Unit.MONGOL_KESHIK, 2, -1, 0) #out of the map, not that important to represent the Mongol invasions this way
-# 1227 AD
-tTripoliR = (
- [((54, 8), "Tarabulus", 100)],
- Civ.BARBARIAN,
- 3,
- Unit.ARBALEST,
- 2,
- Religion.ISLAM,
- 1,
-) # respawn
-# 1250 AD
-tAbo = ([((71, 66), "Abo", 100)], Civ.INDEPENDENT_4, 1, Unit.CROSSBOWMAN, 1, -1, 0)
-tPerekop = (
- [((87, 36), "Or Qapi", 100)],
- Civ.BARBARIAN,
- 1,
- Unit.MONGOL_KESHIK,
- 2,
- -1,
- 0,
-)
-# 1320 AD
-tNizhnyNovgorod = (
- [((97, 58), "Nizhny Novgorod", 100)],
- Civ.INDEPENDENT,
- 1,
- Unit.CROSSBOWMAN,
- 1,
- -1,
- 0,
-)
-# 1392 AD
-tTanais = (
- [((96, 38), "Tana", 100)],
- Civ.BARBARIAN,
- 1,
- Unit.LONGBOWMAN,
- 2,
- Religion.ISLAM,
- 0,
-)
-# 1410 AD
-tReykjavik = (
- [((2, 70), "Reykjavik", 100)],
- Civ.INDEPENDENT,
- 1,
- Unit.VIKING_BERSERKER,
- 2,
- -1,
- 0,
-)
-# 1530 AD
-tValletta = (
- [((57, 14), "Valletta", 100)],
- Civ.INDEPENDENT_4,
- 1,
- Unit.KNIGHT_OF_ST_JOHNS,
- 3,
- Religion.CATHOLICISM,
- 0,
-)
-
-dIndependentCities = {
- DateTurn.i500AD: [
- tTangier,
- tBordeaux,
- tAlger,
- tBarcelona,
- tToulouse,
- tMarseilles,
- tNantes,
- tCaen,
- tLyon,
- tTunis,
- tYork,
- tLondon,
- tMilan,
- tFlorence,
- tTripoli,
- tAugsburg,
- tNapoli,
- tRagusa,
- tSeville,
- tPalermo,
- ],
- DateTurn.i552AD: [tInverness],
- DateTurn.i600AD: [tRhodes],
- DateTurn.i640AD: [tNorwich],
- DateTurn.i670AD: [tKairouan],
- DateTurn.i680AD: [tToledo, tLeicester],
- DateTurn.i700AD: [tValencia, tPamplona, tLubeck, tPorto, tDublin, tDownpatrick],
- DateTurn.i760AD: [tTonsberg],
- DateTurn.i768AD: [tRaska],
- DateTurn.i780AD: [tFez],
- DateTurn.i800AD: [tMilanR, tPrague, tKursk, tCalais, tNidaros, tUppsala, tBeloozero, tZagreb],
- DateTurn.i850AD: [tBrennabor],
- DateTurn.i880AD: [tApulum],
- DateTurn.i900AD: [tTvanksta, tKrakow, tRiga, tWales, tVisby],
- DateTurn.i911AD: [tCaenR],
- DateTurn.i960AD: [tMinsk, tSmolensk],
- DateTurn.i988AD: [tDublinR],
- DateTurn.i1010AD: [tYaroslavl],
- DateTurn.i1050AD: [tGroningen, tKalmar],
- DateTurn.i1110AD: [tGraz],
- DateTurn.i1124AD: [tHalych],
- DateTurn.i1200AD: [tRigaR],
- DateTurn.i1227AD: [tTripoliR],
- DateTurn.i1250AD: [tAbo, tPerekop],
- DateTurn.i1320AD: [tNizhnyNovgorod],
- DateTurn.i1393AD: [tTanais],
- DateTurn.i1410AD: [tReykjavik],
- DateTurn.i1530AD: [tValletta],
-}
-
-
-# Minor Nations structure: [ int Province: all cities in this province will revolt
-# list nations: a city controlled by those players will not revolt (i.e. Greece wouldn't revolt against the Byz)
-# list religions: a city owned by someone with one of those state religions will not revolt (i.e. Jerusalem doesn't revolt against Muslims)
-# list revolt dates: the dates for the revolt,
-# list revolt strength: this is subtracted from the odds to suppress the revolt (i.e. high number more likely to succeed in the revolt)
-# list units: corresponding to the revolt, if we crack down on the rebels, what barbarian units should spawn
-# list number: corresponding to the revolt, if we crack down on the rebels, how many units should spawn (note if we don't bribe the Lords, then double the number of Units will spawn)
-# list text keys: text keys for "The Nation" and "Nation Adjective"
-# Note: lists 3, 4, 5, 6 should have the same size
-# Note: you should increase the size of 'lNextMinorRevolt' in StoredData to be at least the number of minor nations
-lMinorNations = [
- [
- Province.SERBIA,
- [],
- [],
- [DateTurn.i508AD, DateTurn.i852AD, DateTurn.i1346AD],
- [20, 20, 20],
- [Unit.AXEMAN, Unit.AXEMAN, Unit.LONG_SWORDSMAN],
- [2, 1, 2],
- ["TXT_KEY_THE_SERBS", "TXT_KEY_SERBIAN"],
- ],
- [
- Province.SCOTLAND,
- [Civ.SCOTLAND],
- [],
- [DateTurn.i1297AD, DateTurn.i1569AD, DateTurn.i1715AD],
- [20, 10, 20],
- [Unit.HIGHLANDER, Unit.MUSKETMAN, Unit.GRENADIER],
- [2, 2, 2],
- ["TXT_KEY_THE_SCOTS", "TXT_KEY_SCOTTISH"],
- ],
- [
- Province.CATALONIA,
- [Civ.ARAGON],
- [],
- [DateTurn.i1164AD + 10, DateTurn.i1640AD],
- [20, 10],
- [Unit.LONG_SWORDSMAN, Unit.MUSKETMAN],
- [2, 2],
- ["TXT_KEY_THE_CATALANS", "TXT_KEY_CATALAN"],
- ],
- [
- Province.JERUSALEM,
- [Civ.ARABIA, Civ.OTTOMAN, Civ.BYZANTIUM],
- [Religion.ISLAM],
- [
- DateTurn.i1099AD + 8,
- DateTurn.i1099AD + 16,
- DateTurn.i1099AD + 25,
- DateTurn.i1099AD + 33,
- DateTurn.i1099AD + 40,
- DateTurn.i1099AD + 47,
- DateTurn.i1099AD + 55,
- DateTurn.i1099AD + 65,
- ],
- [30, 30, 40, 40, 30, 30, 30, 30],
- [
- Unit.MACEMAN,
- Unit.MACEMAN,
- Unit.MACEMAN,
- Unit.KNIGHT,
- Unit.KNIGHT,
- Unit.KNIGHT,
- Unit.KNIGHT,
- Unit.KNIGHT,
- ],
- [3, 3, 4, 3, 3, 3, 3, 3],
- ["TXT_KEY_THE_MUSLIMS", "TXT_KEY_MUSLIM"],
- ],
- [
- Province.SYRIA,
- [Civ.ARABIA, Civ.OTTOMAN, Civ.BYZANTIUM],
- [Religion.ISLAM],
- [
- DateTurn.i1099AD + 8,
- DateTurn.i1099AD + 16,
- DateTurn.i1099AD + 25,
- DateTurn.i1099AD + 33,
- DateTurn.i1099AD + 40,
- DateTurn.i1099AD + 47,
- DateTurn.i1099AD + 55,
- DateTurn.i1099AD + 65,
- ],
- [30, 30, 40, 40, 30, 30, 30, 30],
- [
- Unit.MACEMAN,
- Unit.MACEMAN,
- Unit.MACEMAN,
- Unit.KNIGHT,
- Unit.KNIGHT,
- Unit.KNIGHT,
- Unit.KNIGHT,
- Unit.KNIGHT,
- ],
- [3, 3, 4, 3, 3, 3, 3, 3],
- ["TXT_KEY_THE_MUSLIMS", "TXT_KEY_MUSLIM"],
- ],
- [
- Province.ORAN,
- [],
- [],
- [DateTurn.i1236AD, DateTurn.i1346AD, DateTurn.i1359AD, DateTurn.i1542AD],
- [40, 10, 10, 20],
- [
- Unit.KNIGHT,
- Unit.HEAVY_LANCER,
- Unit.HEAVY_LANCER,
- Unit.MUSKETMAN,
- ],
- [2, 2, 2, 2],
- ["TXT_KEY_THE_ZIYYANIDS", "TXT_KEY_ZIYYANID"],
- ],
- [
- Province.FEZ,
- [Civ.MOROCCO],
- [],
- [DateTurn.i1473AD],
- [30],
- [Unit.ARQUEBUSIER],
- [4],
- ["TXT_KEY_THE_WATTASIDS", "TXT_KEY_WATTASID"],
- ],
-]
-# 3Miro: Jerusalem and Syria were added here, so the Crusaders will not be able to control it for too long
-
-
-class Barbs:
- def getRevolDates(self):
- return data.lNextMinorRevolt
-
- def setRevolDates(self, lNextMinorRevolt):
- data.lNextMinorRevolt = lNextMinorRevolt
-
- def getTempFlippingCity(self):
- return data.iTempFlippingCity
-
- def setTempFlippingCity(self, tNewValue):
- data.iTempFlippingCity = tNewValue
-
- def getNationRevoltIndex(self):
- return data.lRevoltinNationRevoltIndex
-
- def setNationRevoltIndex(self, iNationIndex, iRevoltIndex):
- data.lRevoltinNationRevoltIndex = [iNationIndex, iRevoltIndex]
-
- def checkTurn(self, iGameTurn):
- # Handicap level modifier
- iHandicap = gc.getGame().getHandicapType() - 1
- # gc.getGame().getHandicapType: Viceroy=0, Monarch=1, Emperor=2
- # iHandicap: Viceroy=-1, Monarch=0, Emperor=1
-
- # The Human player usually gets some additional barbarians
- iHuman = human()
-
- # Mediterranean Pirates (Light before 1500, then heavy for rest of game)
- if DateTurn.i960AD <= iGameTurn < DateTurn.i1401AD:
- self.spawnPirate(
- Civ.BARBARIAN,
- (9, 15),
- (55, 33),
- Unit.WAR_GALLEY,
- 2,
- 0,
- 0,
- iGameTurn,
- 10,
- 3,
- outerSeaSpawn,
- )
- elif iGameTurn >= DateTurn.i1401AD:
- self.spawnPirate(
- Civ.BARBARIAN,
- (9, 15),
- (55, 33),
- Unit.CORSAIR,
- 2,
- 0,
- 0,
- iGameTurn,
- 10,
- 3,
- outerSeaSpawn,
- text("TXT_KEY_BARBARIAN_NAMES_BARBARY_PIRATES"),
- )
- # extra Corsairs around Tunisia
- self.spawnPirate(
- Civ.BARBARIAN,
- (42, 15),
- (54, 23),
- Unit.CORSAIR,
- 1,
- 0,
- 0,
- iGameTurn,
- 5,
- 0,
- outerSeaSpawn,
- text("TXT_KEY_BARBARIAN_NAMES_BARBARY_PIRATES"),
- )
- if DateTurn.i1200AD <= iGameTurn < DateTurn.i1500AD:
- self.spawnPirate(
- Civ.BARBARIAN,
- (9, 15),
- (55, 33),
- Unit.COGGE,
- 1,
- Unit.SWORDSMAN,
- 2,
- iGameTurn,
- 10,
- 5,
- outerSeaSpawn,
- )
- elif iGameTurn >= DateTurn.i1500AD:
- self.spawnPirate(
- Civ.BARBARIAN,
- (9, 15),
- (55, 33),
- Unit.GALLEON,
- 1,
- Unit.MUSKETMAN,
- 2,
- iGameTurn,
- 10,
- 5,
- outerSeaSpawn,
- )
-
- # Germanic Barbarians throughout Western Europe (France, Germany)
- if iGameTurn < DateTurn.i600AD:
- self.spawnUnits(
- Civ.BARBARIAN,
- (43, 42),
- (50, 50),
- Unit.AXEMAN,
- 1,
- iGameTurn,
- 11,
- 1,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_GERMANIC_TRIBES"),
- )
- if Civ.FRANCE == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (42, 40),
- (56, 48),
- Unit.AXEMAN,
- 1,
- iGameTurn,
- 9,
- 3,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_GERMANIC_TRIBES"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (45, 45),
- (60, 55),
- Unit.SPEARMAN,
- 1,
- iGameTurn,
- 18,
- 7,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_GERMANIC_TRIBES"),
- )
- elif DateTurn.i600AD <= iGameTurn < DateTurn.i800AD:
- self.spawnUnits(
- Civ.BARBARIAN,
- (43, 42),
- (50, 50),
- Unit.AXEMAN,
- 1,
- iGameTurn,
- 9,
- 2,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_GERMANIC_TRIBES"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (42, 40),
- (56, 48),
- Unit.AXEMAN,
- 1,
- iGameTurn,
- 11,
- 4,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_GERMANIC_TRIBES"),
- )
- if Civ.FRANCE == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (43, 42),
- (50, 50),
- Unit.AXEMAN,
- 1,
- iGameTurn,
- 9,
- 3,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_GERMANIC_TRIBES"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (45, 45),
- (60, 55),
- Unit.SPEARMAN,
- 1 + iHandicap,
- iGameTurn,
- 11,
- 4,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_GERMANIC_TRIBES"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (46, 48),
- (62, 55),
- Unit.AXEMAN,
- 1 + iHandicap,
- iGameTurn,
- 14,
- 9,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_GERMANIC_TRIBES"),
- )
-
- # Longobards in Italy
- if DateTurn.i632AD <= iGameTurn <= DateTurn.i800AD:
- self.spawnUnits(
- Civ.BARBARIAN,
- (49, 33),
- (53, 36),
- Unit.AXEMAN,
- 1 + iHandicap,
- iGameTurn,
- 10,
- 3,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_LONGOBARDS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (49, 33),
- (53, 36),
- Unit.SPEARMAN,
- 1,
- iGameTurn,
- 12,
- 0,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_LONGOBARDS"),
- )
-
- # Visigoths in Iberia
- if DateTurn.i712AD <= iGameTurn <= DateTurn.i892AD:
- self.spawnUnits(
- Civ.BARBARIAN,
- (22, 21),
- (26, 25),
- Unit.AXEMAN,
- 1,
- iGameTurn,
- 7,
- 0,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_VISIGOTHS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (23, 23),
- (27, 28),
- Unit.SPEARMAN,
- 1,
- iGameTurn,
- 7,
- 3,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_VISIGOTHS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (26, 27),
- (31, 32),
- Unit.MOUNTED_INFANTRY,
- 1,
- iGameTurn,
- 9,
- 5,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_VISIGOTHS"),
- )
- if Civ.CORDOBA == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (24, 31),
- (27, 34),
- Unit.AXEMAN,
- 1 + iHandicap,
- iGameTurn,
- 7,
- 0,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_VISIGOTHS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (27, 28),
- (31, 36),
- Unit.MOUNTED_INFANTRY,
- 1,
- iGameTurn,
- 6,
- 3,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_VISIGOTHS"),
- )
-
- # Berbers in North Africa
- if DateTurn.i700AD <= iGameTurn < DateTurn.i1020AD:
- # Tunesia
- self.spawnUnits(
- Civ.BARBARIAN,
- (28, 10),
- (35, 14),
- Unit.HORSE_ARCHER,
- 1 + iHandicap,
- iGameTurn,
- 8,
- 0,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_BERBERS"),
- )
- # Morocco
- if Civ.CORDOBA == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (21, 3),
- (27, 12),
- Unit.HORSE_ARCHER,
- 1,
- iGameTurn,
- 9,
- 0,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_BERBERS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (22, 3),
- (27, 10),
- Unit.AXEMAN,
- 1,
- iGameTurn,
- 11,
- 5,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_BERBERS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (23, 3),
- (27, 8),
- Unit.SPEARMAN,
- 1,
- iGameTurn,
- 7,
- 3,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_BERBERS"),
- )
- else:
- self.spawnUnits(
- Civ.BARBARIAN,
- (22, 3),
- (27, 10),
- Unit.AXEMAN,
- 1,
- iGameTurn,
- 14,
- 5,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_BERBERS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (23, 3),
- (27, 8),
- Unit.SPEARMAN,
- 1,
- iGameTurn,
- 8,
- 3,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_BERBERS"),
- )
-
- # Avars in the Carpathian Basin
- if DateTurn.i632AD <= iGameTurn < DateTurn.i800AD:
- self.spawnUnits(
- Civ.BARBARIAN,
- (60, 30),
- (75, 40),
- Unit.HORSE_ARCHER,
- 1,
- iGameTurn,
- 5,
- 0,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_AVARS"),
- )
- if Civ.BULGARIA == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (66, 26),
- (73, 29),
- Unit.HORSE_ARCHER,
- 1 + iHandicap,
- iGameTurn,
- 6,
- 1,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_AVARS"),
- )
-
- # Early barbs for Byzantium:
- if iGameTurn < DateTurn.i640AD:
- # Pre-Bulgarian Slavs in the Balkans
- self.spawnUnits(
- Civ.BARBARIAN,
- (68, 18),
- (78, 28),
- Unit.AXEMAN,
- 1,
- iGameTurn,
- 8,
- 0,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SOUTHERN_SLAVS"),
- )
- if Civ.BYZANTIUM == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (64, 21),
- (75, 25),
- Unit.AXEMAN,
- 1 + iHandicap,
- iGameTurn,
- 11,
- 3,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SOUTHERN_SLAVS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (68, 18),
- (78, 28),
- Unit.SPEARMAN,
- 1,
- iGameTurn,
- 8,
- 0,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SOUTHERN_SLAVS"),
- )
- # Sassanids in Anatolia
- self.spawnUnits(
- Civ.BARBARIAN,
- (90, 15),
- (99, 28),
- Unit.LANCER,
- 1,
- iGameTurn,
- 6,
- 2,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SASSANIDS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (94, 19),
- (98, 26),
- Unit.LANCER,
- 1,
- iGameTurn,
- 9,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SASSANIDS"),
- )
- if Civ.BYZANTIUM == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (90, 15),
- (99, 28),
- Unit.LANCER,
- 1,
- iGameTurn,
- 6,
- 2,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SASSANIDS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (94, 19),
- (98, 26),
- Unit.LANCER,
- 1 + iHandicap,
- iGameTurn,
- 9,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SASSANIDS"),
- )
- # Barbs in NW Greece
- if iGameTurn < DateTurn.i720AD:
- self.spawnUnits(
- Civ.BARBARIAN,
- (66, 21),
- (69, 28),
- Unit.AXEMAN,
- 1,
- iGameTurn,
- 9,
- 3,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- )
- if Civ.BYZANTIUM == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (66, 21),
- (69, 28),
- Unit.SPEARMAN,
- 1 + iHandicap,
- iGameTurn,
- 9,
- 3,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- )
-
- # Serbs in the Southern Balkans
- if DateTurn.i1025AD <= iGameTurn < DateTurn.i1282AD:
- if Civ.BYZANTIUM == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (67, 24),
- (73, 28),
- Unit.AXEMAN,
- 1,
- iGameTurn,
- 9,
- 3,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SERBS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (67, 24),
- (73, 28),
- Unit.LANCER,
- 1 + iHandicap,
- iGameTurn,
- 11,
- 7,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SERBS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (69, 25),
- (71, 29),
- Unit.SWORDSMAN,
- 1,
- iGameTurn,
- 7,
- 4,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SERBS"),
- )
- else:
- self.spawnUnits(
- Civ.BARBARIAN,
- (67, 24),
- (73, 28),
- Unit.AXEMAN,
- 1,
- iGameTurn,
- 9,
- 3,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SERBS"),
- )
-
- # Khazars
- if DateTurn.i660AD <= iGameTurn < DateTurn.i864AD:
- self.spawnUnits(
- Civ.BARBARIAN,
- (88, 31),
- (99, 40),
- Unit.AXEMAN,
- 1,
- iGameTurn,
- 8,
- 0,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_KHAZARS"),
- )
- elif DateTurn.i864AD <= iGameTurn < DateTurn.i920AD:
- if Civ.KIEV == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (88, 31),
- (99, 40),
- Unit.AXEMAN,
- 1,
- iGameTurn,
- 7,
- 2,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_KHAZARS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (88, 31),
- (99, 40),
- Unit.SPEARMAN,
- 1,
- iGameTurn,
- 5,
- 2,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_KHAZARS"),
- )
- else:
- self.spawnUnits(
- Civ.BARBARIAN,
- (88, 31),
- (99, 40),
- Unit.AXEMAN,
- 1,
- iGameTurn,
- 11,
- 2,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_KHAZARS"),
- )
-
- # Pechenegs
- if DateTurn.i920AD <= iGameTurn < DateTurn.i1040AD:
- # in the Rus
- self.spawnUnits(
- Civ.BARBARIAN,
- (89, 34),
- (97, 40),
- Unit.STEPPE_HORSE_ARCHER,
- 1,
- iGameTurn,
- 8,
- 3,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_PECHENEGS"),
- )
- if Civ.KIEV == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (91, 35),
- (99, 44),
- Unit.STEPPE_HORSE_ARCHER,
- 1 + iHandicap,
- iGameTurn,
- 5,
- 1,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_PECHENEGS"),
- )
- # in Hungary
- self.spawnUnits(
- Civ.BARBARIAN,
- (66, 35),
- (75, 42),
- Unit.STEPPE_HORSE_ARCHER,
- 1,
- iGameTurn,
- 9,
- 1,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_PECHENEGS"),
- )
- if Civ.HUNGARY == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (66, 35),
- (75, 42),
- Unit.STEPPE_HORSE_ARCHER,
- 1 + iHandicap,
- iGameTurn,
- 9,
- 1,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_PECHENEGS"),
- )
- # in Bulgaria
- elif Civ.BULGARIA == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (77, 31),
- (79, 33),
- Unit.STEPPE_HORSE_ARCHER,
- 2 + iHandicap,
- iGameTurn,
- 5,
- 1,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_PECHENEGS"),
- )
-
- # Cumans and Kipchaks
- elif DateTurn.i1040AD <= iGameTurn < DateTurn.i1200AD:
- # in the Rus
- if Civ.KIEV == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (89, 34),
- (99, 40),
- Unit.STEPPE_HORSE_ARCHER,
- 2,
- iGameTurn,
- 7,
- 5,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_CUMANS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (90, 33),
- (97, 44),
- Unit.STEPPE_HORSE_ARCHER,
- 2 + iHandicap,
- iGameTurn,
- 9,
- 1,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_KIPCHAKS"),
- )
- else:
- self.spawnUnits(
- Civ.BARBARIAN,
- (89, 34),
- (99, 40),
- Unit.STEPPE_HORSE_ARCHER,
- 1,
- iGameTurn,
- 7,
- 5,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_CUMANS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (90, 33),
- (97, 44),
- Unit.STEPPE_HORSE_ARCHER,
- 1,
- iGameTurn,
- 9,
- 1,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_KIPCHAKS"),
- )
- # in Hungary
- self.spawnUnits(
- Civ.BARBARIAN,
- (64, 33),
- (77, 43),
- Unit.STEPPE_HORSE_ARCHER,
- 1,
- iGameTurn,
- 7,
- 1,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_CUMANS"),
- )
- if Civ.HUNGARY == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (64, 33),
- (77, 43),
- Unit.STEPPE_HORSE_ARCHER,
- 1,
- iGameTurn,
- 7,
- 1,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_CUMANS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (66, 35),
- (75, 42),
- Unit.STEPPE_HORSE_ARCHER,
- 1,
- iGameTurn,
- 9,
- 4,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_KIPCHAKS"),
- )
- # in Bulgaria
- if Civ.BULGARIA == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (78, 32),
- (80, 34),
- Unit.STEPPE_HORSE_ARCHER,
- 1,
- iGameTurn,
- 7,
- 3,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_CUMANS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (78, 32),
- (80, 34),
- Unit.STEPPE_HORSE_ARCHER,
- 1,
- iGameTurn,
- 7,
- 3,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_KIPCHAKS"),
- )
-
- # Vikings on ships
- if Civ.NORWAY == iHuman: # Humans can properly go viking without help
- pass
- elif DateTurn.i780AD <= iGameTurn < DateTurn.i1000AD:
- if Civ.FRANCE == iHuman:
- self.spawnVikings(
- Civ.BARBARIAN,
- (37, 48),
- (50, 54),
- Unit.VIKING_BERSERKER,
- 2,
- iGameTurn,
- 8,
- 0,
- outerSeaSpawn,
- text("TXT_KEY_BARBARIAN_NAMES_VIKINGS"),
- )
- else:
- self.spawnVikings(
- Civ.BARBARIAN,
- (37, 48),
- (50, 54),
- Unit.VIKING_BERSERKER,
- 1,
- iGameTurn,
- 8,
- 0,
- outerSeaSpawn,
- text("TXT_KEY_BARBARIAN_NAMES_VIKINGS"),
- )
-
- # Swedish Crusades
- elif DateTurn.i1150AD <= iGameTurn < DateTurn.i1210AD:
- self.spawnVikings(
- Civ.BARBARIAN,
- (71, 62),
- (76, 65),
- Unit.VIKING_BERSERKER,
- 2,
- iGameTurn,
- 6,
- 1,
- outerSeaSpawn,
- text("TXT_KEY_BARBARIAN_NAMES_SWEDES"),
- )
-
- # Chudes in Finland and Estonia
- if DateTurn.i864AD <= iGameTurn < DateTurn.i1150AD:
- self.spawnUnits(
- Civ.BARBARIAN,
- (72, 67),
- (81, 72),
- Unit.AXEMAN,
- 1,
- iGameTurn,
- 7,
- 0,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_CHUDES"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (74, 60),
- (76, 63),
- Unit.AXEMAN,
- 1,
- iGameTurn,
- 11,
- 3,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_CHUDES"),
- )
-
- # Livonian Order as barbs in the area before the Prussian spawn, but only if Prussia is AI (no need for potentially gained extra units for the human player)
- # Also pre-Lithanian barbs for human Prussia a couple turns before the Lithuanian spawn
- if Civ.PRUSSIA == iHuman:
- if DateTurn.i1224AD <= iGameTurn < DateTurn.i1236AD:
- self.spawnUnits(
- Civ.BARBARIAN,
- (73, 56),
- (76, 61),
- Unit.AXEMAN,
- 1,
- iGameTurn,
- 2,
- 1,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_BALTICS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (72, 54),
- (75, 59),
- Unit.AXEMAN,
- 1,
- iGameTurn,
- 2,
- 1,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_BALTICS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (73, 56),
- (76, 61),
- Unit.HORSE_ARCHER,
- 1 + iHandicap,
- iGameTurn,
- 2,
- 1,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_BALTICS"),
- )
- elif DateTurn.i1200AD <= iGameTurn < DateTurn.i1224AD:
- self.spawnUnits(
- Civ.BARBARIAN,
- (73, 57),
- (76, 61),
- Unit.TEUTONIC,
- 1,
- iGameTurn,
- 4,
- 3,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SWORD_BRETHEN"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (73, 57),
- (76, 61),
- Unit.SWORDSMAN,
- 1,
- iGameTurn,
- 4,
- 1,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SWORD_BRETHEN"),
- )
-
- # Couple melee barb units in Ireland:
- if DateTurn.i800AD <= iGameTurn < DateTurn.i900AD:
- self.spawnUnits(
- Civ.BARBARIAN,
- (28, 56),
- (33, 62),
- Unit.AXEMAN,
- 1,
- iGameTurn,
- 7,
- 3,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_IRISH"),
- )
-
- # Anglo-Saxons before the Danish 1st UHV (Conquer England)
- elif DateTurn.i970AD <= iGameTurn < DateTurn.i1050AD:
- if Civ.DENMARK == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (36, 53),
- (41, 59),
- Unit.AXEMAN,
- 1,
- iGameTurn,
- 8,
- 5,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_ANGLO_SAXONS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (33, 48),
- (38, 54),
- Unit.AXEMAN,
- 1,
- iGameTurn,
- 5,
- 2,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_ANGLO_SAXONS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (33, 48),
- (38, 54),
- Unit.SWORDSMAN,
- 1,
- iGameTurn,
- 11,
- 6,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_ANGLO_SAXONS"),
- )
- else:
- self.spawnUnits(
- Civ.BARBARIAN,
- (33, 48),
- (38, 54),
- Unit.AXEMAN,
- 1,
- iGameTurn,
- 5,
- 2,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_ANGLO_SAXONS"),
- )
-
- # Scots to keep England busy, but only if Scotland is dead
- if not gc.getPlayer(Civ.SCOTLAND).isAlive():
- if DateTurn.i1060AD <= iGameTurn < DateTurn.i1320AD:
- if Civ.ENGLAND == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (39, 62),
- (44, 66),
- Unit.HIGHLANDER,
- 2,
- iGameTurn,
- 11,
- 0,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SCOTS"),
- )
- else:
- self.spawnUnits(
- Civ.BARBARIAN,
- (39, 62),
- (44, 66),
- Unit.HIGHLANDER,
- 1,
- iGameTurn,
- 11,
- 0,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SCOTS"),
- )
- elif DateTurn.i1320AD <= iGameTurn < DateTurn.i1500AD:
- if Civ.ENGLAND == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (39, 62),
- (44, 66),
- Unit.HIGHLANDER,
- 2,
- iGameTurn,
- 9,
- 0,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SCOTS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (39, 64),
- (44, 67),
- Unit.HIGHLANDER,
- 2 + iHandicap,
- iGameTurn,
- 17,
- 4,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SCOTS"),
- )
- else:
- self.spawnUnits(
- Civ.BARBARIAN,
- (39, 64),
- (44, 67),
- Unit.HIGHLANDER,
- 2,
- iGameTurn,
- 17,
- 4,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SCOTS"),
- )
-
- # Welsh in Britain
- if DateTurn.i1060AD <= iGameTurn < DateTurn.i1160AD:
- if Civ.ENGLAND == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (37, 53),
- (39, 57),
- Unit.WELSH_LONGBOWMAN,
- 1,
- iGameTurn,
- 7,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_WELSH"),
- )
- else:
- self.spawnUnits(
- Civ.BARBARIAN,
- (37, 53),
- (39, 57),
- Unit.WELSH_LONGBOWMAN,
- 1,
- iGameTurn,
- 13,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_WELSH"),
- )
- elif DateTurn.i1160AD <= iGameTurn < DateTurn.i1452AD:
- if Civ.ENGLAND == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (37, 53),
- (39, 57),
- Unit.WELSH_LONGBOWMAN,
- 2 + iHandicap,
- iGameTurn,
- 12,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_WELSH"),
- )
- else:
- self.spawnUnits(
- Civ.BARBARIAN,
- (37, 53),
- (39, 57),
- Unit.WELSH_LONGBOWMAN,
- 1,
- iGameTurn,
- 9,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_WELSH"),
- )
-
- # Magyars (preceeding Hungary)
- if DateTurn.i840AD <= iGameTurn < DateTurn.i892AD:
- self.spawnUnits(
- Civ.BARBARIAN,
- (54, 38),
- (61, 45),
- Unit.HORSE_ARCHER,
- 1,
- iGameTurn,
- 4,
- 1,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_MAGYARS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (66, 26),
- (73, 29),
- Unit.HORSE_ARCHER,
- 1,
- iGameTurn,
- 4,
- 2,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_MAGYARS"),
- )
- if Civ.BULGARIA == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (77, 31),
- (80, 34),
- Unit.HORSE_ARCHER,
- 2 + iHandicap,
- iGameTurn,
- 5,
- 0,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_MAGYARS"),
- )
- elif Civ.GERMANY == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (54, 38),
- (61, 45),
- Unit.HORSE_ARCHER,
- 2 + iHandicap,
- iGameTurn,
- 5,
- 3,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_MAGYARS"),
- )
-
- # Wends in NE Germany
- if DateTurn.i860AD <= iGameTurn < DateTurn.i1053AD:
- if Civ.GERMANY == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (55, 49),
- (60, 56),
- Unit.AXEMAN,
- 1,
- iGameTurn,
- 6,
- 1,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_WENDS"),
- )
- else:
- self.spawnUnits(
- Civ.BARBARIAN,
- (55, 49),
- (60, 56),
- Unit.AXEMAN,
- 1,
- iGameTurn,
- 8,
- 1,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_WENDS"),
- )
-
- # Great Slav Rising in 983AD
- if (DateTurn.i983AD - 1) <= iGameTurn < (DateTurn.i983AD + 1):
- if Civ.GERMANY == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (53, 48),
- (59, 55),
- Unit.AXEMAN,
- 2,
- iGameTurn,
- 2,
- 0,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_WENDS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (53, 48),
- (59, 55),
- Unit.SPEARMAN,
- 1,
- iGameTurn,
- 2,
- 0,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_WENDS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (53, 48),
- (59, 55),
- Unit.SWORDSMAN,
- 1,
- iGameTurn,
- 2,
- 0,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_WENDS"),
- )
- else:
- self.spawnUnits(
- Civ.BARBARIAN,
- (53, 48),
- (59, 55),
- Unit.AXEMAN,
- 1,
- iGameTurn,
- 2,
- 0,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_WENDS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (53, 48),
- (59, 55),
- Unit.SPEARMAN,
- 1,
- iGameTurn,
- 2,
- 0,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_WENDS"),
- )
-
- # Barbs in the middle east
- if DateTurn.i700AD <= iGameTurn <= DateTurn.i1300AD:
- if not gc.getTeam(gc.getPlayer(Civ.ARABIA).getTeam()).isHasTech(Technology.FARRIERS):
- self.spawnUnits(
- Civ.BARBARIAN,
- (94, 0),
- (99, 3),
- Unit.HORSE_ARCHER,
- 1,
- iGameTurn,
- 11,
- 3,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_BEDUINS"),
- )
- if gc.getPlayer(Civ.ARABIA).isHuman():
- self.spawnUnits(
- Civ.BARBARIAN,
- (94, 0),
- (99, 3),
- Unit.HORSE_ARCHER,
- 1 + iHandicap,
- iGameTurn,
- 11,
- 3,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_BEDUINS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (92, 1),
- (98, 4),
- Unit.HORSE_ARCHER,
- 1,
- iGameTurn,
- 8,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_BEDUINS"),
- )
- else:
- self.spawnUnits(
- Civ.BARBARIAN,
- (94, 0),
- (99, 3),
- Unit.BEDOUIN,
- 1,
- iGameTurn,
- 10,
- 2,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_BEDUINS"),
- )
- if gc.getPlayer(Civ.ARABIA).isHuman():
- self.spawnUnits(
- Civ.BARBARIAN,
- (94, 0),
- (99, 3),
- Unit.BEDOUIN,
- 1 + iHandicap,
- iGameTurn,
- 10,
- 2,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_BEDUINS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (95, 1),
- (98, 5),
- Unit.BEDOUIN,
- 1,
- iGameTurn,
- 7,
- 3,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_BEDUINS"),
- )
-
- # Banu Hilal and Bani Hassan, in Morocco and Tunesia
- if DateTurn.i1040AD <= iGameTurn < DateTurn.i1229AD:
- if Civ.MOROCCO == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (40, 10),
- (44, 14),
- Unit.BEDOUIN,
- 2 + iHandicap,
- iGameTurn,
- 11,
- 2,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_BANU_HILAL"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (44, 1),
- (50, 8),
- Unit.TOUAREG,
- 2 + iHandicap,
- iGameTurn,
- 8,
- 5,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_BANU_HILAL"),
- )
- else:
- self.spawnUnits(
- Civ.BARBARIAN,
- (40, 10),
- (44, 14),
- Unit.BEDOUIN,
- 1,
- iGameTurn,
- 11,
- 2,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_BANU_HILAL"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (44, 1),
- (50, 8),
- Unit.TOUAREG,
- 1,
- iGameTurn,
- 8,
- 5,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_BANU_HILAL"),
- )
- if DateTurn.i1640AD <= iGameTurn < DateTurn.i1680AD:
- self.spawnUnits(
- Civ.BARBARIAN,
- (18, 1),
- (22, 3),
- Unit.BEDOUIN,
- 5 + iHandicap * 2,
- iGameTurn,
- 3,
- 1,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_BANI_HASSAN"),
- )
-
- # Pre Mongols to keep Kiev busy
- if DateTurn.i900AD <= iGameTurn < DateTurn.i1020AD:
- self.spawnUnits(
- Civ.BARBARIAN,
- (93, 35),
- (99, 44),
- Unit.HORSE_ARCHER,
- 1,
- iGameTurn,
- 13,
- 1,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- )
- elif DateTurn.i1020AD <= iGameTurn < DateTurn.i1236AD:
- self.spawnUnits(
- Civ.BARBARIAN,
- (93, 35),
- (99, 44),
- Unit.HORSE_ARCHER,
- 1,
- iGameTurn,
- 9,
- 5,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- )
- if Civ.KIEV == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (94, 32),
- (97, 39),
- Unit.HORSE_ARCHER,
- 2 + iHandicap,
- iGameTurn,
- 10,
- 1,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- )
-
- # Barbs in Anatolia pre Seljuks (but after Sassanids)
- if DateTurn.i700AD <= iGameTurn < DateTurn.i1050AD:
- self.spawnUnits(
- Civ.BARBARIAN,
- (97, 20),
- (99, 26),
- Unit.HORSE_ARCHER,
- 1,
- iGameTurn,
- 10,
- 1,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (95, 20),
- (99, 24),
- Unit.AXEMAN,
- 1,
- iGameTurn,
- 14,
- 2,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (95, 22),
- (97, 26),
- Unit.SPEARMAN,
- 1,
- iGameTurn,
- 16,
- 6,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- )
- if Civ.BYZANTIUM == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (97, 20),
- (99, 26),
- Unit.HORSE_ARCHER,
- 1 + iHandicap,
- iGameTurn,
- 10,
- 1,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (95, 20),
- (99, 24),
- Unit.AXEMAN,
- 1,
- iGameTurn,
- 14,
- 2,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (95, 20),
- (99, 24),
- Unit.HORSE_ARCHER,
- 1 + iHandicap,
- iGameTurn,
- 14,
- 2,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (95, 22),
- (97, 26),
- Unit.SPEARMAN,
- 1,
- iGameTurn,
- 16,
- 6,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (95, 22),
- (97, 26),
- Unit.HORSE_ARCHER,
- 1 + iHandicap,
- iGameTurn,
- 16,
- 6,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- )
-
- # Seljuks
- if DateTurn.i1064AD <= iGameTurn < DateTurn.i1094AD:
- self.spawnUnits(
- Civ.BARBARIAN,
- (90, 21),
- (99, 28),
- Unit.SELJUK_LANCER,
- 3,
- iGameTurn,
- 3,
- 0,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (90, 21),
- (99, 28),
- Unit.TURCOMAN_HORSE_ARCHER,
- 1,
- iGameTurn,
- 3,
- 0,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (90, 21),
- (99, 28),
- Unit.SELJUK_CROSSBOW,
- 1,
- iGameTurn,
- 3,
- 0,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (90, 21),
- (99, 28),
- Unit.SELJUK_SWORDSMAN,
- 1,
- iGameTurn,
- 3,
- 0,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (92, 20),
- (99, 25),
- Unit.SELJUK_LANCER,
- 3,
- iGameTurn,
- 3,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (92, 20),
- (99, 25),
- Unit.TURCOMAN_HORSE_ARCHER,
- 1,
- iGameTurn,
- 3,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (92, 20),
- (99, 25),
- Unit.SELJUK_GUISARME,
- 1,
- iGameTurn,
- 3,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (92, 20),
- (99, 25),
- Unit.SELJUK_FOOTMAN,
- 1,
- iGameTurn,
- 3,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (95, 8),
- (99, 12),
- Unit.SELJUK_LANCER,
- 2,
- iGameTurn,
- 4,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (95, 8),
- (99, 12),
- Unit.SELJUK_CROSSBOW,
- 1,
- iGameTurn,
- 4,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
- )
- if Civ.BYZANTIUM == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (90, 21),
- (99, 28),
- Unit.SELJUK_LANCER,
- 1,
- iGameTurn,
- 3,
- 0,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (90, 21),
- (99, 28),
- Unit.TURCOMAN_HORSE_ARCHER,
- 1,
- iGameTurn,
- 3,
- 0,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (90, 21),
- (99, 28),
- Unit.SELJUK_CROSSBOW,
- 1 + iHandicap,
- iGameTurn,
- 3,
- 0,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (90, 21),
- (99, 28),
- Unit.SELJUK_GUISARME,
- 1,
- iGameTurn,
- 3,
- 0,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (90, 21),
- (99, 28),
- Unit.SELJUK_FOOTMAN,
- 1 + iHandicap,
- iGameTurn,
- 3,
- 0,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (92, 20),
- (99, 25),
- Unit.SELJUK_LANCER,
- 1,
- iGameTurn,
- 3,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (92, 20),
- (99, 25),
- Unit.TURCOMAN_HORSE_ARCHER,
- 1,
- iGameTurn,
- 3,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (92, 20),
- (99, 25),
- Unit.SELJUK_GUISARME,
- 1 + iHandicap,
- iGameTurn,
- 3,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (92, 20),
- (99, 25),
- Unit.SELJUK_CROSSBOW,
- 1,
- iGameTurn,
- 3,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (92, 20),
- (99, 25),
- Unit.SELJUK_SWORDSMAN,
- 1 + iHandicap,
- iGameTurn,
- 3,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
- )
- elif Civ.ARABIA == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (95, 8),
- (99, 12),
- Unit.SELJUK_LANCER,
- 1 + iHandicap,
- iGameTurn,
- 4,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (95, 8),
- (99, 12),
- Unit.TURCOMAN_HORSE_ARCHER,
- 1,
- iGameTurn,
- 4,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (95, 8),
- (99, 12),
- Unit.SELJUK_GUISARME,
- 1,
- iGameTurn,
- 4,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_SELJUKS"),
- )
-
- # Danishmends
- if DateTurn.i1077AD <= iGameTurn < DateTurn.i1147AD:
- if Civ.BYZANTIUM == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (93, 20),
- (99, 22),
- Unit.TURCOMAN_HORSE_ARCHER,
- 3 + iHandicap,
- iGameTurn,
- 5,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_DANISHMENDS"),
- )
- else:
- self.spawnUnits(
- Civ.BARBARIAN,
- (93, 20),
- (99, 22),
- Unit.TURCOMAN_HORSE_ARCHER,
- 2,
- iGameTurn,
- 5,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_DANISHMENDS"),
- )
-
- # Mongols
- if DateTurn.i1236AD <= iGameTurn < DateTurn.i1288AD:
- # Kiev
- if Civ.KIEV == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (93, 32),
- (99, 42),
- Unit.MONGOL_KESHIK,
- 5 + iHandicap,
- iGameTurn,
- 4,
- 0,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (94, 34),
- (99, 45),
- Unit.MONGOL_KESHIK,
- 4 + iHandicap,
- iGameTurn,
- 3,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
- )
- else:
- self.spawnUnits(
- Civ.BARBARIAN,
- (93, 32),
- (99, 42),
- Unit.MONGOL_KESHIK,
- 3,
- iGameTurn,
- 4,
- 0,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (94, 34),
- (99, 45),
- Unit.MONGOL_KESHIK,
- 2,
- iGameTurn,
- 3,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
- )
- # Hungary
- if Civ.HUNGARY == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (71, 38),
- (75, 40),
- Unit.MONGOL_KESHIK,
- 4 + iHandicap,
- iGameTurn,
- 4,
- 2,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (74, 35),
- (77, 37),
- Unit.MONGOL_KESHIK,
- 2,
- iGameTurn,
- 4,
- 2,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
- )
- else:
- self.spawnUnits(
- Civ.BARBARIAN,
- (71, 38),
- (75, 40),
- Unit.MONGOL_KESHIK,
- 2,
- iGameTurn,
- 4,
- 2,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (74, 35),
- (77, 37),
- Unit.MONGOL_KESHIK,
- 1,
- iGameTurn,
- 4,
- 2,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
- )
- # Poland
- if Civ.POLAND == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (73, 43),
- (78, 47),
- Unit.MONGOL_KESHIK,
- 5 + iHandicap,
- iGameTurn,
- 4,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
- )
- else:
- self.spawnUnits(
- Civ.BARBARIAN,
- (73, 43),
- (78, 47),
- Unit.MONGOL_KESHIK,
- 2,
- iGameTurn,
- 4,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
- )
- # Bulgaria
- if Civ.BULGARIA == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (79, 32),
- (82, 35),
- Unit.MONGOL_KESHIK,
- 3 + iHandicap,
- iGameTurn,
- 4,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
- )
- else:
- self.spawnUnits(
- Civ.BARBARIAN,
- (79, 32),
- (82, 35),
- Unit.MONGOL_KESHIK,
- 2,
- iGameTurn,
- 4,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
- )
- # Moscow area
- self.spawnUnits(
- Civ.BARBARIAN,
- (89, 46),
- (95, 54),
- Unit.MONGOL_KESHIK,
- 1,
- iGameTurn,
- 4,
- 0,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (91, 48),
- (97, 53),
- Unit.MONGOL_KESHIK,
- 2,
- iGameTurn,
- 6,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
- )
- # Middle East
- self.spawnUnits(
- Civ.BARBARIAN,
- (94, 20),
- (99, 26),
- Unit.MONGOL_KESHIK,
- 2,
- iGameTurn,
- 3,
- 2,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (92, 21),
- (97, 25),
- Unit.MONGOL_KESHIK,
- 2,
- iGameTurn,
- 6,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_MONGOLS"),
- )
-
- # Timurids, Tamerlane's conquests (aka Mongols, the return!)
- if (
- DateTurn.i1380AD <= iGameTurn <= DateTurn.i1431AD
- ): # Timur started his first western campaigns in 1380AD
- # Eastern Europe
- self.spawnUnits(
- Civ.BARBARIAN,
- (85, 47),
- (99, 57),
- Unit.MONGOL_KESHIK,
- 2,
- iGameTurn,
- 7,
- 0,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_TIMURIDS"),
- )
- # Anatolia
- if Civ.OTTOMAN == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (87, 17),
- (96, 24),
- Unit.MONGOL_KESHIK,
- 4 + iHandicap,
- iGameTurn,
- 4,
- 0,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_TIMURIDS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (94, 18),
- (99, 26),
- Unit.MONGOL_KESHIK,
- 6 + iHandicap,
- iGameTurn,
- 5,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_TIMURIDS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (89, 17),
- (97, 22),
- Unit.MONGOL_KESHIK,
- 3 + iHandicap,
- iGameTurn,
- 4,
- 2,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_TIMURIDS"),
- )
- else:
- self.spawnUnits(
- Civ.BARBARIAN,
- (87, 17),
- (96, 24),
- Unit.MONGOL_KESHIK,
- 2,
- iGameTurn,
- 4,
- 0,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_TIMURIDS"),
- )
- self.spawnUnits(
- Civ.BARBARIAN,
- (94, 18),
- (99, 26),
- Unit.MONGOL_KESHIK,
- 3,
- iGameTurn,
- 5,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_TIMURIDS"),
- )
- # Arabia
- if Civ.ARABIA == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (96, 9),
- (99, 15),
- Unit.MONGOL_KESHIK,
- 5 + iHandicap,
- iGameTurn,
- 4,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_TIMURIDS"),
- )
- else:
- self.spawnUnits(
- Civ.BARBARIAN,
- (96, 9),
- (99, 15),
- Unit.MONGOL_KESHIK,
- 2,
- iGameTurn,
- 4,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_TIMURIDS"),
- )
-
- # Nogais
- if DateTurn.i1500AD <= iGameTurn <= DateTurn.i1600AD:
- self.spawnUnits(
- Civ.BARBARIAN,
- (93, 38),
- (99, 54),
- Unit.HORSE_ARCHER,
- 3,
- iGameTurn,
- 7,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_NOGAIS"),
- )
- if Civ.MOSCOW == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (93, 38),
- (99, 54),
- Unit.HORSE_ARCHER,
- 2 + iHandicap,
- iGameTurn,
- 7,
- 1,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_NOGAIS"),
- )
-
- # Kalmyks
- elif DateTurn.i1600AD <= iGameTurn <= DateTurn.i1715AD:
- self.spawnUnits(
- Civ.BARBARIAN,
- (93, 38),
- (99, 54),
- Unit.MONGOL_KESHIK,
- 3,
- iGameTurn,
- 7,
- 0,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_KALMYKS"),
- )
- if Civ.MOSCOW == iHuman:
- self.spawnUnits(
- Civ.BARBARIAN,
- (93, 38),
- (99, 54),
- Unit.MONGOL_KESHIK,
- 3 + iHandicap,
- iGameTurn,
- 7,
- 0,
- forcedInvasion,
- UnitAITypes.UNITAI_ATTACK,
- text("TXT_KEY_BARBARIAN_NAMES_KALMYKS"),
- )
-
- # Independent/barb city spawns and minor nations:
- self.doIndependentCities(iGameTurn)
-
- if iGameTurn == 1:
- self.setupMinorNation()
- self.doMinorNations(iGameTurn)
-
- def doIndependentCities(self, iGameTurn):
- if iGameTurn in dIndependentCities.keys():
- for tCity in dIndependentCities[iGameTurn]:
- lVariations, iCiv, iPop, iUnit, iNumUnits, iReligion, iWorkers = tCity
- iChosenCity = -1
- iRand = percentage()
- for iCity in range(len(lVariations)):
- if iRand < lVariations[iCity][2]:
- iChosenCity = iCity
- break
- iRand -= lVariations[iCity][2]
- if iChosenCity == -1:
- continue
- tCoords, sName, iPos = lVariations[iChosenCity]
- self.foundCity(iCiv, tCoords, sName, iPop, iUnit, iNumUnits, iReligion, iWorkers)
-
- def foundCity(
- self, iCiv, tCoords, name, iPopulation, iUnitType, iNumUnits, iReligion, iWorkers
- ):
- if self.checkRegion(tCoords):
- gc.getPlayer(iCiv).found(tCoords[0], tCoords[1])
- city = gc.getMap().plot(tCoords[0], tCoords[1]).getPlotCity()
- city.setName(name, False)
- if iPopulation != 1:
- city.setPopulation(iPopulation)
- if iNumUnits > 0:
- make_units(iCiv, iUnitType, tCoords, iNumUnits)
- if iReligion > -1:
- city.setHasReligion(iReligion, True, True, False)
- if iWorkers > 0:
- make_units(iCiv, Unit.WORKER, tCoords, iWorkers)
-
- def checkRegion(self, tCoords):
- cityPlot = gc.getMap().plot(tCoords[0], tCoords[1])
-
- # checks if the plot already belongs to someone
- if cityPlot.isOwned():
- if cityPlot.getOwner() != Civ.BARBARIAN:
- return False
-
- # checks the surroundings for cities
- if plots().surrounding(tCoords).cities().entities():
- return False
- return True
-
- def spawnUnits(
- self,
- iCiv,
- tTopLeft,
- tBottomRight,
- iUnitType,
- iNumUnits,
- iTurn,
- iPeriod,
- iRest,
- function,
- unit_ai,
- unit_name=None,
- ):
- if (iTurn % iPeriod) == iRest:
- plotList = squareSearch(tTopLeft, tBottomRight, function, [])
- if plotList:
- tPlot = random_entry(plotList)
- if tPlot is not None:
- make_units(iCiv, iUnitType, tPlot, iNumUnits, unit_ai, unit_name)
-
- def spawnVikings(
- self,
- iCiv,
- tTopLeft,
- tBottomRight,
- iUnitType,
- iNumUnits,
- iTurn,
- iPeriod,
- iRest,
- function,
- unit_name=None,
- ):
- if (iTurn % iPeriod) == iRest:
- plotList = squareSearch(tTopLeft, tBottomRight, function, [])
- if plotList:
- tPlot = random_entry(plotList)
- if tPlot is not None:
- make_unit(iCiv, Unit.GALLEY, tPlot, UnitAITypes.UNITAI_ASSAULT_SEA, unit_name)
- make_units(
- iCiv, iUnitType, tPlot, iNumUnits, UnitAITypes.UNITAI_ATTACK, unit_name
- )
-
- def spawnPirate(
- self,
- iCiv,
- tTopLeft,
- tBottomRight,
- iShipType,
- iNumShips,
- iFighterType,
- iNumFighters,
- iTurn,
- iPeriod,
- iRest,
- function,
- unit_name=None,
- ):
- if (iTurn % iPeriod) == iRest:
- plotList = squareSearch(tTopLeft, tBottomRight, function, [])
- if plotList:
- tPlot = random_entry(plotList)
- if tPlot is not None:
- make_units(
- iCiv, iShipType, tPlot, iNumShips, UnitAITypes.UNITAI_ATTACK_SEA, unit_name
- )
- make_units(
- iCiv,
- iFighterType,
- tPlot,
- iNumFighters,
- UnitAITypes.UNITAI_ATTACK,
- unit_name,
- )
-
- def killNeighbours(self, tCoords):
- "Kills all units in the neigbbouring tiles of plot (as well as plot itself) so late starters have some space."
- for unit in plots().surrounding(tCoords).units().entities():
- unit.kill(False, Civ.BARBARIAN)
-
- def onImprovementDestroyed(self, iX, iY):
- # getHandicapType: Viceroy=0, Monarch=1, Emperor=2)
- iHandicap = gc.getGame().getHandicapType()
- iTurn = turn()
- if iTurn > DateTurn.i1500AD:
- iBarbUnit = Unit.MUSKETMAN
- elif iTurn > DateTurn.i1284AD:
- iBarbUnit = Unit.ARQUEBUSIER
- elif iTurn > DateTurn.i840AD:
- iBarbUnit = Unit.HORSE_ARCHER
- else:
- iBarbUnit = Unit.SPEARMAN
- self.spawnUnits(
- Civ.BARBARIAN,
- (iX - 1, iY - 1),
- (iX + 1, iY + 1),
- iBarbUnit,
- 1 + iHandicap,
- 1,
- 1,
- 0,
- outerInvasion,
- UnitAITypes.UNITAI_ATTACK,
- )
-
- def setupMinorNation(self):
- lNextMinorRevolt = self.getRevolDates()
-
- for lNation in lMinorNations:
- iNextRevolt = lNation[3][0]
- while iNextRevolt in lNextMinorRevolt:
- iNextRevolt = lNation[3][0] - 3 + rand(6)
- iNationIndex = lMinorNations.index(lNation)
- lNextMinorRevolt[iNationIndex] = iNextRevolt
-
- self.setRevolDates(lNextMinorRevolt)
-
- def doMinorNations(self, iGameTurn):
- lNextMinorRevolt = self.getRevolDates()
-
- if iGameTurn in lNextMinorRevolt:
- # iNation = lNextMinorRevolt.index( iGameTurn )
- lNation = lMinorNations[lNextMinorRevolt.index(iGameTurn)]
- lRevolts = lNation[3]
- for iRevoltDate in lRevolts:
- if (iRevoltDate - 3 <= iGameTurn) and (iRevoltDate + 3 >= iGameTurn):
- iRevoltIndex = lRevolts.index(iRevoltDate)
- break
- # loop over all the province tiles to find the cities revolting
- lPlayersOwning = [0] * civilizations().main().len()
- iProvince = lNation[0]
- for iI in range(gc.getNumProvinceTiles(iProvince)):
- iX = gc.getProvinceX(iProvince, iI)
- iY = gc.getProvinceY(iProvince, iI)
- if gc.getMap().plot(iX, iY).isCity():
- iOwner = gc.getMap().plot(iX, iY).getPlotCity().getOwner()
- if -1 < iOwner < Civ.POPE: # pope doesn't count here
- if (
- iOwner not in lNation[1]
- and gc.getPlayer(iOwner).getStateReligion() not in lNation[2]
- ):
- lPlayersOwning[iOwner] += 1
-
- for iPlayer in civilizations().main().ids():
- if lPlayersOwning[iPlayer] > 0:
- if human() == iPlayer:
- self.doRevoltHuman(iPlayer, iGameTurn, lNation, iRevoltIndex)
- else:
- self.doRevoltAI(iPlayer, iGameTurn, lNation, iRevoltIndex)
- # setup next revolt
- iRevoltIndex += 1
- if iRevoltIndex < len(lNation[3]):
- iNextRevolt = lNation[3][iRevoltIndex] - 3 + rand(6)
- while iNextRevolt in lNextMinorRevolt:
- iNextRevolt = lNation[3][iRevoltIndex] - 3 + rand(6)
- lNextMinorRevolt[lNextMinorRevolt.index(iGameTurn)] = iNextRevolt
- self.setRevolDates(lNextMinorRevolt)
-
- def doRevoltAI(self, iPlayer, iGameTurn, lNation, iRevoltIndex):
- cityList = cities().owner(iPlayer).province(lNation[0]).entities()
-
- iNumGarrison = 0
- for iI in range(len(cityList)):
- iNumGarrison += self.getGarrasonSize(cityList[iI])
-
- # base rebellion odds: maximum 45%
- # odds considering minor nation strength - between 10 and 40
- iSuppressOdds = -lNation[4][iRevoltIndex]
- # stability odds: maximum 20 + lNation[4][iRevoltIndex]
- pPlayer = gc.getPlayer(iPlayer)
- iSuppressOdds += 20 + max(-10, min(pPlayer.getStability() * 2, lNation[4][iRevoltIndex]))
- # passive bonus from city garrison: maximum 15
- iSuppressOdds += min((3 * iNumGarrison) / len(cityList), 15)
- # AI bonus
- iSuppressOdds += 10
-
- # AI always cracks revolt: maximum 35%
- # with a crackdown you will get a turn of unrest and some unhappiness even if it succeeds.
- iSuppressOdds = 10
- iSuppressOdds += min((5 * iNumGarrison) / len(cityList), 25)
-
- # time to roll the dice
- if percentage_chance(iSuppressOdds, strict=True, reverse=True):
- # revolt suppressed
- for iI in range(len(cityList)):
- pCity = cityList[iI]
- pCity.changeHurryAngerTimer(10)
- pCity.changeOccupationTimer(1)
- self.makeRebels(
- pCity, lNation[5][iRevoltIndex], lNation[6][iRevoltIndex], lNation[7][1]
- )
- else:
- # revolt succeeded
- iNewCiv = choice(INDEPENDENT_CIVS)
- for iI in range(len(cityList)):
- pCity = cityList[iI]
- tCity = (pCity.getX(), pCity.getY())
- cultureManager(tCity, 50, iNewCiv, iPlayer, False, True, True)
- flipUnitsInCitySecession(tCity, iNewCiv, iPlayer)
- self.setTempFlippingCity(tCity)
- flipCity(
- tCity, 0, 0, iNewCiv, [iPlayer]
- ) # by trade because by conquest may raze the city
- flipUnitsInCityAfter(self.getTempFlippingCity(), iNewCiv)
-
- def eventApply7627(self, popupReturn):
- iDecision = popupReturn.getButtonClicked()
- iNationIndex, iRevoltIndex = self.getNationRevoltIndex()
- lNation = lMinorNations[iNationIndex]
- iPlayer = human()
-
- cityList = cities().owner(iPlayer).province(lNation[0]).entities()
-
- iNumGarrison = 0
- iBribeGold = 0
- for iI in range(len(cityList)):
- iNumGarrison += self.getGarrasonSize(cityList[iI])
- iBribeGold += 10 * cityList[iI].getPopulation()
-
- # raw suppress score
- iSuppressOdds = -lNation[4][iRevoltIndex]
- pPlayer = gc.getPlayer(iPlayer)
- iSuppressOdds += 20 + max(-10, min(pPlayer.getStability() * 2, lNation[4][iRevoltIndex]))
- iSuppressOdds += min((3 * iNumGarrison) / len(cityList), 15)
-
- # 2nd or 4th choice
- if iDecision in [1, 3]:
- iSuppressOdds += 10 + min((5 * iNumGarrison) / len(cityList), 25)
-
- # 3rd or 4th choice
- if iDecision in [2, 3]:
- iGovernment = pPlayer.getCivics(0)
- if iGovernment == Civic.DESPOTISM:
- iBribeOdds = 15
- elif iGovernment == Civic.FEUDAL_MONARCHY:
- iBribeOdds = 25
- elif iGovernment == Civic.DIVINE_MONARCHY:
- iBribeOdds = 30
- elif iGovernment == Civic.LIMITE_DMONARCHY:
- iBribeOdds = 25
- elif iGovernment == Civic.MERCHANT_REPUBLIC:
- iBribeOdds = 20
- iGold = pPlayer.getGold()
- if iGold < iBribeGold:
- iBribeOdds = (iBribeOdds * iGold) / (iBribeGold)
- pPlayer.setGold(iGold - min(iGold, iBribeGold))
- iSuppressOdds += iBribeOdds
-
- if percentage_chance(iSuppressOdds, strict=True, reverse=True):
- # revolt suppressed
- for iI in range(len(cityList)):
- pCity = cityList[iI]
- message(
- iPlayer,
- text("TXT_KEY_MINOR_NATION_REVOLT_SUPRESSED", pCity.getName()),
- color=MessageData.BLUE,
- )
- # cracking the rebels results in unhappiness in the general population:
- if iDecision in [1, 3]:
- pCity.changeHurryAngerTimer(10)
- pCity.changeOccupationTimer(1)
- # bribing their lords away from their cause angers the rebel militia further:
- if iDecision in [2, 3]:
- self.makeRebels(
- pCity,
- lNation[5][iRevoltIndex],
- 1 + lNation[6][iRevoltIndex],
- lNation[7][1],
- )
- else:
- self.makeRebels(
- pCity, lNation[5][iRevoltIndex], lNation[6][iRevoltIndex], lNation[7][1]
- )
- else:
- # revolt succeeded
- iNewCiv = choice(INDEPENDENT_CIVS)
- for iI in range(len(cityList)):
- pCity = cityList[iI]
- tCity = (pCity.getX(), pCity.getY())
- sNationName = text(lNation[7][1])
- message(
- iPlayer,
- text("TXT_KEY_MINOR_NATION_REVOLT_SUCCEEDED", sNationName, pCity.getName()),
- color=MessageData.ORANGE,
- )
- cultureManager(tCity, 50, iNewCiv, iPlayer, False, True, True)
- flipUnitsInCitySecession(tCity, iNewCiv, iPlayer)
- self.setTempFlippingCity(tCity)
- flipCity(
- tCity, 0, 0, iNewCiv, [iPlayer]
- ) # by trade because by conquest may raze the city
- flipUnitsInCityAfter(self.getTempFlippingCity(), iNewCiv)
-
- # Absinthe: revolution choice effects:
- # base chance: stability bonus adjusted with the revolt strength + base chance + passive military presence - revolt strength
- # suppress with force: + base chance + military strength in the city. revolt +1 turn, unhappy +1 for 10 turns
- # bribe the lords: + financial chance: costs 10 gold per population, suppression depends on the government Divine Monarchy (30%), Feudal or Limited (25%), Merchant (20%), Decentral (15%)
- def doRevoltHuman(self, iPlayer, iGameTurn, lNation, iRevoltIndex):
- self.setNationRevoltIndex(lMinorNations.index(lNation), iRevoltIndex)
-
- cityList = cities().owner(iPlayer).province(lNation[0]).entities()
-
- iNumGarrison = 0
- iBribeGold = 0
- for iI in range(len(cityList)):
- iNumGarrison += self.getGarrasonSize(cityList[iI])
- iBribeGold += 10 * cityList[iI].getPopulation()
-
- # base rebellion odds: maximum 35%
- # odds considering minor nation strength - usually 10, 20, 30, or 40
- iRawOdds = -lNation[4][iRevoltIndex]
- # stability odds: maximum 20 + lNation[4][iRevoltIndex]
- pPlayer = gc.getPlayer(iPlayer)
- iRawOdds += 20 + max(-10, min(pPlayer.getStability() * 2, lNation[4][iRevoltIndex]))
- # passive bonus from city garrison: maximum 15
- iRawOdds += min((3 * iNumGarrison) / len(cityList), 15)
-
- # odds adjusted by a crackdown: maximum 35%
- # with a crackdown you will get a turn of unrest and some unhappiness even if it succeeds.
- iCrackOdds = 10
- iCrackOdds += min((5 * iNumGarrison) / len(cityList), 25)
-
- # odds adjusted by bribery: maximum 30%
- # bribe the lords, cost 10 gold per population
- # suppression depends on the government Divine Monarchy (30%), Feudal or Limited (25%), Merchant (20%), Decentral (15%)
- iGovernment = pPlayer.getCivics(0)
- if iGovernment == Civic.DESPOTISM:
- iBribeOdds = 15
- elif iGovernment == Civic.FEUDAL_MONARCHY:
- iBribeOdds = 25
- elif iGovernment == Civic.DIVINE_MONARCHY:
- iBribeOdds = 30
- elif iGovernment == Civic.LIMITE_DMONARCHY:
- iBribeOdds = 25
- elif iGovernment == Civic.MERCHANT_REPUBLIC:
- iBribeOdds = 20
- iGold = pPlayer.getGold()
- if iGold < iBribeGold:
- iBribeOdds = (iBribeOdds * iGold) / (iBribeGold)
- iGold = min(iGold, iBribeGold)
-
- # values should be between 0 and 100
- iAllOdds = max(0, iRawOdds + iBribeOdds + iCrackOdds)
- iBribeOdds = max(0, iRawOdds + iBribeOdds)
- iCrackOdds = max(0, iRawOdds + iCrackOdds)
- iRawOdds = max(0, iRawOdds)
-
- rebel_name = text(lNation[7][0])
- event_popup(
- 7627,
- text("TXT_KEY_MINOR_REBELLION_TITLE", rebel_name),
- text("TXT_KEY_MINOR_REBELLION_DESC", rebel_name),
- [
- text("TXT_KEY_MINOR_REBELLION_DO_NOTHING", iRawOdds),
- text("TXT_KEY_MINOR_REBELLION_CRACK", iCrackOdds),
- text("TXT_KEY_MINOR_REBELLION_BRIBE", iGold, iBribeGold, iBribeOdds),
- text("TXT_KEY_MINOR_REBELLION_ALL", iAllOdds),
- ],
- )
-
- def getGarrasonSize(self, pCity):
- pPlot = gc.getMap().plot(pCity.getX(), pCity.getY())
- iOwner = pPlot.getOwner()
- if iOwner < 0:
- return 0
- iNumUnits = pPlot.getNumUnits()
- iDefenders = 0
- for i in range(iNumUnits):
- if pPlot.getUnit(i).getOwner() == iOwner:
- iDefenders += 1
- return iDefenders
-
- def makeRebels(self, pCity, iUnit, iCount, szName):
- lAvailableFreeTiles = []
- lAvailableTiles = []
- for plot in (
- plots()
- .surrounding(pCity)
- .filter(lambda p: p.isHills() or p.isFlatlands())
- .filter(lambda p: not p.isCity())
- .entities()
- ):
- if plot.getNumUnits() == 0:
- lAvailableFreeTiles.append(location(plot))
- else:
- lAvailableTiles.append(location(plot))
-
- if lAvailableFreeTiles:
- tPlot = choice(lAvailableFreeTiles)
- elif lAvailableTiles:
- # if all tiles are taken, select one tile at random and kill all units there
- tPlot = choice(lAvailableTiles)
- pPlot = gc.getMap().plot(tPlot[0], tPlot[1])
- iN = pPlot.getNumUnits()
- for i in range(iN):
- pPlot.getUnit(0).kill(False, Civ.BARBARIAN)
- else:
- return
-
- unit_name = text(szName)
- make_units(Civ.BARBARIAN, iUnit, tPlot, iCount, UnitAITypes.UNITAI_ATTACK, unit_name)
diff --git a/Assets/Python/components/Companies.py b/Assets/Python/components/Companies.py
deleted file mode 100644
index defcb76aa..000000000
--- a/Assets/Python/components/Companies.py
+++ /dev/null
@@ -1,782 +0,0 @@
-# RFC Europe - Companies
-# Implemented by AbsintheRed, based on the wonderful idea of embryodead
-
-from CvPythonExtensions import *
-from Consts import MessageData
-from Core import (
- civilizations,
- get_scenario,
- message,
- human,
- player,
- text,
- turn,
- year,
- cities,
- companies,
-)
-from LocationsData import CITIES
-from PyUtils import rand
-import Crusades
-from operator import itemgetter
-from RFCUtils import getUniqueBuilding
-
-from MiscData import COMPANY_BUILDINGS
-from CoreTypes import (
- Building,
- City,
- Civ,
- Civic,
- Company,
- Province,
- Scenario,
- SpecialParameter,
- Religion,
- Technology,
- Wonder,
-)
-
-crus = Crusades.Crusades()
-gc = CyGlobalContext()
-
-
-class Companies:
- def setup(self):
-
- # update companies at the beginning of the 1200AD scenario:
- if get_scenario() == Scenario.i1200AD:
- for company in companies:
- if year(1200).between(company.birthdate, company.deathdate):
- self.addCompany(company.id, 2)
-
- def checkTurn(self, iGameTurn):
-
- # check if it's not too early
- iCompany = iGameTurn % companies.len()
- if iGameTurn < year(companies[iCompany].birthdate):
- return
-
- # check if it's not too late
- elif iGameTurn > year(companies[iCompany].deathdate) + rand(companies.len()):
- iMaxCompanies = 0
- # do not dissolve the Templars while Jerusalem is under Catholic control
- if iCompany == Company.TEMPLARS:
- plot = gc.getMap().plot(*CITIES[City.JERUSALEM])
- if plot.isCity():
- if (
- gc.getPlayer(plot.getPlotCity().getOwner()).getStateReligion()
- == Religion.CATHOLICISM
- ):
- iMaxCompanies = companies[iCompany].limit
-
- # set the company limit
- else:
- iMaxCompanies = companies[iCompany].limit
-
- # modified limit for Hospitallers and Teutons after the Crusades
- if iGameTurn > year(companies[Company.TEMPLARS].deathdate):
- if iCompany == Company.HOSPITALLERS and iGameTurn < year(
- companies[iCompany].deathdate
- ):
- iMaxCompanies -= 1
- elif iCompany == Company.TEUTONS and iGameTurn < year(companies[iCompany].deathdate):
- iMaxCompanies += 2
- # increased limit for Hansa after their first general Diet in 1356
- if iCompany == Company.HANSA:
- if year(1356) < iGameTurn < year(companies[iCompany].deathdate):
- iMaxCompanies += 3
-
- # Templars are Teutons are gone after the Protestant reformation
- if iCompany in [Company.TEMPLARS, Company.TEUTONS]:
- if gc.getGame().isReligionFounded(Religion.PROTESTANTISM):
- iMaxCompanies = 0
- # Order of Calatrava is only active if Cordoba or Morocco is alive
- # TODO: Only if Cordoba is alive, or Morocco has some territories in Europe?
- if iCompany == Company.CALATRAVA:
- if not (gc.getPlayer(Civ.CORDOBA).isAlive() or gc.getPlayer(Civ.MOROCCO).isAlive()):
- iMaxCompanies = 0
- # Order of the Dragon is only active if the Ottomans are alive
- if iCompany == Company.DRAGON:
- if not gc.getPlayer(Civ.OTTOMAN).isAlive():
- iMaxCompanies = 0
-
- # loop through all cities, check the company value for each and add the good ones to a list of tuples (city, value)
- cityValueList = []
- for iPlayer in civilizations().majors().ids():
- for city in cities().owner(iPlayer).entities():
- iValue = self.getCityValue(city, iCompany)
- if iValue > 0:
- sCityName = city.getName()
- bPresent = False
- if city.isHasCorporation(iCompany):
- bPresent = True
- cityValueList.append((city, iValue * 10 + rand(10)))
- elif city.isHasCorporation(
- iCompany
- ): # remove company from cities with a negative value
- city.setHasCorporation(iCompany, False, True, True)
- city.setHasRealBuilding(COMPANY_BUILDINGS[iCompany], False)
- sCityName = city.getName()
- # interface message for the human player
- self.announceHuman(iCompany, city, True)
-
- # sort cities from highest to lowest value
- cityValueList.sort(key=itemgetter(1), reverse=True)
-
- # count the number of companies
- iCompanyCount = 0
- for civ in civilizations().majors():
- if civ.player.isAlive():
- iCompanyCount += civ.player.countCorporations(iCompany)
-
- # spread the company
- for i in range(len(cityValueList)):
- city, iValue = cityValueList[i]
- if city.isHasCorporation(iCompany):
- continue
- if (
- i >= iMaxCompanies
- ): # the goal is to have the company in the first iMaxCompanies number of cities
- break
- city.setHasCorporation(iCompany, True, True, True)
- city.setHasRealBuilding(COMPANY_BUILDINGS[iCompany], True)
- iCompanyCount += 1
- sCityName = city.getName()
- # interface message for the human player
- self.announceHuman(iCompany, city)
- # spread the religion if it wasn't present before
- if iCompany in [
- Company.HOSPITALLERS,
- Company.TEMPLARS,
- Company.TEUTONS,
- Company.CALATRAVA,
- ]:
- if not city.isHasReligion(Religion.CATHOLICISM):
- city.setHasReligion(Religion.CATHOLICISM, True, True, False)
- # one change at a time, only add the highest ranked city (which didn't have the company before)
- break
-
- # if the limit was exceeded, remove company from it's worst city
- if iCompanyCount > iMaxCompanies:
- for (city, iValue) in reversed(cityValueList): # loop backwards in the ordered list
- if city.isHasCorporation(iCompany):
- city.setHasCorporation(iCompany, False, True, True)
- city.setHasRealBuilding(COMPANY_BUILDINGS[iCompany], False)
- sCityName = city.getName()
- # interface message for the human player
- self.announceHuman(iCompany, city, True)
- # one change at a time, only add the lowest ranked city
- break
-
- def onPlayerChangeStateReligion(self, argsList):
- iPlayer, iNewReligion, iOldReligion = argsList
-
- for city in cities().owner(iPlayer).entities():
- for iCompany in companies.ids():
- if city.isHasCorporation(iCompany):
- if self.getCityValue(city, iCompany) < 0:
- city.setHasCorporation(iCompany, False, True, True)
- city.setHasRealBuilding(COMPANY_BUILDINGS[iCompany], False)
- sCityName = city.getName()
- # interface message for the human player
- self.announceHuman(iCompany, city, True)
-
- def onBuildingBuilt(self, iPlayer, iBuilding):
-
- # Galata Tower ownership
- pPlayer = gc.getPlayer(iPlayer)
- if iBuilding == Wonder.GALATA_TOWER:
- pPlayer.setPicklefreeParameter(SpecialParameter.HAS_GALATA_TOWER, 1)
-
- def onCityAcquired(self, iOldOwner, iNewOwner, city):
-
- for iCompany in companies.ids():
- if city.isHasCorporation(iCompany):
- if self.getCityValue(city, iCompany) < 0:
- city.setHasCorporation(iCompany, False, True, True)
- city.setHasRealBuilding(COMPANY_BUILDINGS[iCompany], False)
- sCityName = city.getName()
- # interface message for the human player
- self.announceHuman(iCompany, city, True)
-
- # Galata Tower ownership
- pOldOwner = gc.getPlayer(iOldOwner)
- pNewOwner = gc.getPlayer(iNewOwner)
- if city.isHasBuilding(Wonder.GALATA_TOWER):
- pNewOwner.setPicklefreeParameter(SpecialParameter.HAS_GALATA_TOWER, 1)
- pOldOwner.setPicklefreeParameter(SpecialParameter.HAS_GALATA_TOWER, 0)
-
- def onCityRazed(self, iOldOwner, iPlayer, city):
-
- # Galata Tower ownership
- pOldOwner = gc.getPlayer(iOldOwner)
- pPlayer = gc.getPlayer(iPlayer)
- if city.isHasBuilding(Wonder.GALATA_TOWER):
- pPlayer.setPicklefreeParameter(SpecialParameter.HAS_GALATA_TOWER, 0)
- pOldOwner.setPicklefreeParameter(SpecialParameter.HAS_GALATA_TOWER, 0)
-
- def announceHuman(self, iCompany, city, bRemove=False):
- iHuman = human()
- iHumanTeam = gc.getPlayer(iHuman).getTeam()
- if not player().isExisting() or not city.isRevealed(iHumanTeam, False):
- return
-
- sCityName = city.getName()
- sCompanyName = gc.getCorporationInfo(iCompany).getDescription()
-
- if bRemove:
- sText = text("TXT_KEY_MISC_CORPORATION_REMOVED", sCompanyName, sCityName)
- else:
- sText = text("TXT_KEY_MISC_CORPORATION_SPREAD", sCompanyName, sCityName)
- message(
- iHuman,
- sText,
- sound=gc.getCorporationInfo(iCompany).getSound(),
- event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
- button=gc.getCorporationInfo(iCompany).getButton(),
- color=MessageData.WHITE,
- location=city,
- )
-
- def getCityValue(self, city, iCompany):
-
- if city is None:
- return -1
- elif city.isNone():
- return -1
-
- iValue = 0
-
- owner = gc.getPlayer(city.getOwner())
- iOwner = owner.getID()
- ownerTeam = gc.getTeam(owner.getTeam())
-
- # spread the Teutons to Teutonic Order cities and don't spread if the owner civ is at war with the Teutons
- if iCompany == Company.TEUTONS:
- if iOwner == Civ.PRUSSIA:
- iValue += 5
- elif ownerTeam.isAtWar(Civ.PRUSSIA):
- return -1
-
- # Genoese UP
- if iOwner == Civ.GENOA:
- iValue += 1
- # extra bonus for banking companies
- if iCompany in [Company.MEDICI, Company.AUGSBURG, Company.ST_GEORGE]:
- iValue += 1
-
- # state religion requirements
- iStateReligion = owner.getStateReligion()
- if iCompany in [Company.HOSPITALLERS, Company.TEMPLARS, Company.TEUTONS]:
- if iStateReligion == Religion.CATHOLICISM:
- iValue += 3
- elif iStateReligion in [Religion.PROTESTANTISM, Religion.ORTHODOXY]:
- iValue -= 2
- else:
- return -1
- elif iCompany == Company.DRAGON:
- if iStateReligion == Religion.CATHOLICISM:
- iValue += 2
- elif iStateReligion == Religion.ORTHODOXY:
- iValue += 1
- elif iStateReligion == Religion.ISLAM:
- return -1
- elif iCompany == Company.CALATRAVA:
- if iStateReligion == Religion.CATHOLICISM:
- iValue += 2
- else:
- return -1
- else:
- if iStateReligion == Religion.ISLAM:
- return -1
-
- # geographical requirements
- iProvince = city.getProvince()
- if len(companies[iCompany].region) and iProvince not in companies[iCompany].region:
- return -1
- if iCompany == Company.MEDICI:
- if iProvince == Province.TUSCANY:
- iValue += 4
- elif iCompany == Company.AUGSBURG:
- if iProvince == Province.BAVARIA:
- iValue += 3
- elif iProvince == Province.SWABIA:
- iValue += 2
- elif iCompany == Company.ST_GEORGE:
- if iProvince == Province.LIGURIA:
- iValue += 3
- elif iCompany == Company.HANSA:
- if iProvince == Province.HOLSTEIN:
- iValue += 5
- if iProvince in [Province.BRANDENBURG, Province.SAXONY]:
- iValue += 2
-
- # geographical requirement changes after the Crusades
- iGameTurn = turn()
- if iGameTurn < year(companies[Company.TEMPLARS].deathdate):
- if iCompany in [
- Company.HOSPITALLERS,
- Company.TEMPLARS,
- Company.TEUTONS,
- ]:
- if iStateReligion == Religion.CATHOLICISM:
- if iProvince in [
- Province.ANTIOCHIA,
- Province.LEBANON,
- Province.JERUSALEM,
- ]:
- iValue += 5
- elif iProvince in [Province.CYPRUS, Province.EGYPT]:
- iValue += 3
- else:
- if iCompany == Company.HOSPITALLERS:
- if iProvince in [Province.RHODES, Province.MALTA]:
- iValue += 4
- elif iCompany == Company.TEUTONS:
- if iProvince == Province.TRANSYLVANIA:
- iValue += 2
-
- # bonus for civs whom actively participate (with units) in the actual Crusade:
- if iOwner < civilizations().majors().len():
- if crus.getNumUnitsSent(iOwner) > 0:
- if iCompany in [
- Company.HOSPITALLERS,
- Company.TEMPLARS,
- Company.TEUTONS,
- ]:
- iValue += 2
-
- # additional bonus for the city of Jerusalem
- if (city.getX(), city.getY()) == CITIES[City.JERUSALEM]:
- if iCompany in [
- Company.HOSPITALLERS,
- Company.TEMPLARS,
- Company.TEUTONS,
- ]:
- iValue += 3
-
- # coastal and riverside check
- if iCompany == Company.HANSA:
- if not city.isCoastal(20): # water body with at least 20 tiles
- if not city.plot().isRiverSide():
- return -1
- elif iCompany == Company.HOSPITALLERS:
- if city.isCoastal(20):
- iValue += 2
-
- # bonus for religions in the city
- if iCompany in [
- Company.HANSA,
- Company.MEDICI,
- Company.AUGSBURG,
- Company.ST_GEORGE,
- ]:
- if city.isHasReligion(
- Religion.JUDAISM
- ): # not necessarily historic, but has great gameplay synergies
- iValue += 1
- elif iCompany in [
- Company.HOSPITALLERS,
- Company.TEMPLARS,
- Company.TEUTONS,
- Company.CALATRAVA,
- ]:
- # they have a harder time to choose a city without Catholicism, but they spread the religion there
- if not city.isHasReligion(Religion.CATHOLICISM):
- iValue -= 1
- if city.isHasReligion(Religion.ISLAM):
- iValue -= 1
- elif iCompany == Company.DRAGON:
- if city.isHasReligion(Religion.CATHOLICISM) or city.isHasReligion(Religion.ORTHODOXY):
- iValue += 1
- if city.isHasReligion(Religion.ISLAM):
- iValue -= 1
-
- # faith points of the population
- if iCompany in [
- Company.HOSPITALLERS,
- Company.TEMPLARS,
- Company.TEUTONS,
- Company.CALATRAVA,
- ]:
- if owner.getFaith() >= 50:
- iValue += 3
- elif owner.getFaith() >= 30:
- iValue += 2
- elif owner.getFaith() >= 15:
- iValue += 1
-
- # city size
- if iCompany in [
- Company.HANSA,
- Company.DRAGON,
- Company.MEDICI,
- Company.AUGSBURG,
- Company.ST_GEORGE,
- ]:
- if city.getPopulation() > 9:
- iValue += 3
- elif city.getPopulation() > 6:
- iValue += 2
- elif city.getPopulation() > 3:
- iValue += 1
-
- # Galata Tower bonus: 2 for all cities, additional 2 for the wonder's city
- if owner.getPicklefreeParameter(SpecialParameter.HAS_GALATA_TOWER) == 1:
- iValue += 2
- if city.isHasBuilding(Wonder.GALATA_TOWER):
- iValue += 2
-
- # various building bonuses, trade route bonus
- iBuildCounter = 0 # building bonus counter: we don't want buildings to be the deciding factor in company spread
- if iCompany in [Company.HOSPITALLERS, Company.TEMPLARS, Company.TEUTONS]:
- iMaxPossible = 11 # building bonus counter: we don't want buildings to be the deciding factor in company spread
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.WALLS)) > 0:
- iBuildCounter += 1
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.CASTLE)) > 0:
- iBuildCounter += 2
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.BARRACKS)) > 0:
- iBuildCounter += 1
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.STABLE)) > 0:
- iBuildCounter += 1
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.ARCHERY_RANGE)) > 0:
- iBuildCounter += 1
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.FORGE)) > 0:
- iBuildCounter += 1
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.CATHOLIC_TEMPLE)) > 0:
- iBuildCounter += 1
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.CATHOLIC_MONASTERY)) > 0:
- iBuildCounter += 2
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.GUILD_HALL)) > 0:
- iBuildCounter += 1
- iValue += (4 * iBuildCounter) / iMaxPossible # maximum is 4, with all buildings built
- # wonders should be handled separately
- if city.getNumRealBuilding(Wonder.KRAK_DES_CHEVALIERS) > 0:
- if iCompany == Company.HOSPITALLERS:
- iValue += 5
- else:
- iValue += 2
- if city.getNumRealBuilding(Wonder.DOME_ROCK) > 0:
- if iCompany == Company.TEMPLARS:
- iValue += 5
- else:
- iValue += 2
- elif iCompany == Company.CALATRAVA:
- iMaxPossible = 11 # building bonus counter: we don't want buildings to be the deciding factor in company spread
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.WALLS)) > 0:
- iBuildCounter += 1
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.CASTLE)) > 0:
- iBuildCounter += 2
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.BARRACKS)) > 0:
- iBuildCounter += 1
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.STABLE)) > 0:
- iBuildCounter += 1
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.ARCHERY_RANGE)) > 0:
- iBuildCounter += 1
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.FORGE)) > 0:
- iBuildCounter += 1
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.CATHOLIC_TEMPLE)) > 0:
- iBuildCounter += 1
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.CATHOLIC_MONASTERY)) > 0:
- iBuildCounter += 2
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.STAR_FORT)) > 0:
- iBuildCounter += 1
- iValue += (5 * iBuildCounter) / iMaxPossible # maximum is 5, with all buildings built
- elif iCompany == Company.DRAGON:
- iMaxPossible = 9 # building bonus counter: we don't want buildings to be the deciding factor in company spread
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.WALLS)) > 0:
- iBuildCounter += 1
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.CASTLE)) > 0:
- iBuildCounter += 2
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.BARRACKS)) > 0:
- iBuildCounter += 1
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.STABLE)) > 0:
- iBuildCounter += 1
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.ARCHERY_RANGE)) > 0:
- iBuildCounter += 1
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.FORGE)) > 0:
- iBuildCounter += 1
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.STAR_FORT)) > 0:
- iBuildCounter += 2
- iValue += (5 * iBuildCounter) / iMaxPossible # maximum is 5, with all buildings built
- elif iCompany in [Company.MEDICI, Company.AUGSBURG, Company.ST_GEORGE]:
- iMaxPossible = 11 # building bonus counter: we don't want buildings to be the deciding factor in company spread
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.MARKET)) > 0:
- iBuildCounter += 1
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.BANK)) > 0:
- iBuildCounter += 3
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.JEWELER)) > 0:
- iBuildCounter += 2
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.GUILD_HALL)) > 0:
- iBuildCounter += 1
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.LUXURY_STORE)) > 0:
- iBuildCounter += 2
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.COURTHOUSE)) > 0:
- iBuildCounter += 2
- iValue += (5 * iBuildCounter) / iMaxPossible # maximum is 5, with all buildings built
- # wonders should be handled separately
- if city.getNumRealBuilding(Building.PALACE) > 0:
- iValue += 1
- if city.getNumRealBuilding(Building.SUMMER_PALACE) > 0:
- iValue += 1
- # bonus from trade routes
- iValue += max(0, city.getTradeRoutes() - 1)
- elif iCompany == Company.HANSA:
- iMaxPossible = 16 # building bonus counter: we don't want buildings to be the deciding factor in company spread
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.HARBOR)) > 0:
- iBuildCounter += 2
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.LIGHTHOUSE)) > 0:
- iBuildCounter += 2
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.WHARF)) > 0:
- iBuildCounter += 2
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.CUSTOM_HOUSE)) > 0:
- iBuildCounter += 1
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.MARKET)) > 0:
- iBuildCounter += 2
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.BREWERY)) > 0:
- iBuildCounter += 1
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.WEAVER)) > 0:
- iBuildCounter += 1
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.GUILD_HALL)) > 0:
- iBuildCounter += 1
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.WAREHOUSE)) > 0:
- iBuildCounter += 2
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.TANNERY)) > 0:
- iBuildCounter += 1
- if city.getNumRealBuilding(getUniqueBuilding(iOwner, Building.TEXTILE_MILL)) > 0:
- iBuildCounter += 1
- iValue += (6 * iBuildCounter) / iMaxPossible # maximum is 6, with all buildings built
- # bonus from trade routes
- iValue += city.getTradeRoutes()
-
- # civic bonuses
- if owner.getCivics(0) == Civic.MERCHANT_REPUBLIC:
- if iCompany in [
- Company.MEDICI,
- Company.ST_GEORGE,
- Company.HOSPITALLERS,
- ]:
- iValue += 1
- elif iCompany == Company.HANSA:
- iValue += 2
- if owner.getCivics(1) == Civic.FEUDAL_LAW:
- if iCompany in [
- Company.HOSPITALLERS,
- Company.TEMPLARS,
- Company.TEUTONS,
- Company.DRAGON,
- Company.CALATRAVA,
- ]:
- iValue += 2
- elif owner.getCivics(1) == Civic.RELIGIOUS_LAW:
- if iCompany in [
- Company.HOSPITALLERS,
- Company.TEMPLARS,
- Company.TEUTONS,
- Company.CALATRAVA,
- ]:
- iValue += 1
- if owner.getCivics(2) == Civic.APPRENTICESHIP:
- if iCompany == Company.HANSA:
- iValue += 1
- if owner.getCivics(3) == Civic.TRADE_ECONOMY:
- if iCompany in [Company.MEDICI, Company.AUGSBURG, Company.ST_GEORGE]:
- iValue += 1
- elif iCompany == Company.HANSA:
- iValue += 2
- elif owner.getCivics(3) == Civic.GUILDS:
- if iCompany in [
- Company.HOSPITALLERS,
- Company.TEMPLARS,
- Company.TEUTONS,
- Company.MEDICI,
- Company.AUGSBURG,
- Company.ST_GEORGE,
- Company.DRAGON,
- Company.CALATRAVA,
- ]:
- iValue += 1
- elif iCompany == Company.HANSA:
- iValue += 2
- elif owner.getCivics(3) == Civic.MERCANTILISM:
- if iCompany == Company.HANSA:
- return -1
- elif iCompany in [
- Company.MEDICI,
- Company.AUGSBURG,
- Company.ST_GEORGE,
- ]:
- iValue -= 2
- if owner.getCivics(4) == Civic.THEOCRACY:
- if iCompany in [Company.HOSPITALLERS, Company.TEMPLARS]:
- iValue += 1
- elif iCompany == Company.TEUTONS:
- iValue += 2
- elif owner.getCivics(4) == Civic.FREE_RELIGION:
- if iCompany in [
- Company.HOSPITALLERS,
- Company.TEMPLARS,
- Company.TEUTONS,
- Company.DRAGON,
- ]:
- iValue -= 1
- elif iCompany == Company.CALATRAVA:
- iValue -= 2
- if owner.getCivics(5) == Civic.OCCUPATION:
- if iCompany in [
- Company.HOSPITALLERS,
- Company.TEMPLARS,
- iCompany,
- iCompany == Company.CALATRAVA,
- ]:
- iValue += 1
-
- # bonus for techs
- if iCompany in [
- Company.HOSPITALLERS,
- Company.TEMPLARS,
- Company.TEUTONS,
- Company.DRAGON,
- Company.CALATRAVA,
- ]:
- for iTech in [
- Technology.CHIVALRY,
- Technology.PLATE_ARMOR,
- Technology.GUILDS,
- Technology.MILITARY_TRADITION,
- ]:
- if ownerTeam.isHasTech(iTech):
- iValue += 1
- elif iCompany == Company.HANSA:
- for iTech in [
- Technology.GUILDS,
- Technology.CLOCKMAKING,
- Technology.OPTICS,
- Technology.SHIP_BUILDING,
- ]:
- if ownerTeam.isHasTech(iTech):
- iValue += 1
- elif iCompany in [Company.MEDICI, Company.ST_GEORGE]:
- for iTech in [
- Technology.BANKING,
- Technology.PAPER,
- Technology.CLOCKMAKING,
- Technology.OPTICS,
- Technology.SHIP_BUILDING,
- ]:
- if ownerTeam.isHasTech(iTech):
- iValue += 1
- elif iCompany == Company.AUGSBURG:
- for iTech in [
- Technology.BANKING,
- Technology.PAPER,
- Technology.CHEMISTRY,
- ]:
- if ownerTeam.isHasTech(iTech):
- iValue += 1
-
- # resources
- iTempValue = 0
- bFound = False
- for i in range(5):
- iBonus = gc.getCorporationInfo(iCompany).getPrereqBonus(i)
- if iBonus > -1:
- if city.getNumBonuses(iBonus) > 0:
- bFound = True
- if iCompany in [
- Company.HOSPITALLERS,
- Company.TEMPLARS,
- Company.TEUTONS,
- Company.DRAGON,
- Company.CALATRAVA,
- ]:
- iTempValue += (
- city.getNumBonuses(iBonus) + 2
- ) # 3 for the first bonus, 1 for the rest of the same type
- else:
- iTempValue += (
- city.getNumBonuses(iBonus) + 1
- ) * 2 # 4 for the first bonus, 2 for the rest
- if (
- iCompany
- in [
- Company.HANSA,
- Company.MEDICI,
- Company.AUGSBURG,
- Company.ST_GEORGE,
- ]
- and not bFound
- ):
- return -1
- # we don't want the bonus to get too big, and dominate the selection values
- iValue += iTempValue / 4
-
- # bonus for resources in the fat cross of a city?
-
- # competition
- if iCompany == Company.HOSPITALLERS:
- if city.isHasCorporation(Company.TEMPLARS):
- iValue *= 2
- iValue /= 3
- if city.isHasCorporation(Company.TEUTONS):
- iValue *= 2
- iValue /= 3
- elif iCompany == Company.TEMPLARS:
- if city.isHasCorporation(Company.HOSPITALLERS):
- iValue *= 2
- iValue /= 3
- if city.isHasCorporation(Company.TEUTONS):
- iValue *= 2
- iValue /= 3
- elif iCompany == Company.TEUTONS:
- if city.isHasCorporation(Company.TEMPLARS):
- iValue *= 2
- iValue /= 3
- if city.isHasCorporation(Company.HOSPITALLERS):
- iValue *= 2
- iValue /= 3
- elif iCompany == Company.MEDICI:
- if city.isHasCorporation(Company.ST_GEORGE) or city.isHasCorporation(Company.AUGSBURG):
- iValue /= 2
- elif iCompany == Company.ST_GEORGE:
- if city.isHasCorporation(Company.MEDICI) or city.isHasCorporation(Company.AUGSBURG):
- iValue /= 2
- elif iCompany == Company.AUGSBURG:
- if city.isHasCorporation(Company.MEDICI) or city.isHasCorporation(Company.ST_GEORGE):
- iValue /= 2
-
- # threshold
- if iValue < 3:
- return -1
-
- # spread it out
- iCompOwned = owner.countCorporations(iCompany)
- if city.isHasCorporation(iCompany):
- iValue -= iCompOwned # -1 per city if the company is already present here (smaller penalty in the value list)
- else:
- iValue -= (
- 5 * iCompOwned / 2
- ) # -2,5 per city if it's a possible new spread (bigger penalty in the value list)
-
- return iValue
-
- def addCompany(self, iCompany, iNumber):
-
- # adds the company to the best iNumber cities
- cityValueList = []
- iCompaniesAdded = 0
- for iPlayer in civilizations().majors().ids():
- for city in cities().owner(iPlayer).entities():
- iValue = self.getCityValue(city, iCompany)
- if iValue > 0:
- cityValueList.append((city, iValue * 10 + rand(10)))
- # sort cities from highest to lowest value
- cityValueList.sort(key=itemgetter(1), reverse=True)
- # spread the company
- for (city, _) in cityValueList:
- if not city.isHasCorporation(iCompany):
- city.setHasCorporation(iCompany, True, True, True)
- city.setHasRealBuilding(COMPANY_BUILDINGS[iCompany], True)
- iCompaniesAdded += 1
- if iCompaniesAdded == iNumber:
- break
diff --git a/Assets/Python/components/Crusades.py b/Assets/Python/components/Crusades.py
deleted file mode 100644
index c291633b8..000000000
--- a/Assets/Python/components/Crusades.py
+++ /dev/null
@@ -1,1869 +0,0 @@
-from CvPythonExtensions import *
-from Consts import MessageData
-from Core import (
- civilization,
- civilizations,
- event_popup,
- human,
- location,
- make_crusade_unit,
- make_crusade_units,
- player,
- team,
- teamtype,
- message,
- text,
- turn,
- year,
- cities,
- plots,
- units,
-)
-from PyUtils import percentage, percentage_chance, rand, choice
-from ProvinceMapData import PROVINCES_MAP
-import CityNameManager
-from RFCUtils import convertPlotCulture, getMaster, getUniqueUnit, isAVassal
-from StoredData import data
-import random
-
-from CoreTypes import City, Civ, Religion, Promotion, Technology, Unit, Province
-from MiscData import NUM_CRUSADES
-from LocationsData import CITIES
-
-gc = CyGlobalContext()
-cnm = CityNameManager.CityNameManager()
-
-
-# Can call defensive crusade to aid Catholics, if at war with Non-Catholic and Non-Orthodox player, who isn't vassal of Catholic or Orthodox player and has at least one city in the provinces listed here
-tDefensiveCrusadeMap = [
- [], # Byzantium
- [
- Province.ILE_DE_FRANCE,
- Province.AQUITAINE,
- Province.ORLEANS,
- Province.CHAMPAGNE,
- Province.BRETAGNE,
- Province.NORMANDY,
- Province.PROVENCE,
- Province.FLANDERS,
- Province.BURGUNDY,
- Province.PICARDY,
- ], # France
- [], # Arabia
- [], # Bulgaria
- [
- Province.LEON,
- Province.GALICIA,
- Province.LUSITANIA,
- Province.ARAGON,
- Province.CATALONIA,
- Province.NAVARRE,
- Province.CASTILE,
- Province.ANDALUSIA,
- Province.LA_MANCHA,
- Province.VALENCIA,
- ], # Cordoba (for consistency)
- [
- Province.VERONA,
- Province.TUSCANY,
- Province.ARBERIA,
- Province.DALMATIA,
- ], # Venecia
- [
- Province.FLANDERS,
- Province.PROVENCE,
- Province.BURGUNDY,
- Province.CHAMPAGNE,
- Province.LORRAINE,
- Province.PICARDY,
- ], # Burgundy
- [
- Province.LORRAINE,
- Province.SWABIA,
- Province.BAVARIA,
- Province.SAXONY,
- Province.FRANCONIA,
- Province.FLANDERS,
- Province.BRANDENBURG,
- Province.HOLSTEIN,
- Province.BOHEMIA,
- ], # Germany
- [], # Novgorod
- [], # Norway
- [], # Kiev
- [
- Province.HUNGARY,
- Province.TRANSYLVANIA,
- Province.UPPER_HUNGARY,
- Province.WALLACHIA,
- Province.SLAVONIA,
- Province.PANNONIA,
- Province.AUSTRIA,
- Province.CARINTHIA,
- Province.SERBIA,
- Province.MOESIA,
- Province.BANAT,
- Province.BOSNIA,
- Province.DALMATIA,
- ], # Hungary
- [
- Province.LEON,
- Province.GALICIA,
- Province.LUSITANIA,
- Province.ARAGON,
- Province.CATALONIA,
- Province.NAVARRE,
- Province.CASTILE,
- Province.ANDALUSIA,
- Province.LA_MANCHA,
- Province.VALENCIA,
- ], # Spain
- [Province.ESTONIA], # Denmark
- [], # Scotland
- [
- Province.GREATER_POLAND,
- Province.LESSER_POLAND,
- Province.SILESIA,
- Province.POMERANIA,
- Province.MASOVIA,
- Province.GALICJA,
- Province.BREST,
- ], # Poland
- [
- Province.LIGURIA,
- Province.LOMBARDY,
- Province.CORSICA,
- Province.SARDINIA,
- Province.TUSCANY,
- ], # Genoa
- [], # Morocco
- [], # England
- [
- Province.LEON,
- Province.GALICIA,
- Province.LUSITANIA,
- Province.ARAGON,
- Province.CATALONIA,
- Province.NAVARRE,
- Province.CASTILE,
- Province.ANDALUSIA,
- Province.LA_MANCHA,
- Province.VALENCIA,
- ], # Portugal
- [
- Province.VALENCIA,
- Province.BALEARS,
- Province.SICILY,
- Province.APULIA,
- Province.CALABRIA,
- ], # Aragon
- [Province.OSTERLAND], # Sweden
- [
- Province.LIVONIA,
- Province.ESTONIA,
- Province.LITHUANIA,
- Province.PRUSSIA,
- ], # Prussia
- [], # Lithuania
- [
- Province.AUSTRIA,
- Province.CARINTHIA,
- Province.BAVARIA,
- Province.BOHEMIA,
- Province.MORAVIA,
- Province.SILESIA,
- ], # Austria
- [], # Turkey
- [], # Moscow
- [], # Dutch
- [], # Papal States
-]
-
-
-class Crusades:
-
- ###############
- ### Popups 3Miro: taken from RFC Congress ###
- #############
-
- def getCrusadeInit(self, iCrusade):
- return data.lCrusadeInit[iCrusade]
-
- def setCrusadeInit(self, iCrusade, iNewCode):
- # codes are: -2, no crusade yet
- # -1 crusade is active but waiting to start (Holy City is Christian and/or another Crusade in progress)
- # 0 or more, the turn when it was initialized
- data.lCrusadeInit[iCrusade] = iNewCode
-
- def addSelectedUnit(self, iUnitPlace):
- data.lSelectedUnits[iUnitPlace] += 1
-
- def setSelectedUnit(self, iUnitPlace, iNewNumber):
- data.lSelectedUnits[iUnitPlace] = iNewNumber
-
- def getSelectedUnit(self, iUnitPlace):
- return data.lSelectedUnits[iUnitPlace]
-
- def changeNumUnitsSent(self, iPlayer, iChange):
- data.lNumUnitsSent[iPlayer] += iChange
-
- def setNumUnitsSent(self, iPlayer, iNewNumber):
- data.lNumUnitsSent[iPlayer] = iNewNumber
-
- def getNumUnitsSent(self, iPlayer):
- return data.lNumUnitsSent[iPlayer]
-
- def getActiveCrusade(self, iGameTurn):
- for i in range(NUM_CRUSADES):
- iInit = data.lCrusadeInit[i]
- if iInit > -1 and iInit + 9 > iGameTurn:
- return i
- return -1
-
- def getParticipate(self):
- return data.bParticipate
-
- def setParticipate(self, bVal):
- data.bParticipate = bVal
-
- def getVotingPower(self, iCiv):
- return data.lVotingPower[iCiv]
-
- def setVotingPower(self, iCiv, iVotes):
- data.lVotingPower[iCiv] = iVotes
-
- def getCrusadePower(self):
- return data.iCrusadePower
-
- def setCrusadePower(self, iPower):
- data.iCrusadePower = iPower
-
- def getFavorite(self):
- return data.iFavorite
-
- def setFavorite(self, iFavorite):
- data.iFavorite = iFavorite
-
- def getPowerful(self):
- return data.iPowerful
-
- def setPowerful(self, iPowerful):
- data.iPowerful = iPowerful
-
- def getLeader(self):
- return data.iLeader
-
- def setLeader(self, iLeader):
- data.iLeader = iLeader
-
- def getVotesGatheredFavorite(self):
- return data.lVotesGathered[0]
-
- def setVotesGatheredFavorite(self, iVotes):
- data.lVotesGathered[0] = iVotes
-
- def getVotesGatheredPowerful(self):
- return data.lVotesGathered[1]
-
- def setVotesGatheredPowerful(self, iVotes):
- data.lVotesGathered[1] = iVotes
-
- def getRichestCatholic(self):
- return data.iRichestCatholic
-
- def setRichestCatholic(self, iPlayer):
- data.iRichestCatholic = iPlayer
-
- def getIsTarget(self, iCiv):
- return data.lDeviateTargets[iCiv]
-
- def setIsTarget(self, iCiv, bTarget):
- data.lDeviateTargets[iCiv] = bTarget
-
- def getTargetPlot(self):
- return data.tTarget
-
- def setTarget(self, iX, iY):
- data.tTarget = (iX, iY)
-
- def hasSucceeded(self):
- iSucc = data.iCrusadeSucceeded
- iTest = iSucc == 1
- return iTest
-
- def setSucceeded(self):
- data.iCrusadeSucceeded = 1
-
- def getCrusadeToReturn(self):
- return data.iCrusadeToReturn
-
- def setCrusadeToReturn(self, iNewValue):
- data.iCrusadeToReturn = iNewValue
-
- def isDefensiveCrusadeEnabled(self):
- return data.bDCEnabled
-
- def setDefensiveCrusadeEnabled(self, bNewValue):
- data.bDCEnabled = bNewValue
-
- def getDefensiveCrusadeLast(self):
- return data.iDCLast
-
- def setDefensiveCrusadeLast(self, iLast):
- data.iDCLast = iLast
-
- def initVotePopup(self):
- iHuman = human()
- pHuman = gc.getPlayer(iHuman)
- iActiveCrusade = self.getActiveCrusade(turn())
- iBribe = 200 + 50 * iActiveCrusade
- if pHuman.getGold() >= iBribe:
- event_popup(
- 7616,
- text("TXT_KEY_CRUSADE_INIT_POPUP"),
- text("TXT_KEY_CRUSADE_INIT"),
- [
- text("TXT_KEY_CRUSADE_ACCEPT"),
- text("TXT_KEY_CRUSADE_DENY"),
- text("TXT_KEY_CRUSADE_DENY_RUDE"),
- text("TXT_KEY_CRUSADE_BRIBE_OUT", iBribe),
- ],
- )
- else:
- event_popup(
- 7616,
- text("TXT_KEY_CRUSADE_INIT_POPUP"),
- text("TXT_KEY_CRUSADE_INIT"),
- [
- text("TXT_KEY_CRUSADE_ACCEPT"),
- text("TXT_KEY_CRUSADE_DENY"),
- text("TXT_KEY_CRUSADE_DENY_RUDE"),
- ],
- )
-
- def informLeaderPopup(self):
- event_popup(
- 7617,
- text("TXT_KEY_CRUSADE_LEADER_POPUP"),
- player(self.getLeader()).getName() + text("TXT_KEY_CRUSADE_LEAD"),
- [text("TXT_KEY_CRUSADE_OK")],
- )
-
- def voteHumanPopup(self):
- favorite_txt = (
- gc.getPlayer(self.getFavorite()).getName()
- + " ("
- + gc.getPlayer(self.getFavorite()).getCivilizationShortDescription(0)
- + ")"
- )
- powerful_txt = (
- gc.getPlayer(self.getPowerful()).getName()
- + " ("
- + gc.getPlayer(self.getPowerful()).getCivilizationShortDescription(0)
- + ")"
- )
- event_popup(
- 7618,
- text("TXT_KEY_CRUSADE_VOTE_POPUP"),
- text("TXT_KEY_CRUSADE_VOTE"),
- [favorite_txt, powerful_txt],
- )
-
- def deviateHumanPopup(self):
- iCost = gc.getPlayer(human()).getGold() / 3
- sString = (
- text("TXT_KEY_CRUSADE_RICHEST")
- + text("TXT_KEY_CRUSADE_COST")
- + " "
- + str(iCost)
- + " "
- + text("TXT_KEY_CRUSADE_GOLD")
- + gc.getPlayer(self.getLeader()).getName()
- + " "
- + text("TXT_KEY_CRUSADE_CURRENT_LEADER")
- )
- event_popup(
- 7619,
- text("TXT_KEY_CRUSADE_DEVIATE"),
- sString,
- [text("TXT_KEY_CRUSADE_DECIDE_WEALTH"), text("TXT_KEY_CRUSADE_DECIDE_FAITH")],
- )
-
- def deviateNewTargetPopup(self):
- lTargetList = []
- lTargetList.append(
- gc.getMap().plot(*CITIES[City.JERUSALEM]).getPlotCity().getName()
- + " ("
- + gc.getPlayer(
- gc.getMap().plot(*CITIES[City.JERUSALEM]).getPlotCity().getOwner()
- ).getCivilizationAdjective(0)
- + ")"
- )
- for iPlayer in civilizations().majors().ids():
- pPlayer = gc.getPlayer(iPlayer)
- if (
- iPlayer == Civ.POPE
- or pPlayer.getStateReligion() == Religion.CATHOLICISM
- or not pPlayer.isAlive()
- ):
- self.setIsTarget(iPlayer, False)
- else:
- self.setIsTarget(iPlayer, True)
- lTargetList.append(
- pPlayer.getCapitalCity().getName()
- + " ("
- + pPlayer.getCivilizationAdjective(0)
- + ")"
- )
- event_popup(
- 7620, text("TXT_KEY_CRUSADE_CORRUPT"), text("TXT_KEY_CRUSADE_TARGET"), lTargetList
- )
-
- def underCrusadeAttackPopup(self, sCityName, iLeader):
- sText = text(
- "TXT_KEY_CRUSADE_UNDER_ATTACK1",
- gc.getPlayer(iLeader).getCivilizationAdjective(0),
- gc.getPlayer(iLeader).getName(),
- sCityName,
- )
- event_popup(
- 7621, text("TXT_KEY_CRUSADE_UNDER_ATTACK"), sText, [text("TXT_KEY_CRUSADE_PREPARE")]
- )
-
- def endCrusades(self):
- for i in range(NUM_CRUSADES):
- if self.getCrusadeInit(i) < 0:
- self.setCrusadeInit(i, 0)
- # Absinthe: reset sent unit counter after the Crusades are over (so it won't give Company benefits forever based on the last one)
- for iPlayer in civilizations().majors().ids():
- self.setNumUnitsSent(iPlayer, 0)
-
- def checkTurn(self, iGameTurn):
- # self.informPopup()
-
- if self.getCrusadeToReturn() > -1:
- self.freeCrusaders(self.getCrusadeToReturn())
- self.setCrusadeToReturn(-1)
-
- # Absinthe: crusade date - 5 means the exact time for the arrival
- if iGameTurn == year(1096) - 5: # First Crusade arrives in 1096AD
- self.setCrusadeInit(0, -1)
- elif (
- iGameTurn >= year(1147) - 7
- and self.getCrusadeInit(0) > 0
- and self.getCrusadeInit(1) == -2
- ): # Crusade of 1147AD, little earlier (need to be more than 9 turns between crusades)
- self.setCrusadeInit(1, -1) # turn 176
- elif (
- iGameTurn >= year(1187) - 8
- and self.getCrusadeInit(1) > 0
- and self.getCrusadeInit(2) == -2
- ): # Crusade of 1187AD, little earlier (need to be more than 9 turns between crusades)
- self.setCrusadeInit(2, -1) # turn 187
- elif (
- iGameTurn >= year(1202) - 4
- and self.getCrusadeInit(2) > 0
- and self.getCrusadeInit(3) == -2
- ): # Crusade of 1202AD, little later (need to be more than 9 turns between crusades)
- self.setCrusadeInit(3, -1) # turn 197
- elif (
- iGameTurn >= year(1229) - 3
- and self.getCrusadeInit(3) > 0
- and self.getCrusadeInit(4) == -2
- ): # Crusade of 1229AD, little later (need to be more than 9 turns between crusades)
- self.setCrusadeInit(4, -1) # turn 207
- elif (
- iGameTurn >= year(1271) - 5
- and self.getCrusadeInit(4) > 0
- and self.getCrusadeInit(5) == -2
- ): # Crusade of 1270AD
- self.setCrusadeInit(5, -1) # turn 219
-
- # Start of Defensive Crusades: indulgences for the Reconquista given by the Catholic Church in 1000AD
- if iGameTurn == year(1000):
- self.setDefensiveCrusadeEnabled(True)
-
- # End of Defensive Crusades: no more defensive crusades after Protestantism is founded
- if self.isDefensiveCrusadeEnabled():
- if gc.getGame().isReligionFounded(Religion.PROTESTANTISM):
- self.setDefensiveCrusadeEnabled(False)
-
- if self.isDefensiveCrusadeEnabled():
- self.doDefensiveCrusade(iGameTurn)
-
- self.checkToStart(iGameTurn)
-
- iActiveCrusade = self.getActiveCrusade(iGameTurn)
- if iActiveCrusade > -1:
- iStartDate = self.getCrusadeInit(iActiveCrusade)
- if iStartDate == iGameTurn:
- self.doParticipation(iGameTurn)
-
- elif iStartDate + 1 == iGameTurn:
- self.computeVotingPower(iGameTurn)
- self.setCrusaders()
- for i in range(8):
- self.setSelectedUnit(i, 0)
- for iPlayer in civilizations().majors().ids():
- # Absinthe: first we set all civs' unit counter to 0, then send the new round of units
- self.setNumUnitsSent(iPlayer, 0)
- if self.getVotingPower(iPlayer) > 0:
- self.sendUnits(iPlayer)
- if not self.anyParticipate():
- return
- self.chooseCandidates(iGameTurn)
- self.voteForCandidatesAI()
- self.voteForCandidatesHuman()
-
- elif iStartDate + 2 == iGameTurn:
- if not self.anyParticipate():
- return
- self.selectVoteWinner()
- self.decideTheRichestCatholic(iActiveCrusade)
- if self.getRichestCatholic() == human():
- self.decideDeviateHuman()
- else:
- self.decideDeviateAI()
-
- elif iStartDate + 5 == iGameTurn:
- if not self.anyParticipate():
- return
- self.crusadeArrival(iActiveCrusade)
-
- elif iStartDate + 8 == iGameTurn:
- iLeader = self.getLeader()
- self.setCrusadeToReturn(iLeader)
- self.returnCrusaders()
-
- def checkToStart(self, iGameTurn):
- # if Jerusalem is Islamic or Pagan, Crusade has been initialized and it has been at least 5 turns since the last crusade and there are any Catholics, begin crusade
- pJPlot = gc.getMap().plot(*CITIES[City.JERUSALEM])
- for i in range(NUM_CRUSADES): # check the Crusades
- if self.getCrusadeInit(i) == -1: # if this one is to start
- if (
- pJPlot.isCity() and self.anyCatholic()
- ): # if there is Jerusalem and there are any Catholics
- # Sedna17 -- allowing crusades against independent Jerusalem
- iVictim = pJPlot.getPlotCity().getOwner()
- if self.isOrMasterChristian(iVictim):
- break
- if i == 0 or (
- self.getCrusadeInit(i - 1) > -1
- and self.getCrusadeInit(i - 1) + 9 < iGameTurn
- ):
- self.setCrusadeInit(i, iGameTurn)
-
- def anyCatholic(self):
- return civilizations().main().any(lambda c: c.has_state_religion(Religion.CATHOLICISM))
-
- def anyParticipate(self):
- for i in civilizations().main().ids():
- if self.getVotingPower(i) > 0:
- return True
- return False
-
- def eventApply7616(self, popupReturn):
- iHuman = human()
- if popupReturn.getButtonClicked() == 0:
- self.setParticipate(True)
- gc.getPlayer(iHuman).setIsCrusader(True)
- elif popupReturn.getButtonClicked() == 1 or popupReturn.getButtonClicked() == 2:
- self.setParticipate(False)
- pPlayer = gc.getPlayer(iHuman)
- pPlayer.setIsCrusader(False)
- pPlayer.changeFaith(-min(5, pPlayer.getFaith()))
- message(
- iHuman, text("TXT_KEY_CRUSADE_DENY_FAITH"), force=True, color=MessageData.LIGHT_RED
- )
- gc.getPlayer(Civ.POPE).AI_changeMemoryCount(
- iHuman, MemoryTypes.MEMORY_REJECTED_DEMAND, 2
- )
- # Absinthe: some units from Chivalric Orders might leave you nevertheless
- for pUnit in units().owner(iHuman).entities():
- iUnitType = pUnit.getUnitType()
- if iUnitType in [
- Unit.KNIGHT_OF_ST_JOHNS,
- Unit.TEMPLAR,
- Unit.TEUTONIC,
- ]:
- pPlot = gc.getMap().plot(pUnit.getX(), pUnit.getY())
- random_value = percentage()
- # Absinthe: less chance for units currently on ships
- if pUnit.isCargo():
- random_value -= 10
- if pPlot.isCity():
- if self.getNumDefendersAtPlot(pPlot) > 3:
- if random_value < 50:
- self.addSelectedUnit(self.unitCrusadeCategory(iUnitType))
- message(
- iHuman,
- text("TXT_KEY_CRUSADE_DENY_LEAVE_ANYWAY"),
- button=gc.getUnitInfo(iUnitType).getButton(),
- color=MessageData.LIGHT_RED,
- location=pUnit,
- )
- pUnit.kill(0, -1)
- elif self.getNumDefendersAtPlot(pPlot) > 1:
- if random_value < 10:
- self.addSelectedUnit(self.unitCrusadeCategory(iUnitType))
- message(
- iHuman,
- text("TXT_KEY_CRUSADE_DENY_LEAVE_ANYWAY"),
- button=gc.getUnitInfo(iUnitType).getButton(),
- color=MessageData.LIGHT_RED,
- location=pUnit,
- )
- pUnit.kill(0, -1)
- elif random_value < 30:
- self.addSelectedUnit(self.unitCrusadeCategory(iUnitType))
- message(
- iHuman,
- text("TXT_KEY_CRUSADE_DENY_LEAVE_ANYWAY"),
- button=gc.getUnitInfo(iUnitType).getButton(),
- color=MessageData.LIGHT_RED,
- location=pUnit,
- )
- pUnit.kill(0, -1)
- # Absinthe: 3rd option, only if you have enough money to make a contribution to the Crusade instead of sending units
- else:
- self.setParticipate(False)
- pPlayer = gc.getPlayer(iHuman)
- pPlayer.setIsCrusader(False)
- pPope = gc.getPlayer(Civ.POPE)
- iActiveCrusade = self.getActiveCrusade(turn())
- iBribe = 200 + 50 * iActiveCrusade
- pPope.changeGold(iBribe)
- pPlayer.changeGold(-iBribe)
- gc.getPlayer(Civ.POPE).AI_changeMemoryCount(
- iHuman, MemoryTypes.MEMORY_REJECTED_DEMAND, 1
- )
-
- def eventApply7618(self, popupReturn):
- if popupReturn.getButtonClicked() == 0:
- self.setVotesGatheredFavorite(
- self.getVotesGatheredFavorite() + self.getVotingPower(human())
- )
- else:
- self.setVotesGatheredPowerful(
- self.getVotesGatheredPowerful() + self.getVotingPower(human())
- )
-
- def eventApply7619(self, popupReturn):
- if popupReturn.getButtonClicked() == 0:
- player().changeGold(-player().getGold() / 3)
- self.setLeader(human())
- self.setCrusadePower(self.getCrusadePower() / 2)
- self.deviateNewTargetPopup()
- else:
- self.setTarget(*CITIES[City.JERUSALEM])
- self.startCrusade()
-
- def eventApply7620(self, popupReturn):
- iDecision = popupReturn.getButtonClicked()
- if iDecision == 0:
- self.setTarget(*CITIES[City.JERUSALEM])
- self.startCrusade()
- return
- iTargets = 0
- for i in civilizations().majors().ids():
- if self.getIsTarget(i):
- iTargets += 1
- if iTargets == iDecision:
- pTargetCity = gc.getPlayer(i).getCapitalCity()
- self.setTarget(pTargetCity.getX(), pTargetCity.getY())
- iDecision = -2
-
- self.startCrusade()
-
- def doParticipation(self, iGameTurn):
- iHuman = human()
- if civilization(iHuman).date.birth < iGameTurn:
- pHuman = gc.getPlayer(iHuman)
- if pHuman.getStateReligion() != Religion.CATHOLICISM:
- self.setParticipate(False)
- message(
- iHuman, text("TXT_KEY_CRUSADE_CALLED"), force=True, color=MessageData.LIGHT_RED
- )
- else:
- self.initVotePopup()
- else:
- self.setParticipate(False)
-
- def chooseCandidates(self, iGameTurn):
- bFound = False
- iFavorite = 0
- iFavor = 0
- for i in civilizations().main().ids():
- if self.getVotingPower(i) > 0:
- if bFound:
- iNFavor = gc.getRelationTowards(Civ.POPE, i)
- if iNFavor > iFavor:
- iNFavor = iFavor
- iFavorite = i
- else:
- iFavor = gc.getRelationTowards(Civ.POPE, i)
- iFavorite = i
- bFound = True
- self.setFavorite(iFavorite)
-
- iPowerful = iFavorite
- iPower = self.getVotingPower(iPowerful)
-
- for i in civilizations().main().ids():
- if self.getVotingPower(i) > iPower or (
- iPowerful == iFavorite and self.getVotingPower(i) > 0
- ):
- iPowerful = i
- iPower = self.getVotingPower(iPowerful)
-
- if iPowerful == iFavorite:
- self.setPowerful(-1)
- else:
- self.setPowerful(iPowerful)
-
- def computeVotingPower(self, iGameTurn):
- iTmJerusalem = gc.getPlayer(
- gc.getMap().plot(*CITIES[City.JERUSALEM]).getPlotCity().getOwner()
- ).getTeam()
- for iPlayer in civilizations().majors().ids():
- pPlayer = gc.getPlayer(iPlayer)
- if (
- civilization(iPlayer).date.birth > iGameTurn
- or not pPlayer.isAlive()
- or pPlayer.getStateReligion() != Religion.CATHOLICISM
- or gc.getTeam(pPlayer.getTeam()).isVassal(iTmJerusalem)
- ):
- self.setVotingPower(iPlayer, 0)
- else:
- # We use the (similarly named) getVotingPower from CvPlayer.cpp to determine a vote value for a given State Religion, but it's kinda strange
- # Will leave it this way for now, but might be a good idea to improve it at some point
- self.setVotingPower(iPlayer, pPlayer.getVotingPower(Religion.CATHOLICISM))
-
- # No votes from the human player if he/she won't participate (AI civs will always participate)
- if not self.getParticipate():
- self.setVotingPower(human(), 0)
-
- # The Pope has more votes (Rome is small anyway)
- self.setVotingPower(Civ.POPE, self.getVotingPower(Civ.POPE) * (5 / 4))
-
- iPower = 0
- for iPlayer in civilizations().majors().ids():
- iPower += self.getVotingPower(iPlayer)
-
- self.setCrusadePower(iPower)
- # Note that voting power is increased after this (but before the actual vote) for each sent unit by 2
-
- def setCrusaders(self):
- for iPlayer in civilizations().majors().ids():
- if not iPlayer == human() and self.getVotingPower(iPlayer) > 0:
- gc.getPlayer(iPlayer).setIsCrusader(True)
-
- def sendUnits(self, iPlayer):
- pPlayer = gc.getPlayer(iPlayer)
- iNumUnits = pPlayer.getNumUnits()
- if civilization(iPlayer).date.birth + 10 > turn(): # in the first 10 turns
- if iNumUnits < 10:
- iMaxToSend = 0
- else:
- iMaxToSend = 1
- elif civilization(iPlayer).date.birth + 25 > turn(): # between turn 11-25
- iMaxToSend = min(10, max(1, (5 * iNumUnits) / 50))
- else:
- iMaxToSend = min(10, max(1, (5 * iNumUnits) / 35)) # after turn 25
- iCrusadersSend = 0
- if iMaxToSend > 0:
- # Absinthe: a randomized list of all units of the civ
- lUnits = [pPlayer.getUnit(i) for i in range(iNumUnits)]
- random.shuffle(lUnits)
- for pUnit in lUnits:
- # Absinthe: check only for combat units and ignore naval units
- if pUnit.baseCombatStr() > 0 and pUnit.getDomainType() != DomainTypes.DOMAIN_SEA:
- # Absinthe: mercenaries and leaders (units with attached Great Generals) won't go
- if not pUnit.isHasPromotion(Promotion.MERC) and not pUnit.isHasPromotion(
- Promotion.LEADER
- ):
- iCrusadeCategory = self.unitCrusadeCategory(pUnit.getUnitType())
- pPlot = gc.getMap().plot(pUnit.getX(), pUnit.getY())
- iRandNum = percentage()
- # Absinthe: much bigger chance for special Crusader units and Knights
- if iCrusadeCategory < 4:
- if pPlot.isCity():
- if self.getNumDefendersAtPlot(pPlot) > 3:
- if iRandNum < 80:
- iCrusadersSend += 1
- self.sendUnit(pUnit)
- elif self.getNumDefendersAtPlot(pPlot) > 1:
- if iRandNum < 40:
- iCrusadersSend += 1
- self.sendUnit(pUnit)
- else:
- # Absinthe: much less chance for units currently on ships
- if pUnit.isCargo():
- if iRandNum < 40:
- iCrusadersSend += 1
- self.sendUnit(pUnit)
- else:
- if iRandNum < 80:
- iCrusadersSend += 1
- self.sendUnit(pUnit)
- else:
- if pPlot.isCity():
- if self.getNumDefendersAtPlot(pPlot) > 2:
- if iRandNum < (self.unitProbability(pUnit.getUnitType()) - 10):
- iCrusadersSend += 1
- self.sendUnit(pUnit)
- else:
- # Absinthe: much less chance for units currently on ships
- if pUnit.isCargo():
- if (
- iRandNum
- < (self.unitProbability(pUnit.getUnitType()) - 10) / 2
- ):
- iCrusadersSend += 1
- self.sendUnit(pUnit)
- else:
- if iRandNum < (self.unitProbability(pUnit.getUnitType()) - 10):
- iCrusadersSend += 1
- self.sendUnit(pUnit)
- if iCrusadersSend == iMaxToSend:
- return
- # Absinthe: extra chance for some random units, if we didn't fill the quota
- for i in range(15):
- iNumUnits = (
- pPlayer.getNumUnits()
- ) # we have to recalculate each time, as some units might have gone on the Crusade already
- iRandUnit = rand(iNumUnits)
- pUnit = pPlayer.getUnit(iRandUnit)
- # Absinthe: check only for combat units and ignore naval units
- if pUnit.baseCombatStr() > 0 and pUnit.getDomainType() != 0:
- # Absinthe: mercenaries and leaders (units with attached Great Generals) won't go
- if not pUnit.isHasPromotion(Promotion.MERC) and not pUnit.isHasPromotion(
- Promotion.LEADER
- ):
- pPlot = gc.getMap().plot(pUnit.getX(), pUnit.getY())
- if pPlot.isCity():
- if self.getNumDefendersAtPlot(pPlot) > 2:
- if percentage_chance(
- self.unitProbability(pUnit.getUnitType()), strict=True
- ):
- iCrusadersSend += 1
- self.sendUnit(pUnit)
- else:
- # Absinthe: much less chance for units currently on ships
- if pUnit.isCargo() and percentage_chance(
- self.unitProbability(pUnit.getUnitType() / 2), strict=True
- ):
- iCrusadersSend += 1
- self.sendUnit(pUnit)
- elif percentage_chance(
- self.unitProbability(pUnit.getUnitType()), strict=True
- ):
- iCrusadersSend += 1
- self.sendUnit(pUnit)
- if iCrusadersSend == iMaxToSend:
- return
-
- def getNumDefendersAtPlot(self, pPlot):
- iOwner = pPlot.getOwner()
- if iOwner < 0:
- return 0
- iNumUnits = pPlot.getNumUnits()
- iDefenders = 0
- for i in range(iNumUnits):
- pUnit = pPlot.getUnit(i)
- if pUnit.getOwner() == iOwner:
- if pUnit.baseCombatStr() > 0 and pUnit.getDomainType() != DomainTypes.DOMAIN_SEA:
- iDefenders += 1
- return iDefenders
-
- def sendUnit(self, pUnit):
- iOwner = pUnit.getOwner()
- self.addSelectedUnit(self.unitCrusadeCategory(pUnit.getUnitType()))
- self.setVotingPower(iOwner, self.getVotingPower(iOwner) + 2)
- self.changeNumUnitsSent(iOwner, 1) # Absinthe: counter for sent units per civ
- # Absinthe: faith point boost for each sent unit (might get some more on successful Crusade):
- player(iOwner).changeFaith(1)
- if iOwner == human():
- message(
- human(),
- text("TXT_KEY_CRUSADE_LEAVE") + " " + pUnit.getName(),
- sound="AS2D_BUILD_CATHOLIC",
- color=MessageData.ORANGE,
- )
- pUnit.kill(0, -1)
-
- def unitProbability(self, iUnitType):
- if iUnitType in [
- Unit.ARCHER,
- Unit.CROSSBOWMAN,
- Unit.ARBALEST,
- Unit.GENOA_BALESTRIERI,
- Unit.LONGBOWMAN,
- Unit.ENGLISH_LONGBOWMAN,
- Unit.PORTUGAL_FOOT_KNIGHT,
- ]:
- return 10
- if iUnitType in [
- Unit.LANCER,
- Unit.BULGARIAN_KONNIK,
- Unit.CORDOBAN_BERBER,
- Unit.HEAVY_LANCER,
- Unit.HUNGARIAN_HUSZAR,
- Unit.ARABIA_GHAZI,
- Unit.BYZANTINE_CATAPHRACT,
- Unit.KIEV_DRUZHINA,
- Unit.KNIGHT,
- Unit.MOSCOW_BOYAR,
- Unit.BURGUNDIAN_PALADIN,
- ]:
- return 70
- if iUnitType in [
- Unit.TEMPLAR,
- Unit.TEUTONIC,
- Unit.KNIGHT_OF_ST_JOHNS,
- Unit.CALATRAVA_KNIGHT,
- Unit.DRAGON_KNIGHT,
- ]:
- return 90
- if (
- iUnitType <= Unit.ISLAMIC_MISSIONARY or iUnitType >= Unit.WORKBOAT
- ): # Workers, Executives, Missionaries, Sea Units and Mercenaries do not go
- return -1
- return 50
-
- def unitCrusadeCategory(self, iUnitType):
- if iUnitType == Unit.TEMPLAR:
- return 0
- if iUnitType == Unit.TEUTONIC:
- return 1
- if iUnitType in [
- Unit.KNIGHT_OF_ST_JOHNS,
- Unit.CALATRAVA_KNIGHT,
- Unit.DRAGON_KNIGHT,
- ]:
- return 2
- if iUnitType in [
- Unit.KNIGHT,
- Unit.MOSCOW_BOYAR,
- Unit.BURGUNDIAN_PALADIN,
- ]:
- return 3
- if iUnitType in [
- Unit.HEAVY_LANCER,
- Unit.HUNGARIAN_HUSZAR,
- Unit.ARABIA_GHAZI,
- Unit.BYZANTINE_CATAPHRACT,
- Unit.KIEV_DRUZHINA,
- ]:
- return 4
- if iUnitType in [
- Unit.LANCER,
- Unit.BULGARIAN_KONNIK,
- Unit.CORDOBAN_BERBER,
- ]:
- return 5
- if iUnitType in [Unit.CATAPULT, Unit.TREBUCHET]:
- return 6
- return 7
-
- def voteForCandidatesAI(self):
- if self.getPowerful() == -1:
- self.setLeader(self.getFavorite())
- if self.getParticipate():
- self.informLeaderPopup()
- elif player().isExisting():
- message(
- human(),
- gc.getPlayer(self.getLeader()).getName() + text("TXT_KEY_CRUSADE_LEAD"),
- force=True,
- color=MessageData.LIGHT_RED,
- )
- return
-
- iFavorite = self.getFavorite()
- iPowerful = self.getPowerful()
- if iFavorite == human():
- iFavorVotes = 0
- else:
- iFavorVotes = self.getVotingPower(iFavorite)
- if iPowerful == human():
- iPowerVotes = 0
- else:
- iPowerVotes = self.getVotingPower(iPowerful)
-
- for civ in civilizations().majors().ai().drop(iFavorite, iPowerful).ids():
- iVotes = self.getVotingPower(civ)
- if iVotes > 0:
- if gc.getRelationTowards(civ, iFavorite) > gc.getRelationTowards(civ, iPowerful):
- iFavorVotes += iVotes
- else:
- iPowerVotes += iVotes
-
- self.setVotesGatheredFavorite(iFavorVotes)
- self.setVotesGatheredPowerful(iPowerVotes)
-
- def voteForCandidatesHuman(self):
- if self.getParticipate() and not self.getPowerful() == -1:
- self.voteHumanPopup()
-
- def selectVoteWinner(self):
- if self.getVotesGatheredPowerful() > self.getVotesGatheredFavorite():
- self.setLeader(self.getPowerful())
- else:
- self.setLeader(self.getFavorite())
-
- if self.getParticipate():
- self.informLeaderPopup()
- elif player().isExisting():
- message(
- human(),
- gc.getPlayer(self.getLeader()).getName() + text("TXT_KEY_CRUSADE_LEAD"),
- force=True,
- color=MessageData.LIGHT_RED,
- )
-
- # not yet, check to see for deviations
- # pJPlot = gc.getMap().plot(*CITIES[City.JERUSALEM])
- # gc.getTeam( gc.getPlayer( self.getLeader() ) ).declareWar( pJPlot.getPlotCity().getOwner(), True, -1 )
-
- def decideTheRichestCatholic(self, iActiveCrusade):
- # The First Crusade cannot be deviated
- if iActiveCrusade == 0:
- self.setRichestCatholic(-1)
- return
-
- iRichest = -1
- iMoney = 0
- # iPopeMoney = gc.getPlayer( Civ.POPE ).getGold()
- for i in civilizations().main().ids():
- if self.getVotingPower(i) > 0:
- pPlayer = gc.getPlayer(i)
- iPlayerMoney = pPlayer.getGold()
- # if ( iPlayerMoney > iMoney and iPlayerMoney > iPopeMoney ):
- if iPlayerMoney > iMoney:
- iRichest = i
- iMoney = iPlayerMoney
-
- if iRichest != Civ.POPE:
- self.setRichestCatholic(iRichest)
- else:
- self.setRichestCatholic(-1)
-
- def decideDeviateHuman(self):
- self.deviateHumanPopup()
-
- def decideDeviateAI(self):
- iRichest = self.getRichestCatholic()
- bStolen = False
- if iRichest in [Civ.VENECIA, Civ.GENOA]:
- pByzantium = gc.getPlayer(Civ.BYZANTIUM)
- if pByzantium.isAlive():
- # Only if the potential attacker is not vassal of the target
- iTeamByzantium = pByzantium.getTeam()
- pRichest = gc.getPlayer(iRichest)
- pTeamRichest = gc.getTeam(pRichest.getTeam())
- if not pTeamRichest.isVassal(iTeamByzantium):
- # Only if Byzantium holds Constantinople and not a vassal
- pConstantinoplePlot = gc.getMap().plot(
- *civilization(Civ.BYZANTIUM).location.capital
- )
- pConstantinopleCity = pConstantinoplePlot.getPlotCity()
- iConstantinopleOwner = pConstantinopleCity.getOwner()
- # should check if Constantinople is their capital city to be fully correct, but we can assume that's the case
- bIsNotAVassal = not isAVassal(Civ.BYZANTIUM)
- if iConstantinopleOwner == Civ.BYZANTIUM and bIsNotAVassal:
- self.crusadeStolenAI(iRichest, Civ.BYZANTIUM)
- bStolen = True
- elif iRichest in [Civ.CASTILE, Civ.PORTUGAL, Civ.ARAGON]:
- pCordoba = gc.getPlayer(Civ.CORDOBA)
- if pCordoba.isAlive():
- # Only if the potential attacker is not vassal of the target
- iTeamCordoba = pCordoba.getTeam()
- pRichest = gc.getPlayer(iRichest)
- pTeamRichest = gc.getTeam(pRichest.getTeam())
- if not pTeamRichest.isVassal(iTeamCordoba):
- # Only if Cordoba is Muslim and not a vassal
- bIsNotAVassal = not isAVassal(Civ.CORDOBA)
- if pCordoba.getStateReligion() == Religion.ISLAM and bIsNotAVassal:
- self.crusadeStolenAI(iRichest, Civ.CORDOBA)
- bStolen = True
- elif iRichest in [Civ.HUNGARY, Civ.POLAND, Civ.AUSTRIA]:
- pTurkey = gc.getPlayer(Civ.OTTOMAN)
- if pTurkey.isAlive():
- # Only if the potential attacker is not vassal of the target
- iTeamTurkey = pTurkey.getTeam()
- pRichest = gc.getPlayer(iRichest)
- pTeamRichest = gc.getTeam(pRichest.getTeam())
- if not pTeamRichest.isVassal(iTeamTurkey):
- # Only if the Ottomans are Muslim and not a vassal
- bIsNotAVassal = not isAVassal(Civ.OTTOMAN)
- if pTurkey.getStateReligion() == Religion.ISLAM and bIsNotAVassal:
- self.crusadeStolenAI(iRichest, Civ.OTTOMAN)
- bStolen = True
-
- if not bStolen:
- self.setTarget(*CITIES[City.JERUSALEM])
-
- self.startCrusade()
-
- def crusadeStolenAI(self, iNewLeader, iNewTarget):
- self.setLeader(iNewLeader)
- pLeader = gc.getPlayer(iNewLeader)
- if player().isExisting():
- message(
- human(),
- pLeader.getName() + text("TXT_KEY_CRUSADE_DEVIATED"),
- color=MessageData.LIGHT_RED,
- )
- # pLeader.setGold( pLeader.getGold() - gc.getPlayer( Civ.POPE ).getGold() / 3 )
- # pLeader.setGold( gc.getPlayer( Civ.POPE ).getGold() / 4 )
- pLeader.setGold(2 * pLeader.getGold() / 3)
- pTarget = gc.getPlayer(iNewTarget).getCapitalCity()
- self.setTarget(pTarget.getX(), pTarget.getY())
- self.setCrusadePower(self.getCrusadePower() / 2)
-
- def startCrusade(self):
- iHuman = human()
- iLeader = self.getLeader()
- iX, iY = self.getTargetPlot()
- pTargetCity = gc.getMap().plot(iX, iY).getPlotCity()
- iTargetPlayer = pTargetCity.getOwner()
- # Absinthe: in case the Crusader civ has been destroyed
- if not gc.getPlayer(iLeader).isAlive():
- self.returnCrusaders()
- return
- # Target city can change ownership during the voting
- if gc.getPlayer(iTargetPlayer).getStateReligion() == Religion.CATHOLICISM:
- self.returnCrusaders()
- return
- # Absinthe: do not Crusade against themselves
- if iTargetPlayer == iLeader:
- self.returnCrusaders()
- return
- if iTargetPlayer == iHuman:
- self.underCrusadeAttackPopup(pTargetCity.getName(), iLeader)
- elif player().isExisting():
- sCityName = cnm.lookupName(pTargetCity, Civ.POPE)
- if sCityName == "Unknown":
- sCityName = cnm.lookupName(pTargetCity, iLeader)
- sText = text(
- "TXT_KEY_CRUSADE_START",
- gc.getPlayer(iLeader).getCivilizationAdjectiveKey(),
- gc.getPlayer(iLeader).getName(),
- gc.getPlayer(iTargetPlayer).getCivilizationAdjectiveKey(),
- sCityName,
- )
- message(iHuman, sText, color=MessageData.LIGHT_RED)
-
- # Absinthe: proper war declaration checks
- teamLeader = gc.getTeam(gc.getPlayer(iLeader).getTeam())
- iTeamTarget = gc.getPlayer(iTargetPlayer).getTeam()
- if not teamLeader.isAtWar(iTeamTarget):
- # Absinthe: add contact if they did not meet before
- if not teamLeader.isHasMet(iTeamTarget):
- teamLeader.meet(iTeamTarget, False)
- if teamLeader.canDeclareWar(iTeamTarget):
- teamLeader.declareWar(iTeamTarget, True, -1)
- else:
- # we cannot declare war to the current owner of the target city
- self.returnCrusaders()
- return
-
- def returnCrusaders(self):
- self.setLeader(-1)
- for i in civilizations().majors().ids():
- gc.getPlayer(i).setIsCrusader(False)
-
- def crusadeArrival(self, iActiveCrusade):
- iTX, iTY = self.getTargetPlot()
- iChosenX = -1
- iChosenY = -1
-
- # if the leader has been destroyed, cancel the Crusade
- iLeader = self.getLeader()
- if iLeader == -1 or not gc.getPlayer(iLeader).isAlive():
- self.returnCrusaders()
- return
-
- # if the target is Jerusalem, and in the mean time it has been captured by an Orthodox or Catholic player (or the owner of Jerusalem converted to a Christian religion), cancel the Crusade
- if (iTX, iTY) == CITIES[City.JERUSALEM]:
- pPlot = gc.getMap().plot(*CITIES[City.JERUSALEM])
- if pPlot.isCity():
- iVictim = pPlot.getPlotCity().getOwner()
- if iVictim < civilizations().majors().len():
- iReligion = gc.getPlayer(iVictim).getStateReligion()
- if iReligion in [Religion.CATHOLICISM, Religion.ORTHODOXY]:
- return
-
- # if not at war with the owner of the city, declare war
- pPlot = gc.getMap().plot(iTX, iTY)
- if pPlot.isCity():
- iVictim = pPlot.getPlotCity().getOwner()
- if (
- iVictim != iLeader
- and gc.getPlayer(iVictim).getStateReligion() != Religion.CATHOLICISM
- ):
- teamLeader = gc.getTeam(gc.getPlayer(iLeader).getTeam())
- iTeamVictim = gc.getPlayer(iVictim).getTeam()
- if not teamLeader.isAtWar(iTeamVictim):
- # Absinthe: add contact if they did not meet before
- if not teamLeader.isHasMet(iTeamVictim):
- teamLeader.meet(iTeamVictim, False)
- if teamLeader.canDeclareWar(iTeamVictim):
- teamLeader.declareWar(iTeamVictim, False, -1)
- else:
- # we cannot declare war to the current owner of the target city
- self.returnCrusaders()
- return
-
- lFreeLandPlots = []
- lLandPlots = []
- for plot in (
- plots()
- .surrounding((iTX, iTY))
- .filter(lambda p: (p.isHills() or p.isFlatlands()) and not p.isCity())
- .entities()
- ):
- lLandPlots.append(location(plot))
- if plot.getNumUnits() == 0:
- lFreeLandPlots.append(location(plot))
- # Absinthe: we try to spawn the army west from the target city (preferably northwest), or at least on as low x coordinates as possible
- # works great both for Jerusalem (try not to spawn across the Jordan river) and for Constantinople (European side, where the actual city is located)
- # also better for most cities in the Levant and in Egypt, and doesn't really matter for the rest
- if lFreeLandPlots:
- iChosenX = 200
- iChosenY = 200
- for tFreeLandPlot in lFreeLandPlots:
- if tFreeLandPlot[0] < iChosenX:
- iChosenX = tFreeLandPlot[0]
- iChosenY = tFreeLandPlot[1]
- elif tFreeLandPlot[0] == iChosenX:
- if tFreeLandPlot[0] > iChosenY:
- iChosenY = tFreeLandPlot[1]
- elif lLandPlots:
- iChosenX = 200
- iChosenY = 200
- for tLandPlot in lLandPlots:
- if tLandPlot[0] < iChosenX:
- iChosenX = tLandPlot[0]
- iChosenY = tLandPlot[1]
- elif tLandPlot[0] == iChosenX:
- if tLandPlot[0] > iChosenY:
- iChosenY = tLandPlot[1]
- pPlot = gc.getMap().plot(iChosenX, iChosenY)
- for i in range(pPlot.getNumUnits()):
- pPlot.getUnit(0).kill(False, Civ.BARBARIAN)
-
- # Absinthe: if a valid plot is found, make the units and send a message about the arrival to the human player
- if (iChosenX, iChosenY) != (-1, -1):
- self.crusadeMakeUnits((iChosenX, iChosenY), iActiveCrusade)
- if human() == iLeader:
- pTargetCity = gc.getMap().plot(iTX, iTY).getPlotCity()
- sCityName = cnm.lookupName(pTargetCity, Civ.POPE)
- if sCityName == "Unknown":
- sCityName = cnm.lookupName(pTargetCity, iLeader)
- message(
- human(),
- text("TXT_KEY_CRUSADE_ARRIVAL", sCityName) + "!",
- color=MessageData.GREEN,
- location=(iChosenX, iChosenY),
- )
- else:
- self.returnCrusaders()
-
- def crusadeMakeUnits(self, tPlot, iActiveCrusade):
- iLeader = self.getLeader()
- teamLeader = gc.getTeam(gc.getPlayer(iLeader).getTeam())
- iTX, iTY = self.getTargetPlot()
- # if the target is Jerusalem
- if (iTX, iTY) == CITIES[City.JERUSALEM]:
- iRougeModifier = 100
- # human player should always face powerful units when defending Jerusalem
- iHuman = human()
- pPlot = gc.getMap().plot(*CITIES[City.JERUSALEM])
- iVictim = pPlot.getPlotCity().getOwner()
- if teamLeader.isHasTech(Technology.CHIVALRY) or iVictim == iHuman:
- make_crusade_unit(iLeader, Unit.BURGUNDIAN_PALADIN, tPlot, iActiveCrusade)
- make_crusade_unit(iLeader, Unit.TEMPLAR, tPlot, iActiveCrusade)
- make_crusade_unit(iLeader, Unit.TEUTONIC, tPlot, iActiveCrusade)
- make_crusade_unit(iLeader, Unit.KNIGHT_OF_ST_JOHNS, tPlot, iActiveCrusade)
- make_crusade_unit(iLeader, Unit.GUISARME, tPlot, iActiveCrusade)
- make_crusade_unit(iLeader, Unit.CATAPULT, tPlot, iActiveCrusade)
- else:
- make_crusade_units(iLeader, Unit.HEAVY_LANCER, tPlot, iActiveCrusade, 2)
- make_crusade_unit(iLeader, Unit.LANCER, tPlot, iActiveCrusade)
- make_crusade_unit(iLeader, Unit.LONG_SWORDSMAN, tPlot, iActiveCrusade)
- make_crusade_unit(iLeader, Unit.SPEARMAN, tPlot, iActiveCrusade)
- make_crusade_unit(iLeader, Unit.TREBUCHET, tPlot, iActiveCrusade)
- # there are way too many generic units in most Crusades:
- if self.getSelectedUnit(7) > 1:
- iReducedNumber = (
- self.getSelectedUnit(7) * 6 / 10
- ) # note that this is before the specific Crusade reduction
- self.setSelectedUnit(7, iReducedNumber)
- # if the Crusade was derailed
- else:
- iRougeModifier = 200
- if teamLeader.isHasTech(Technology.CHIVALRY):
- make_crusade_unit(iLeader, Unit.KNIGHT, tPlot, iActiveCrusade)
- make_crusade_unit(iLeader, Unit.TEUTONIC, tPlot, iActiveCrusade)
- make_crusade_unit(iLeader, Unit.LONG_SWORDSMAN, tPlot, iActiveCrusade)
- make_crusade_unit(iLeader, Unit.GUISARME, tPlot, iActiveCrusade)
- make_crusade_unit(iLeader, Unit.CATAPULT, tPlot, iActiveCrusade)
- else:
- make_crusade_unit(iLeader, Unit.HEAVY_LANCER, tPlot, iActiveCrusade)
- make_crusade_unit(iLeader, Unit.LANCER, tPlot, iActiveCrusade)
- make_crusade_unit(iLeader, Unit.LONG_SWORDSMAN, tPlot, iActiveCrusade)
- make_crusade_unit(iLeader, Unit.SPEARMAN, tPlot, iActiveCrusade)
- make_crusade_unit(iLeader, Unit.TREBUCHET, tPlot, iActiveCrusade)
- # there are way too many generic units in most Crusades:
- if self.getSelectedUnit(7) > 1:
- iReducedNumber = (
- self.getSelectedUnit(7) * 8 / 10
- ) # note that this is before the specific Crusade reduction
- self.setSelectedUnit(7, iReducedNumber)
-
- # Absinthe: not all units should arrive near Jerusalem
- # later Crusades have more units in the pool, so they should have bigger reduction
- iHuman = human()
- pPlot = gc.getMap().plot(*CITIES[City.JERUSALEM])
- iVictim = pPlot.getPlotCity().getOwner()
- # Absinthe: this reduction is very significant for an AI-controlled Jerusalem, but Crusades should remain an increasing threat to the human player
- if iVictim != iHuman:
- if iActiveCrusade == 0:
- iRougeModifier *= 7 / 5
- elif iActiveCrusade == 1:
- iRougeModifier *= 8 / 5
- elif iActiveCrusade == 2:
- iRougeModifier *= 9 / 5
- elif iActiveCrusade == 3:
- iRougeModifier *= 10 / 5
- elif iActiveCrusade == 4:
- iRougeModifier *= 12 / 5
- else:
- iRougeModifier *= 14 / 5
- else:
- if iActiveCrusade == 0:
- iRougeModifier *= 11 / 10
- elif iActiveCrusade == 1:
- iRougeModifier *= 5 / 5
- elif iActiveCrusade == 2:
- iRougeModifier *= 6 / 5
- elif iActiveCrusade == 3:
- iRougeModifier *= 7 / 5
- elif iActiveCrusade == 4:
- iRougeModifier *= 8 / 5
- else:
- iRougeModifier *= 8 / 5
-
- if self.getSelectedUnit(0) > 0:
- make_crusade_units(
- iLeader,
- Unit.TEMPLAR,
- tPlot,
- iActiveCrusade,
- self.getSelectedUnit(0) * 100 / iRougeModifier,
- )
- if self.getSelectedUnit(1) > 0:
- make_crusade_units(
- iLeader,
- Unit.TEUTONIC,
- tPlot,
- iActiveCrusade,
- self.getSelectedUnit(1) * 100 / iRougeModifier,
- )
- if self.getSelectedUnit(2) > 0:
- make_crusade_units(
- iLeader,
- Unit.KNIGHT_OF_ST_JOHNS,
- tPlot,
- iActiveCrusade,
- self.getSelectedUnit(2) * 100 / iRougeModifier,
- )
- if self.getSelectedUnit(3) > 0:
- iKnightNumber = self.getSelectedUnit(3) * 100 / iRougeModifier
- if iLeader == Civ.BURGUNDY:
- for i in range(0, iKnightNumber):
- if percentage_chance(50, strict=True):
- make_crusade_unit(iLeader, Unit.BURGUNDIAN_PALADIN, tPlot, iActiveCrusade)
- else:
- make_crusade_unit(iLeader, Unit.KNIGHT, tPlot, iActiveCrusade)
- else:
- for i in range(0, iKnightNumber):
- if percentage_chance(20, strict=True):
- make_crusade_unit(iLeader, Unit.BURGUNDIAN_PALADIN, tPlot, iActiveCrusade)
- else:
- make_crusade_unit(iLeader, Unit.KNIGHT, tPlot, iActiveCrusade)
- if self.getSelectedUnit(4) > 0:
- iLightCavNumber = self.getSelectedUnit(4) * 100 / iRougeModifier
- if iLeader == Civ.HUNGARY:
- for i in range(0, iLightCavNumber):
- if percentage_chance(50, strict=True):
- make_crusade_unit(iLeader, Unit.HUNGARIAN_HUSZAR, tPlot, iActiveCrusade)
- else:
- make_crusade_unit(iLeader, Unit.HEAVY_LANCER, tPlot, iActiveCrusade)
- else:
- make_crusade_units(
- iLeader, Unit.HEAVY_LANCER, tPlot, iActiveCrusade, iLightCavNumber
- )
- if self.getSelectedUnit(5) > 0:
- make_crusade_units(
- iLeader,
- Unit.LANCER,
- tPlot,
- iActiveCrusade,
- self.getSelectedUnit(5) * 100 / iRougeModifier,
- )
- if self.getSelectedUnit(6) > 0:
- iSiegeNumber = self.getSelectedUnit(6) * 100 / iRougeModifier
- if iSiegeNumber > 2:
- make_crusade_units(iLeader, Unit.CATAPULT, tPlot, iActiveCrusade, 2)
- make_crusade_units(
- iLeader, Unit.TREBUCHET, tPlot, iActiveCrusade, iSiegeNumber - 2
- )
- else:
- make_crusade_units(iLeader, Unit.CATAPULT, tPlot, iActiveCrusade, iSiegeNumber)
- if self.getSelectedUnit(7) > 0:
- iFootNumber = self.getSelectedUnit(7) * 100 / iRougeModifier
- for i in range(0, iFootNumber):
- if percentage_chance(50, strict=True):
- make_crusade_unit(iLeader, Unit.LONG_SWORDSMAN, tPlot, iActiveCrusade)
- else:
- make_crusade_unit(iLeader, Unit.GUISARME, tPlot, iActiveCrusade)
-
- def freeCrusaders(self, iPlayer):
- # the majority of Crusader units will return from the Crusade, so the Crusading civ will have harder time keeping Jerusalem and the Levant
- iPrevGameTurn = (
- turn() - 1
- ) # process for freeCrusaders was actually started in the previous turn, iActiveCrusade might have changed for the current turn
- iActiveCrusade = self.getActiveCrusade(
- iPrevGameTurn
- ) # Absinthe: the Crusader units are called back before the next Crusade is initialized
- iHuman = human()
- for pUnit in units().owner(iPlayer).entities():
- if pUnit.getMercID() == (
- -5 - iActiveCrusade
- ): # Absinthe: so this is a Crusader Unit of the active Crusade
- pPlot = gc.getMap().plot(pUnit.getX(), pUnit.getY())
- iOdds = 80
- iCrusadeCategory = self.unitCrusadeCategory(pUnit.getUnitType())
- if iCrusadeCategory < 3:
- continue # Knightly Orders don't return
- elif iCrusadeCategory == 7:
- iOdds = 50 # leave some defenders
- if pPlot.isCity():
- if pPlot.getPlotCity().getOwner() == iPlayer:
- iDefenders = self.getNumDefendersAtPlot(pPlot)
- if iDefenders < 4:
- iOdds = 20
- if iDefenders == 0:
- continue
-
- if percentage_chance(iOdds, strict=True):
- pUnit.kill(0, -1)
- if iHuman == iPlayer:
- message(
- iHuman,
- text("TXT_KEY_CRUSADE_CRUSADERS_RETURNING_HOME")
- + " "
- + pUnit.getName(),
- color=MessageData.LIME,
- )
-
- # benefits for the other participants on Crusade return - Faith points, GG points, Relics
- for iCiv in civilizations().main().ids():
- pCiv = gc.getPlayer(iCiv)
- if pCiv.getStateReligion() == Religion.CATHOLICISM and pCiv.isAlive():
- iUnitNumber = self.getNumUnitsSent(iCiv)
- if iUnitNumber > 0:
- # the leader already got exp points through the Crusade itself
- if iCiv == iPlayer:
- # if Jerusalem is held by a Christian civ (maybe some cities in the Levant should be enough) (maybe there should be a unit in the Levant from this Crusade)
- pCity = gc.getMap().plot(*CITIES[City.JERUSALEM]).getPlotCity()
- pPlayer = gc.getPlayer(pCity.getOwner())
- if pPlayer.getStateReligion() == Religion.CATHOLICISM:
- pCiv.changeFaith(1 * iUnitNumber)
- # add relics in the capital
- capital = pCiv.getCapitalCity()
- iCapitalX = capital.getX()
- iCapitalY = capital.getY()
- pCiv.initUnit(
- Unit.HOLY_RELIC,
- iCapitalX,
- iCapitalY,
- UnitAITypes.NO_UNITAI,
- DirectionTypes.DIRECTION_SOUTH,
- )
- if iCiv == iHuman:
- message(
- iHuman,
- text("TXT_KEY_CRUSADE_NEW_RELIC"),
- sound="AS2D_UNIT_BUILD_UNIQUE_UNIT",
- button=gc.getUnitInfo(Unit.HOLY_RELIC).getButton(),
- color=MessageData.GREEN,
- location=(iCapitalX, iCapitalY),
- )
- if iUnitNumber > 3 and percentage_chance(80, strict=True):
- pCiv.initUnit(
- Unit.HOLY_RELIC,
- iCapitalX,
- iCapitalY,
- UnitAITypes.NO_UNITAI,
- DirectionTypes.DIRECTION_SOUTH,
- )
- if iUnitNumber > 9 and percentage_chance(80, strict=True):
- pCiv.initUnit(
- Unit.HOLY_RELIC,
- iCapitalX,
- iCapitalY,
- UnitAITypes.NO_UNITAI,
- DirectionTypes.DIRECTION_SOUTH,
- )
- # all other civs get experience points as well
- else:
- if iCiv == iHuman:
- message(
- iHuman,
- text("TXT_KEY_CRUSADE_CRUSADERS_ARRIVED_HOME"),
- color=MessageData.GREEN,
- )
- pCiv.changeCombatExperience(12 * iUnitNumber)
- # if Jerusalem is held by a Christian civ (maybe some cities in the Levant should be enough) (maybe there should be a unit in the Levant from this Crusade)
- pCity = gc.getMap().plot(*CITIES[City.JERUSALEM]).getPlotCity()
- pPlayer = gc.getPlayer(pCity.getOwner())
- if pPlayer.getStateReligion() == Religion.CATHOLICISM:
- pCiv.changeFaith(1 * iUnitNumber)
- # add relics in the capital
- capital = pCiv.getCapitalCity()
- iCapitalX = capital.getX()
- iCapitalY = capital.getY()
- # safety check, game crashes if it wants to create a unit in a non-existing city
- if capital.getName():
- if percentage_chance(80, strict=True):
- pCiv.initUnit(
- Unit.HOLY_RELIC,
- iCapitalX,
- iCapitalY,
- UnitAITypes.NO_UNITAI,
- DirectionTypes.DIRECTION_SOUTH,
- )
- if iCiv == iHuman:
- message(
- iHuman,
- text("TXT_KEY_CRUSADE_NEW_RELIC"),
- sound="AS2D_UNIT_BUILD_UNIQUE_UNIT",
- button=gc.getUnitInfo(Unit.HOLY_RELIC).getButton(),
- color=MessageData.GREEN,
- location=(iCapitalX, iCapitalY),
- )
- if iUnitNumber > 3 and percentage_chance(60, strict=True):
- pCiv.initUnit(
- Unit.HOLY_RELIC,
- iCapitalX,
- iCapitalY,
- UnitAITypes.NO_UNITAI,
- DirectionTypes.DIRECTION_SOUTH,
- )
- if iUnitNumber > 9 and percentage_chance(60, strict=True):
- pCiv.initUnit(
- Unit.HOLY_RELIC,
- iCapitalX,
- iCapitalY,
- UnitAITypes.NO_UNITAI,
- DirectionTypes.DIRECTION_SOUTH,
- )
-
- # Absinthe: called from CvRFCEventHandler.onCityAcquired
- def success(self, iPlayer):
- pPlayer = gc.getPlayer(iPlayer)
- if not self.hasSucceeded():
- pPlayer.changeGoldenAgeTurns(gc.getPlayer(iPlayer).getGoldenAgeLength())
- self.setSucceeded()
- for plot in plots().surrounding(CITIES[City.JERUSALEM]).entities():
- convertPlotCulture(plot, iPlayer, 100, False)
-
- # Absinthe: pilgrims in Jerusalem if it's held by a Catholic civ
- def checkPlayerTurn(self, iGameTurn, iPlayer):
- if iGameTurn % 3 == 1: # checked every 3rd turn
- pCity = gc.getMap().plot(*CITIES[City.JERUSALEM]).getPlotCity()
- if pCity.getOwner() == iPlayer:
- pPlayer = gc.getPlayer(iPlayer)
- if pPlayer.getStateReligion() == Religion.CATHOLICISM:
- # possible population gain, chance based on the current size
- iRandom = rand(10)
- if (
- 1 + pCity.getPopulation()
- ) <= iRandom: # 1 -> 80%, 2 -> 70%, 3 -> 60% ... 7 -> 20%, 8 -> 10%, 9+ -> 0%
- pCity.changePopulation(1)
- if iPlayer == human():
- message(
- iPlayer,
- text("TXT_KEY_CRUSADE_JERUSALEM_PILGRIMS"),
- color=MessageData.GREEN,
- location=pCity,
- )
- # spread Catholicism if not present
- if not pCity.isHasReligion(Religion.CATHOLICISM):
- pCity.setHasReligion(Religion.CATHOLICISM, True, True, False)
-
- def doDefensiveCrusade(self, iGameTurn):
- if (
- iGameTurn < self.getDefensiveCrusadeLast() + 15
- ): # wait 15 turns between defensive crusades
- return
- if iGameTurn % 5 != rand(5):
- return
- if percentage_chance(33, strict=True):
- return
- lPotentials = [
- iPlayer
- for iPlayer in civilizations().main().ids()
- if self.canDefensiveCrusade(iPlayer, iGameTurn)
- ]
- if lPotentials:
- pPope = gc.getPlayer(Civ.POPE)
- weights = []
- for iPlayer in lPotentials:
- iCatholicFaith = 0
- pPlayer = gc.getPlayer(iPlayer)
- # while faith points matter more, diplomatic relations are also very important
- iCatholicFaith += pPlayer.getFaith()
- iCatholicFaith += 3 * max(0, pPope.AI_getAttitude(iPlayer))
- if iCatholicFaith > 0:
- weights.append(iCatholicFaith)
- else:
- weights.append(0)
-
- iChosenPlayer = choice(lPotentials, weights)
- if iChosenPlayer == human():
- self.callDefensiveCrusadeHuman()
- else:
- self.callDefensiveCrusadeAI(iChosenPlayer)
- self.setDefensiveCrusadeLast(iGameTurn)
-
- def canDefensiveCrusade(self, iPlayer, iGameTurn):
- pPlayer = gc.getPlayer(iPlayer)
- teamPlayer = gc.getTeam(pPlayer.getTeam())
- # only born, flipped and living Catholics can defensive crusade
- if (
- (iGameTurn < civilization(iPlayer).date.birth + 5)
- or not pPlayer.isAlive()
- or pPlayer.getStateReligion() != Religion.CATHOLICISM
- ):
- return False
- # need to have open borders with the Pope
- if not teamPlayer.isOpenBorders(gc.getPlayer(Civ.POPE).getTeam()):
- return False
-
- tPlayerDCMap = tDefensiveCrusadeMap[iPlayer]
- # Can defensive crusade if at war with a non-catholic/orthodox enemy, enemy is not a vassal of a catholic/orthodox civ and has a city in the defensive crusade map
- for iEnemy in civilizations().main().ids():
- pEnemy = gc.getPlayer(iEnemy)
- if (
- teamPlayer.isAtWar(pEnemy.getTeam())
- and civilization(iEnemy).date.birth + 10 < iGameTurn
- ):
- if self.isOrMasterChristian(iEnemy):
- continue
- for pCity in cities().owner(iEnemy).entities():
- if PROVINCES_MAP[pCity.getY()][pCity.getX()] in tPlayerDCMap:
- return True
- return False
-
- def callDefensiveCrusadeHuman(self):
- event_popup(
- 7625,
- text("TXT_KEY_CRUSADE_DEFENSIVE_PROPOSAL_POPUP"),
- text("TXT_KEY_CRUSADE_DEFENSIVE_PROPOSAL"),
- [
- text("TXT_KEY_CRUSADE_DEFENSIVE_PROPOSAL_YES"),
- text("TXT_KEY_CRUSADE_DEFENSIVE_PROPOSAL_NO"),
- ],
- )
-
- def callDefensiveCrusadeAI(self, iPlayer):
- if player().isExisting():
- if (
- team().canContact(teamtype(iPlayer))
- or player().getStateReligion() == Religion.CATHOLICISM
- ): # as you have contact with the Pope by default
- sText = (
- text("TXT_KEY_CRUSADE_DEFENSIVE_AI_MESSAGE") + " " + player(iPlayer).getName()
- )
- message(human(), sText, force=True, color=MessageData.LIGHT_RED)
- self.makeDefensiveCrusadeUnits(iPlayer)
- player(iPlayer).changeFaith(-min(2, player(iPlayer).getFaith()))
-
- def eventApply7625(self, popupReturn):
- iDecision = popupReturn.getButtonClicked()
- if iDecision == 0:
- self.makeDefensiveCrusadeUnits(human())
- player().changeFaith(-min(2, player().getFaith()))
- # else:
- # #pHuman.changeFaith( - min( 1, pHuman.getFaith() ) )
- # pass
-
- def makeDefensiveCrusadeUnits(self, iPlayer):
- pPlayer = gc.getPlayer(iPlayer)
- iFaith = pPlayer.getFaith()
- iBestInfantry = self.getDefensiveCrusadeBestInfantry(iPlayer)
- iBestCavalry = self.getDefensiveCrusadeBestCavalry(iPlayer)
- pCapital = pPlayer.getCapitalCity()
- if pCapital:
- iX = pCapital.getX()
- iY = pCapital.getY()
- else:
- city = cities().owner(iPlayer).random_entry()
- if city is not None:
- iX = city.getX()
- iY = city.getY()
- else:
- return
-
- # Absinthe: interface message for the player
- if gc.getPlayer(iPlayer).isHuman():
- message(
- iPlayer,
- text("TXT_KEY_CRUSADE_DEFENSIVE_HUMAN_MESSAGE"),
- color=MessageData.GREEN,
- location=(iX, iY),
- )
-
- pPlayer.initUnit(
- iBestInfantry, iX, iY, UnitAITypes.UNITAI_ATTACK, DirectionTypes.DIRECTION_SOUTH
- )
- pPlayer.initUnit(
- iBestCavalry, iX, iY, UnitAITypes.UNITAI_ATTACK, DirectionTypes.DIRECTION_SOUTH
- )
-
- # smaller Empires need a bit more help
- if pPlayer.getNumCities() < 6:
- if iBestCavalry == Unit.KNIGHT:
- if percentage_chance(30, strict=True):
- pPlayer.initUnit(
- Unit.BURGUNDIAN_PALADIN,
- iX,
- iY,
- UnitAITypes.UNITAI_ATTACK,
- DirectionTypes.DIRECTION_SOUTH,
- )
- else:
- pPlayer.initUnit(
- iBestCavalry,
- iX,
- iY,
- UnitAITypes.UNITAI_ATTACK,
- DirectionTypes.DIRECTION_SOUTH,
- )
- else:
- pPlayer.initUnit(
- iBestCavalry, iX, iY, UnitAITypes.UNITAI_ATTACK, DirectionTypes.DIRECTION_SOUTH
- )
-
- if iFaith > 4:
- pPlayer.initUnit(
- iBestInfantry, iX, iY, UnitAITypes.UNITAI_ATTACK, DirectionTypes.DIRECTION_SOUTH
- )
- if iFaith > 11:
- if iBestCavalry == Unit.KNIGHT:
- if percentage_chance(30, strict=True):
- pPlayer.initUnit(
- Unit.BURGUNDIAN_PALADIN,
- iX,
- iY,
- UnitAITypes.UNITAI_ATTACK,
- DirectionTypes.DIRECTION_SOUTH,
- )
- else:
- pPlayer.initUnit(
- iBestCavalry,
- iX,
- iY,
- UnitAITypes.UNITAI_ATTACK,
- DirectionTypes.DIRECTION_SOUTH,
- )
- else:
- pPlayer.initUnit(
- iBestCavalry, iX, iY, UnitAITypes.UNITAI_ATTACK, DirectionTypes.DIRECTION_SOUTH
- )
- if iFaith > 20:
- pPlayer.initUnit(
- iBestInfantry, iX, iY, UnitAITypes.UNITAI_ATTACK, DirectionTypes.DIRECTION_SOUTH
- )
- if iFaith > 33:
- pPlayer.initUnit(
- iBestCavalry, iX, iY, UnitAITypes.UNITAI_ATTACK, DirectionTypes.DIRECTION_SOUTH
- )
-
- # extra units for the AI, it is dumb anyway
- if not iPlayer == human():
- pPlayer.initUnit(
- iBestInfantry, iX, iY, UnitAITypes.UNITAI_ATTACK, DirectionTypes.DIRECTION_SOUTH
- )
- pPlayer.initUnit(
- iBestCavalry, iX, iY, UnitAITypes.UNITAI_ATTACK, DirectionTypes.DIRECTION_SOUTH
- )
- if iBestCavalry == Unit.KNIGHT:
- if percentage_chance(30, strict=True):
- pPlayer.initUnit(
- Unit.BURGUNDIAN_PALADIN,
- iX,
- iY,
- UnitAITypes.UNITAI_ATTACK,
- DirectionTypes.DIRECTION_SOUTH,
- )
- else:
- pPlayer.initUnit(
- iBestCavalry,
- iX,
- iY,
- UnitAITypes.UNITAI_ATTACK,
- DirectionTypes.DIRECTION_SOUTH,
- )
- else:
- pPlayer.initUnit(
- iBestCavalry, iX, iY, UnitAITypes.UNITAI_ATTACK, DirectionTypes.DIRECTION_SOUTH
- )
-
- def getDefensiveCrusadeBestInfantry(self, iPlayer):
- pPlayer = gc.getPlayer(iPlayer)
- lUnits = [
- Unit.GRENADIER,
- Unit.MACEMAN,
- Unit.LONG_SWORDSMAN,
- Unit.SWORDSMAN,
- ]
- for iUnit in lUnits:
- if pPlayer.canTrain(getUniqueUnit(iPlayer, iUnit), False, False):
- return getUniqueUnit(iPlayer, iUnit)
- return getUniqueUnit(iPlayer, Unit.AXEMAN)
-
- def getDefensiveCrusadeBestCavalry(self, iPlayer):
- pPlayer = gc.getPlayer(iPlayer)
- lUnits = [
- Unit.CUIRASSIER,
- Unit.KNIGHT,
- Unit.HEAVY_LANCER,
- Unit.LANCER,
- ]
- for iUnit in lUnits:
- if pPlayer.canTrain(getUniqueUnit(iPlayer, iUnit), False, False):
- return getUniqueUnit(iPlayer, iUnit)
- return getUniqueUnit(iPlayer, Unit.SCOUT)
-
- def do1200ADCrusades(self):
- self.setCrusadeInit(0, year(1096))
- self.setCrusadeInit(1, year(1147))
- self.setCrusadeInit(2, year(1187))
-
- def isOrMasterChristian(self, iPlayer):
- pPlayer = gc.getPlayer(iPlayer)
- iReligion = pPlayer.getStateReligion()
- if iReligion in [Religion.CATHOLICISM, Religion.ORTHODOXY]:
- return True
- iMaster = getMaster(iPlayer)
- if iMaster != -1:
- iMasterReligion = gc.getPlayer(iMaster).getStateReligion()
- if iMasterReligion in [Religion.CATHOLICISM, Religion.ORTHODOXY]:
- return True
- return False
diff --git a/Assets/Python/components/Plague.py b/Assets/Python/components/Plague.py
deleted file mode 100644
index 253505ffa..000000000
--- a/Assets/Python/components/Plague.py
+++ /dev/null
@@ -1,634 +0,0 @@
-# Rhye's and Fall of Civilization: Europe - Plague
-
-from CvPythonExtensions import *
-from Consts import MessageData
-from Core import (
- civilization,
- civilizations,
- message,
- location,
- owner,
- text,
- human,
- player,
- turn,
- year,
- city as _city,
- plot as _plot,
- cities,
- plots,
-)
-from CoreTypes import PlagueType, Improvement, Civ
-from PyUtils import percentage, percentage_chance, rand
-
-from RFCUtils import calculateDistance, getPlagueCountdown, isMortalUnit, setPlagueCountdown
-from StoredData import data
-import random
-
-from MiscData import PLAGUE_IMMUNITY
-
-gc = CyGlobalContext()
-
-
-# Absinthe: Black Death is more severe, while the Plague of Justinian is less severe than the others plagues
-iBaseHumanDuration = 10
-iBaseAIDuration = 6
-iNumPlagues = 5
-iConstantinople = 0
-iBlackDeath = 1
-
-
-class Plague:
- def getGenericPlagueDates(self, i):
- return data.lGenericPlagueDates[i]
-
- def setGenericPlagueDates(self, i, iNewValue):
- data.lGenericPlagueDates[i] = iNewValue
-
- def getBadPlague(self):
- return data.bBadPlague
-
- def setBadPlague(self, bBad):
- data.bBadPlague = bBad
-
- def getFirstPlague(self):
- return data.bFirstPlague
-
- def setFirstPlague(self, bFirst):
- data.bFirstPlague = bFirst
-
- #######################################
- ### Main methods (Event-Triggered) ###
- #####################################
-
- def setup(self):
-
- for i in civilizations().majors().ids():
- setPlagueCountdown(i, -PLAGUE_IMMUNITY)
-
- # Sedna17: Set number of GenericPlagues in StoredData
- # 3Miro: Plague 0 strikes France too hard, make it less random and force it to pick Byzantium as starting land
- self.setGenericPlagueDates(0, 28 + rand(5) - 10) # Plagues of Constantinople
- self.setGenericPlagueDates(1, 247 + rand(40) - 20) # 1341 Black Death
- self.setGenericPlagueDates(2, 300 + rand(40) - 20) # Generic recurrence of plague
- self.setGenericPlagueDates(3, 375 + rand(40) - 30) # 1650 Great Plague
- self.setGenericPlagueDates(4, 440 + rand(40) - 30) # 1740 Small Pox
-
- def checkTurn(self, iGameTurn):
-
- for iPlayer in civilizations().ids():
- if gc.getPlayer(iPlayer).isAlive():
- if getPlagueCountdown(iPlayer) > 0:
- setPlagueCountdown(iPlayer, getPlagueCountdown(iPlayer) - 1)
- iPlagueCountDown = getPlagueCountdown(iPlayer)
- if iPlagueCountDown == 2:
- self.preStopPlague(iPlayer, iPlagueCountDown)
- elif iPlagueCountDown == 1:
- self.preStopPlague(iPlayer, iPlagueCountDown)
- elif iPlagueCountDown == 0:
- self.stopPlague(iPlayer)
- elif getPlagueCountdown(iPlayer) < 0:
- setPlagueCountdown(iPlayer, getPlagueCountdown(iPlayer) + 1)
-
- for iPlague in range(iNumPlagues):
- if iGameTurn == self.getGenericPlagueDates(iPlague):
- self.startPlague(iPlague)
-
- # if the plague has stopped too quickly, restart
- if iGameTurn == self.getGenericPlagueDates(iPlague) + 4:
- # not on the first one, that's mostly for one civ anyway
- bFirstPlague = self.getFirstPlague()
- if not bFirstPlague:
- iInfectedCounter = 0
- for iPlayer in civilizations().ids():
- if gc.getPlayer(iPlayer).isAlive() and getPlagueCountdown(iPlayer) > 0:
- iInfectedCounter += 1
- if iInfectedCounter <= 1:
- self.startPlague(iPlague)
-
- def checkPlayerTurn(self, iGameTurn, iPlayer):
- if iPlayer < civilizations().len():
- if getPlagueCountdown(iPlayer) > 0:
- self.processPlague(iPlayer)
-
- def startPlague(self, iPlagueCount):
- iWorstCiv = -1
- iWorstHealth = 100
-
- # Absinthe: specific plagues
- # Plague of Constantinople (that started at Alexandria)
- if iPlagueCount == iConstantinople:
- iWorstCiv = Civ.BYZANTIUM
- self.setFirstPlague(True)
- self.setBadPlague(False)
- # Black Death in the 14th century
- elif iPlagueCount == iBlackDeath:
- self.setFirstPlague(False)
- self.setBadPlague(True)
- # all the others
- else:
- self.setFirstPlague(False)
- self.setBadPlague(False)
-
- # try to find the most unhealthy civ
- if iWorstCiv == -1:
- for iPlayer in civilizations().majors().ids():
- pPlayer = gc.getPlayer(iPlayer)
- if pPlayer.isAlive():
- if self.isVulnerable(iPlayer):
- iHealth = self.calcHealth(iPlayer) - rand(10)
- if iHealth < iWorstHealth:
- iWorstCiv = iPlayer
- iWorstHealth = iHealth
-
- # choose a random civ if we didn't find it
- if iWorstCiv == -1:
- iWorstCiv = civilizations().majors().alive().random().unwrap().id
-
- city = cities().owner(iWorstCiv).random_entry()
- if city is not None:
- self.spreadPlague(iWorstCiv, city)
- self.infectCity(city)
-
- def calcHealth(self, iPlayer):
- pPlayer = gc.getPlayer(iPlayer)
- iTCH = pPlayer.calculateTotalCityHealthiness()
- iTCU = pPlayer.calculateTotalCityUnhealthiness()
- # Absinthe: use average city health instead
- iNumCities = pPlayer.getNumCities()
- if iNumCities == 0:
- return 0 # Avoid zero division error
- iAverageCityHealth = int(
- (10 * (iTCH - iTCU)) / iNumCities
- ) # 10x the average health actually
- return iAverageCityHealth
-
- def isVulnerable(self, iPlayer):
- # Absinthe: based on recent infections and the average city healthiness (also tech immunity should go here if it's ever added to the mod)
- if iPlayer >= civilizations().majors().len():
- if getPlagueCountdown(iPlayer) == 0:
- return True
- else:
- if getPlagueCountdown(iPlayer) == 0:
- # Absinthe: health doesn't matter for the Black Death, everyone is vulnerable
- if self.getBadPlague():
- return True
- else:
- iHealth = self.calcHealth(iPlayer)
- if (
- iHealth < 42
- ): # won't spread at all if the average surplus health in the cities is at least 4.2
- return True
- return False
-
- def spreadPlague(self, iPlayer, city):
- # Absinthe: the Plague of Justinian shouldn't spread to Italy and France, even if it was as deadly as the Black Death
- if iPlayer in [Civ.FRANCE, Civ.POPE] and turn() <= year(632):
- return
-
- # Absinthe: message about the spread
- iHuman = human()
- iHumanTeam = gc.getPlayer(iHuman).getTeam()
- if gc.getPlayer(iHuman).canContact(iPlayer) and iHuman != iPlayer:
- if city != -1 and city.isRevealed(iHumanTeam, False):
- message(
- iHuman,
- text("TXT_KEY_PLAGUE_SPREAD_CITY")
- + " "
- + city.getName()
- + " ("
- + gc.getPlayer(city.getOwner()).getCivilizationAdjective(0)
- + ")!",
- force=True,
- sound="AS2D_PLAGUE",
- button=gc.getBuildingInfo(PlagueType.PLAGUE).getButton(),
- color=MessageData.LIME,
- location=city,
- )
- elif city != -1:
- pCiv = gc.getPlayer(city.getOwner())
- message(
- iHuman,
- text("TXT_KEY_PLAGUE_SPREAD_CIV")
- + " "
- + pCiv.getCivilizationDescription(0)
- + "!",
- force=True,
- sound="AS2D_PLAGUE",
- color=MessageData.LIME,
- )
-
- # Absinthe: this is where the duration is handled for each civ
- # number of cities should be a significant factor, so plague isn't way more deadly for smaller civs
- iHealth = self.calcHealth(iPlayer)
- iHealthDuration = max(min((iHealth / 14), 3), -4) # between -4 and +3
- iCityDuration = min(
- (gc.getPlayer(iPlayer).getNumCities() + 2) / 3, 10
- ) # between 1 and 10 from cities
- if iPlayer == iHuman:
- # Overall duration for the plague is between 4 and 12 (usually between 6-8)
- iValue = (iBaseHumanDuration + iCityDuration - iHealthDuration) / 2
- else:
- # Overall duration for the plague is between 2 and 10 (usually around 5-6)
- iValue = max(
- ((iBaseAIDuration + iCityDuration - iHealthDuration) / 2), 4
- ) # at least 4
- setPlagueCountdown(iPlayer, iValue)
-
- def infectCity(self, city):
- # Absinthe: the Plague of Justinian shouldn't spread to Italy and France, even if it was as deadly as the Black Death
- if city.getOwner() in [Civ.FRANCE, Civ.POPE] and turn() <= year(632):
- return
-
- city.setHasRealBuilding(PlagueType.PLAGUE, True)
- if player(city).isHuman():
- message(
- city.getOwner(),
- text("TXT_KEY_PLAGUE_SPREAD_CITY") + " " + city.getName() + "!",
- force=True,
- sound="AS2D_PLAGUE",
- button=gc.getBuildingInfo(PlagueType.PLAGUE).getButton(),
- color=MessageData.LIME,
- location=location(city),
- )
-
- for plot in plots().surrounding(city, radius=2).entities():
- iImprovement = plot.getImprovementType()
- # Absinthe: chance for reducing the improvement vs. only resetting the process towards the next level to 0
- if iImprovement == Improvement.TOWN: # 100% chance to reduce towns
- plot.setImprovementType(Improvement.VILLAGE)
- elif iImprovement == Improvement.VILLAGE:
- if percentage_chance(75, strict=True):
- plot.setImprovementType(Improvement.HAMLET)
- else:
- plot.setUpgradeProgress(0)
- elif iImprovement == Improvement.HAMLET:
- if percentage_chance(50, strict=True):
- plot.setImprovementType(Improvement.COTTAGE)
- else:
- plot.setUpgradeProgress(0)
- elif iImprovement == Improvement.COTTAGE:
- if percentage_chance(25, strict=True):
- plot.setImprovementType(-1)
- else:
- plot.setUpgradeProgress(0)
-
- # Absinthe: one population is killed by default
- if city.getPopulation() > 1:
- city.changePopulation(-1)
-
- # Absinthe: plagues won't kill units instantly on spread anymore
- # Plague of Justinian deals even less initial damage
- bFirstPlague = self.getFirstPlague()
- if bFirstPlague:
- self.killUnitsByPlague(city, _plot(city), 0, 80, 0)
- else:
- self.killUnitsByPlague(city, _plot(city), 0, 90, 0)
-
- def killUnitsByPlague(self, city, plot, iThreshold, iDamage, iPreserveDefenders):
- iCityOwner = city.getOwner()
- pCityOwner = gc.getPlayer(iCityOwner)
- teamCityOwner = gc.getTeam(pCityOwner.getTeam())
-
- iNumUnitsInAPlot = plot.getNumUnits()
- iHuman = human()
- iCityHealthRate = city.healthRate(False, 0)
-
- if iNumUnitsInAPlot > 0:
- # Absinthe: if we mix up the order of the units, health will be much less static for the chosen defender units
- bOrderChange = percentage_chance(25)
- for j in range(iNumUnitsInAPlot):
- if bOrderChange:
- i = j # we are counting from the strongest unit
- else:
- i = iNumUnitsInAPlot - j - 1 # count back from the weakest unit
- unit = plot.getUnit(i)
- if isMortalUnit(unit) and percentage_chance(
- iThreshold + 5 * iCityHealthRate, strict=True, reverse=True
- ):
- iUnitDamage = unit.getDamage()
- # if some defenders are set to be preserved for some reason, they won't get more damage if they are already under 50%
- if (
- unit.getOwner() == iCityOwner
- and iPreserveDefenders > 0
- and unit.getDomainType() != 0
- and unit.baseCombatStr() > 0
- ): # only units which can really defend
- iPreserveDefenders -= 1
- unit.setDamage(
- max(
- iUnitDamage,
- min(
- 50,
- iUnitDamage
- + iDamage
- - unit.getExperience() / 10
- - 3 * unit.baseCombatStr() / 7,
- ),
- ),
- Civ.BARBARIAN,
- )
- else:
- if unit.baseCombatStr() > 0:
- if (
- unit.getDomainType() == DomainTypes.DOMAIN_SEA
- ): # naval units get less damage, won't be killed unless they were very badly damaged originally
- iShipDamage = iDamage * 93 / 100
- iUnitDamage = max(
- iUnitDamage,
- unit.getDamage()
- + iShipDamage
- - unit.getExperience() / 10
- - 3 * unit.baseCombatStr() / 7,
- )
- else:
- iUnitDamage = max(
- iUnitDamage,
- unit.getDamage()
- + iDamage
- - unit.getExperience() / 10
- - 3 * unit.baseCombatStr() / 7,
- )
- else: # less damage for civilian units - workers, settlers, missionaries, etc.
- iCivilDamage = (
- iDamage * 96 / 100
- ) # workers will be killed with any value here if they are automated (thus moving instead of healing)
- iUnitDamage = max(iUnitDamage, unit.getDamage() + iCivilDamage)
- # kill the unit if necessary
- if iUnitDamage >= 100:
- unit.kill(False, Civ.BARBARIAN)
- if unit.getOwner() == iHuman:
- message(
- iHuman,
- text("TXT_KEY_PLAGUE_PROCESS_UNIT", unit.getName())
- + " "
- + city.getName()
- + "!",
- force=False,
- sound="AS2D_PLAGUE",
- button=gc.getBuildingInfo(PlagueType.PLAGUE).getButton(),
- color=MessageData.LIME,
- location=plot,
- )
- else:
- unit.setDamage(iUnitDamage, Civ.BARBARIAN)
- # if we have many units in the same plot, decrease the damage for every other unit
- iDamage *= 7
- iDamage /= 8
-
- def processPlague(self, iPlayer):
- bBadPlague = self.getBadPlague()
- bFirstPlague = self.getFirstPlague()
- pPlayer = gc.getPlayer(iPlayer)
- iHuman = human()
-
- lInfectedCities = cities().owner(iPlayer).building(PlagueType.PLAGUE).entities()
- lNotInfectedCities = cities().owner(iPlayer).not_building(PlagueType.PLAGUE).entities()
-
- # first spread to close locations
- for city in lInfectedCities:
- # kill citizens
- if city.getPopulation() > 1:
- # the plague itself also greatly contributes to unhealth, so the health rate will almost always be negative
- iHealthRate = city.goodHealth() - city.badHealth(False)
- # always between -5 and +5
- iHealthRate = max(-5, min(5, iHealthRate))
-
- iRandom = percentage()
- iPopSize = city.getPopulation()
- if bBadPlague: # if it's the Black Death, bigger chance for population loss
- bKill = iRandom < 10 + 10 * (iPopSize - 4) - 5 * iHealthRate
- elif (
- bFirstPlague
- ): # if it's the Plague of Justinian, smaller chance for population loss
- bKill = iRandom < 10 * (iPopSize - 4) - 5 * iHealthRate
- else:
- # in "normal" plagues the range for a given pop size is from 10*(size-6) to 10*(size-1)
- # so with size 2: from -40 to 10, size 5: -10 to 40, size 8: 20 to 70, size 12: 60 to 110, size 15: 90 to 140
- bKill = iRandom < 5 + 10 * (iPopSize - 4) - 5 * iHealthRate
- if bKill:
- city.changePopulation(-1)
- if iPlayer == iHuman:
- message(
- iHuman,
- text("TXT_KEY_PLAGUE_PROCESS_CITY", city.getName())
- + " "
- + city.getName()
- + "!",
- force=False,
- sound="AS2D_PLAGUE",
- button=gc.getBuildingInfo(PlagueType.PLAGUE).getButton(),
- color=MessageData.LIME,
- location=city,
- )
-
- # infect vassals
- if getPlagueCountdown(iPlayer) > 2: # don't spread in the last turns
- if city.isCapital():
- for iLoopCiv in civilizations().majors().ids():
- if gc.getTeam(pPlayer.getTeam()).isVassal(iLoopCiv) or gc.getTeam(
- gc.getPlayer(iLoopCiv).getTeam()
- ).isVassal(iPlayer):
- if (
- gc.getPlayer(iLoopCiv).getNumCities() > 0
- ): # this check is needed, otherwise game crashes
- if self.isVulnerable(iLoopCiv):
- capital = gc.getPlayer(iLoopCiv).getCapitalCity()
- self.spreadPlague(iLoopCiv, capital)
- self.infectCity(capital)
-
- # spread plague in 2 distance around the city
- if getPlagueCountdown(iPlayer) > 2: # don't spread in the last turns
- for plot in (
- plots()
- .surrounding(city, radius=2)
- .filter(lambda p: p.isOwned())
- .without(city)
- .entities()
- ):
- if (
- owner(plot, iPlayer)
- and plot.isCity()
- and not _city(plot).isHasRealBuilding(PlagueType.PLAGUE)
- ):
- self.infectCity(_city(plot))
- else:
- if self.isVulnerable(plot.getOwner()):
- self.spreadPlague(plot.getOwner(), -1)
- self.infectCitiesNear(plot.getOwner(), *location(plot))
- # kill units around the city
- for plot in plots().surrounding(city, radius=3).entities():
- iDistance = calculateDistance(city.getX(), city.getY(), *location(plot))
- if iDistance == 0: # City
- self.killUnitsByPlague(city, plot, 20, 40, 2)
- elif not plot.isCity():
- if iDistance == 1:
- if plot.isRoute():
- self.killUnitsByPlague(city, plot, 20, 30, 0)
- else:
- self.killUnitsByPlague(city, plot, 30, 30, 0)
- elif iDistance == 2:
- if plot.isRoute():
- self.killUnitsByPlague(city, plot, 30, 30, 0)
- else:
- self.killUnitsByPlague(city, plot, 40, 30, 0)
- else:
- if plot.getOwner() == iPlayer or not plot.isOwned():
- if plot.isRoute() or plot.isWater():
- self.killUnitsByPlague(city, plot, 40, 30, 0)
-
- # spread by the trade routes
- if getPlagueCountdown(iPlayer) > 2: # don't spread in the last turns
- for iTradeRoute in range(city.getTradeRoutes()):
- loopCity = city.getTradeCity(iTradeRoute)
- if not loopCity.isNone():
- if not loopCity.isHasRealBuilding(PlagueType.PLAGUE):
- iOwner = loopCity.getOwner()
- if iOwner == iPlayer:
- self.infectCity(loopCity)
- if self.isVulnerable(iOwner):
- self.spreadPlague(iOwner, loopCity)
- self.infectCity(loopCity)
-
- # Absinthe: spread to a couple cities which are not too far from already infected ones
- # cities are chosen randomly from the possible targets
- # the maximum number of infections is based on the size of the empire
- if (
- getPlagueCountdown(iPlayer) > 2
- ): # don't spread in the last turns, when preStopPlague is active
- if lNotInfectedCities:
- iTotalCities = pPlayer.getNumCities()
- if iTotalCities > 21:
- iMaxNumInfections = 4
- elif iTotalCities > 14:
- iMaxNumInfections = 3
- elif iTotalCities > 7:
- iMaxNumInfections = 2
- else:
- iMaxNumInfections = 1
-
- # plagues are rather short, always spread at least once
- iNumSpreads = min(1, len(lNotInfectedCities), rand(iMaxNumInfections))
-
- iInfections = 0
- random.shuffle(lNotInfectedCities)
- for targetCity in lNotInfectedCities:
- if [
- city
- for city in lInfectedCities
- if targetCity.isConnectedTo(city)
- and calculateDistance(
- targetCity.getX(), targetCity.getY(), city.getX(), city.getY()
- )
- <= 10
- ]:
- if not targetCity.isHasRealBuilding(PlagueType.PLAGUE):
- # might have changed since the beginning of the function
- self.infectCity(targetCity)
- iInfections += 1
- if iInfections >= iNumSpreads:
- break
-
- # if there are no cities with plague (gifted away, razed on conquest), but the civ itself has plague
- # there is a chance that it will spread to some of your cities
- # the civ would be immune otherwise, basically
- if len(lInfectedCities) == 0:
- if (
- getPlagueCountdown(iPlayer) > 2
- ): # don't spread in the last turns, when preStopPlague is active
- iTotalCities = pPlayer.getNumCities()
- if iTotalCities > 21:
- iMaxNumInfections = 4
- elif iTotalCities > 14:
- iMaxNumInfections = 3
- elif iTotalCities > 7:
- iMaxNumInfections = 2
- else:
- iMaxNumInfections = 1
- iInfections = 0
- _cities = cities().owner(iPlayer).not_building(PlagueType.PLAGUE).entities()
- # TODO fix shuffle
- random.shuffle(_cities)
- for city in _cities:
- if percentage_chance(20, strict=True):
- self.infectCity(city)
- iInfections += 1
- if iInfections >= iMaxNumInfections:
- break
-
- def infectCitiesNear(self, iPlayer, startingX, startingY):
- for city in cities().owner(iPlayer).not_building(PlagueType.PLAGUE).entities():
- if calculateDistance(city.getX(), city.getY(), startingX, startingY) <= 3:
- self.infectCity(city)
-
- def preStopPlague(self, iPlayer, iPlagueCountDown):
- cityList = cities().owner(iPlayer).building(PlagueType.PLAGUE).entities()
- if cityList:
- iRemoveModifier = 0
- iTimeModifier = iPlagueCountDown * 15
- iPopModifier = 0
- iHealthModifier = 0
- # small cities should have a good chance to be chosen
- for city in cityList:
- # iPopModifier: -28, -21, -14, -7, 0, 7, 14, 21, 28, 35, etc.
- iPopModifier = 7 * city.getPopulation() - 35
- iHealthModifier = 5 * city.healthRate(False, 0)
- if percentage_chance(
- 100 - iTimeModifier - iPopModifier + iHealthModifier - iRemoveModifier,
- strict=True,
- ):
- city.setHasRealBuilding(PlagueType.PLAGUE, False)
- iRemoveModifier += 5 # less chance for each city which already quit
-
- def stopPlague(self, iPlayer):
- setPlagueCountdown(iPlayer, -PLAGUE_IMMUNITY)
- for city in cities().owner(iPlayer).entities():
- city.setHasRealBuilding(PlagueType.PLAGUE, False)
-
- def onCityAcquired(self, iOldOwner, iNewOwner, city):
- if city.isHasRealBuilding(PlagueType.PLAGUE):
- # TODO when plague will not kill units anymore, remove this
- # Absinthe: the Plague of Justinian shouldn't spread to Italy and France, even if it was as deadly as the Black Death
- if city.getOwner() in [Civ.FRANCE, Civ.POPE] and turn() <= year(632):
- city.setHasRealBuilding(PlagueType.PLAGUE, False)
- return
-
- # only if it's not a recently born civ
- if turn() > civilization(iNewOwner).date.birth + PLAGUE_IMMUNITY:
- # reinfect the human player if conquering plagued cities
- if iNewOwner == human():
- # if > 0 do nothing, if < 0 skip immunity and restart the plague, if == 0 start the plague
- if getPlagueCountdown(iNewOwner) <= 0:
- self.spreadPlague(iNewOwner, -1)
- for cityNear in cities().owner(iNewOwner).entities():
- if not cityNear.isHasRealBuilding(PlagueType.PLAGUE):
- if (
- calculateDistance(
- city.getX(), city.getY(), cityNear.getX(), cityNear.getY()
- )
- <= 3
- ):
- if percentage_chance(50, strict=True):
- self.infectCity(cityNear)
- # no reinfect for the AI, only infect
- else:
- # if > 0 do nothing, if < 0 keep immunity and remove plague from the city, if == 0 start the plague
- if getPlagueCountdown(iNewOwner) == 0:
- self.spreadPlague(iNewOwner, -1)
- for cityNear in cities().owner(iNewOwner).entities():
- if not cityNear.isHasRealBuilding(PlagueType.PLAGUE):
- if (
- calculateDistance(
- city.getX(), city.getY(), cityNear.getX(), cityNear.getY()
- )
- <= 3
- ):
- if percentage_chance(50, strict=True):
- self.infectCity(cityNear)
- elif getPlagueCountdown(iNewOwner) < 0:
- city.setHasRealBuilding(PlagueType.PLAGUE, False)
- else:
- city.setHasRealBuilding(PlagueType.PLAGUE, False)
-
- def onCityRazed(self, city, iNewOwner):
- pass
diff --git a/Assets/Python/components/Provinces.py b/Assets/Python/components/Provinces.py
deleted file mode 100644
index 83b16ff0d..000000000
--- a/Assets/Python/components/Provinces.py
+++ /dev/null
@@ -1,88 +0,0 @@
-from Core import get_scenario, civilization, civilizations, player, year, cities
-from RFCUtils import refreshStabilityOverlay
-from ProvinceMapData import PROVINCES_MAP
-from CoreTypes import Province, Event, Scenario, ProvinceType
-
-
-class ProvinceManager:
- def setup(self):
- # set the initial situation for all players
- for civ in civilizations().main():
- for type, provinces in civ.location.provinces.items():
- for province in provinces:
- civ.player.setProvinceType(province, type)
- # update provinces for the 1200 AD Scenario
- if get_scenario() == Scenario.i1200AD:
- for civ in civilizations().main():
- if civ.date.birth < year(1200):
- self.onSpawn(civ.id)
-
- def checkTurn(self, iGameTurn):
- for civ in civilizations():
- events = civ.event.provinces.get(Event.ON_DATETURN)
- if events is not None:
- for dateturn, provinces in events.items():
- if iGameTurn == year(dateturn):
- for province, province_type in provinces:
- civ.player.setProvinceType(province, province_type)
-
- def onCityBuilt(self, iPlayer, x, y):
- if iPlayer not in civilizations().main().ids():
- return
- civ = civilization(iPlayer)
- province = PROVINCES_MAP[y][x]
- if civ.player.getProvinceType(province) == ProvinceType.POTENTIAL:
- civ.player.setProvinceType(province, ProvinceType.HISTORICAL)
- refreshStabilityOverlay()
-
- def onCityAcquired(self, owner, iPlayer, city, bConquest, bTrade):
- if iPlayer not in civilizations().main().ids():
- return
- civ = civilization(iPlayer)
- province = city.getProvince()
- if civ.player.getProvinceType(province) == ProvinceType.POTENTIAL:
- civ.player.setProvinceType(province, ProvinceType.HISTORICAL)
- refreshStabilityOverlay()
-
- def onCityRazed(self, iOwner, iPlayer, city):
- pass
-
- def updatePotential(self, iPlayer):
- civ = civilization(iPlayer)
- for city in cities().owner(iPlayer).entities():
- province = city.getProvince()
- if civ.player.getProvinceType(province) == ProvinceType.POTENTIAL:
- civ.player.setProvinceType(province, ProvinceType.HISTORICAL)
- refreshStabilityOverlay()
-
- def onRespawn(self, iPlayer):
- # Absinthe: reset the original potential provinces, but only if they wasn't changed to something entirely different later on
- civ = civilization(iPlayer)
- for province in civ.location.provinces[ProvinceType.HISTORICAL]:
- if civ.player.getProvinceType(province) == ProvinceType.HISTORICAL:
- civ.player.setProvinceType(province, ProvinceType.POTENTIAL)
-
- # Absinthe: special respawn conditions
- events = civ.event.provinces.get(Event.ON_RESPAWN)
- if events is not None:
- for province, province_type in events:
- civ.player.setProvinceType(province, province_type)
-
- def resetProvinces(self, iPlayer):
- # Absinthe: keep in mind that this will reset all to the initial status, so won't take later province changes into account
- civ = civilization(iPlayer)
- for province in Province:
- civ.player.setProvinceType(province, ProvinceType.NONE)
-
- for type, provinces in civ.location.provinces.items():
- for province in provinces:
- civ.player.setProvinceType(province, type)
-
- def onSpawn(self, iPlayer):
- # when a new nations spawns, old nations in the region should lose some of their provinces
- events = civilization(iPlayer).event.provinces.get(Event.ON_SPAWN)
- if events is not None:
- for civ, province, province_type in events:
- player(civ).setProvinceType(province, province_type)
-
- refreshStabilityOverlay()
diff --git a/Assets/Python/components/Religions.py b/Assets/Python/components/Religions.py
deleted file mode 100644
index 70a4b0726..000000000
--- a/Assets/Python/components/Religions.py
+++ /dev/null
@@ -1,1124 +0,0 @@
-from CvPythonExtensions import (
- CyGlobalContext,
- EventContextTypes,
- InterfaceMessageTypes,
- UnitAITypes,
- DirectionTypes,
-)
-from Consts import MessageData
-from Core import (
- civilization,
- civilizations,
- event_popup,
- human,
- location,
- player,
- text,
- message,
- year,
- cities,
- units,
-)
-from CoreTypes import (
- Building,
- Civ,
- City,
- Civic,
- Province,
- StabilityCategory,
- Religion,
- Technology,
- Unit,
- Wonder,
-)
-from LocationsData import CITIES
-import Popup
-from ProvinceMapData import PROVINCES_MAP
-from RFCUtils import getBaseBuilding, prosecute
-from ReligionData import RELIGIOUS_BUILDINGS
-from StoredData import data
-from PyUtils import choice, percentage, percentage_chance, rand
-
-from ReligionData import RELIGIOUS_WONDERS
-
-gc = CyGlobalContext()
-
-
-### Regions to spread religion ###
-tSpain = [
- Province.LEON,
- Province.GALICIA,
- Province.ARAGON,
- Province.CATALONIA,
- Province.CASTILE,
- Province.LA_MANCHA,
- Province.ANDALUSIA,
- Province.VALENCIA,
-]
-tPoland = [
- Province.GREATER_POLAND,
- Province.LESSER_POLAND,
- Province.MASOVIA,
- Province.SILESIA,
- Province.SUVALKIJA,
- Province.BREST,
- Province.POMERANIA,
- Province.GALICJA,
-]
-tGermany = [
- Province.LORRAINE,
- Province.FRANCONIA,
- Province.BAVARIA,
- Province.SWABIA,
-]
-tWestAfrica = [
- Province.TETOUAN,
- Province.MOROCCO,
- Province.MARRAKESH,
- Province.FEZ,
- Province.ORAN,
-]
-tNorthAfrica = [
- Province.ALGIERS,
- Province.IFRIQIYA,
- Province.TRIPOLITANIA,
- Province.CYRENAICA,
-]
-tBalkansAndAnatolia = [
- Province.CONSTANTINOPLE,
- Province.THRACE,
- Province.OPSIKION,
- Province.PAPHLAGONIA,
- Province.THRAKESION,
- Province.CILICIA,
- Province.ANATOLIKON,
- Province.ARMENIAKON,
- Province.CHARSIANON,
-]
-tCentralEurope = [
- Province.GREATER_POLAND,
- Province.LESSER_POLAND,
- Province.MASOVIA,
- Province.GALICJA,
- Province.BREST,
- Province.SUVALKIJA,
- Province.LITHUANIA,
- Province.PRUSSIA,
- Province.POMERANIA,
- Province.SAXONY,
- Province.BRANDENBURG,
- Province.HOLSTEIN,
- Province.DENMARK,
- Province.BAVARIA,
- Province.SWABIA,
- Province.BOHEMIA,
- Province.MORAVIA,
- Province.SILESIA,
- Province.HUNGARY,
- Province.TRANSYLVANIA,
- Province.UPPER_HUNGARY,
- Province.PANNONIA,
- Province.SLAVONIA,
- Province.CARINTHIA,
- Province.AUSTRIA,
-]
-tMaghrebAndalusia = [
- Province.TETOUAN,
- Province.MOROCCO,
- Province.MARRAKESH,
- Province.FEZ,
- Province.ORAN,
- Province.ALGIERS,
- Province.IFRIQIYA,
- Province.TRIPOLITANIA,
- Province.CYRENAICA,
- Province.LA_MANCHA,
- Province.ANDALUSIA,
- Province.VALENCIA,
-]
-tBulgariaBalkans = [
- Province.MOESIA,
- Province.MACEDONIA,
- Province.SERBIA,
- Province.WALLACHIA,
-]
-tOldRus = [
- Province.NOVGOROD,
- Province.ROSTOV,
- Province.POLOTSK,
- Province.SMOLENSK,
- Province.MINSK,
- Province.CHERNIGOV,
- Province.KIEV,
- Province.PEREYASLAVL,
- Province.SLOBODA,
-]
-tSouthScandinavia = [
- Province.DENMARK,
- Province.GOTALAND,
- Province.SKANELAND,
- Province.VESTFOLD,
- Province.NORWAY,
-]
-tHungary = [
- Province.HUNGARY,
- Province.TRANSYLVANIA,
- Province.UPPER_HUNGARY,
- Province.PANNONIA,
-]
-
-
-class Religions:
-
- ##################################################
- ### Secure storage & retrieval of script data ###
- ################################################
-
- def getReformationActive(self):
- return data.bReformationActive
-
- def setReformationActive(self, bNewValue):
- data.bReformationActive = bNewValue
-
- def getReformationHitMatrix(self, iCiv):
- return data.lReformationHitMatrix[iCiv]
-
- def setReformationHitMatrix(self, iCiv, bNewValue):
- data.lReformationHitMatrix[iCiv] = bNewValue
-
- def getReformationHitMatrixAll(self):
- return data.lReformationHitMatrix
-
- def getCounterReformationActive(self):
- return data.bCounterReformationActive
-
- def setCounterReformationActive(self, bNewValue):
- data.bCounterReformationActive = bNewValue
-
- #######################################
- ### Main methods (Event-Triggered) ###
- #####################################
-
- def setup(self):
- gc.getPlayer(Civ.BYZANTIUM).changeFaith(10)
- gc.getPlayer(Civ.OTTOMAN).changeFaith(20)
-
- def checkTurn(self, iGameTurn):
- # Absinthe: Spreading religion in a couple preset dates
- if iGameTurn == year(700) - 2:
- # Spread Judaism to Toledo
- self.spreadReligion(CITIES[City.TOLEDO], Religion.JUDAISM)
- # Spread Islam to a random city in Africa
- tCity = self.selectRandomCityRegion(tNorthAfrica, Religion.ISLAM)
- if tCity:
- self.spreadReligion(tCity, Religion.ISLAM)
- elif iGameTurn == year(700) + 2:
- # Spread Judaism and Islam to a random city in Africa
- tCity = self.selectRandomCityRegion(tWestAfrica, Religion.ISLAM)
- if tCity:
- self.spreadReligion(tCity, Religion.ISLAM)
- tCity = self.selectRandomCityRegion(tWestAfrica, Religion.JUDAISM)
- if tCity:
- self.spreadReligion(tCity, Religion.JUDAISM)
- elif iGameTurn == year(900):
- # Spread Judaism to another city in Spain
- tCity = self.selectRandomCityRegion(tSpain, Religion.JUDAISM)
- if tCity:
- self.spreadReligion(tCity, Religion.JUDAISM)
- elif iGameTurn == year(1000):
- # Spread Judaism to a city in France/Germany
- tCity = self.selectRandomCityRegion(tGermany, Religion.JUDAISM)
- if tCity:
- self.spreadReligion(tCity, Religion.JUDAISM)
- # Spread Islam to another city in Africa
- tCity = self.selectRandomCityRegion(tNorthAfrica, Religion.ISLAM)
- if tCity:
- self.spreadReligion(tCity, Religion.ISLAM)
- elif iGameTurn == year(1101):
- # Spread Judaism to a couple towns in Poland
- tCity = self.selectRandomCityRegion(tPoland, Religion.JUDAISM)
- if tCity:
- self.spreadReligion(tCity, Religion.JUDAISM)
- elif iGameTurn == year(1200):
- # Spread Judaism to a couple towns in Poland
- tCity = self.selectRandomCityRegion(tPoland, Religion.JUDAISM)
- if tCity:
- self.spreadReligion(tCity, Religion.JUDAISM)
- elif year(1299) < iGameTurn < year(1350) and iGameTurn % 3 == 0:
- # Spread Islam to a couple cities in Anatolia before the Ottoman spawn
- tCity = self.selectRandomCityRegion(tBalkansAndAnatolia, Religion.ISLAM)
- if tCity:
- self.spreadReligion(tCity, Religion.ISLAM)
- elif iGameTurn == year(1401):
- # Spread Judaism to a couple towns in Poland
- tCity = self.selectRandomCityRegion(tPoland, Religion.JUDAISM)
- if tCity:
- self.spreadReligion(tCity, Religion.JUDAISM)
-
- # Absinthe: Spreading Judaism in random dates
- # General 6% chance to spread Jews to a random city in every third turn
- if year(800) < iGameTurn < year(1700) and iGameTurn % 3 == 0:
- if percentage_chance(6, strict=True):
- tCity = cities().all().random_entry()
- if tCity is not None:
- self.spreadReligion(tCity, Religion.JUDAISM)
-
- # Additional 11% chance to spread Jews to a random Central European city in every third turn
- if year(1000) < iGameTurn < year(1500) and iGameTurn % 3 == 1:
- if percentage_chance(11, strict=True):
- tCity = self.selectRandomCityRegion(tCentralEurope, Religion.JUDAISM)
- if tCity:
- self.spreadReligion(tCity, Religion.JUDAISM)
-
- # Absinthe: Encouraging desired religion spread in a couple areas (mostly for Islam and Orthodoxy)
- # Maghreb and Cordoba:
- if year(700) < iGameTurn < year(800) and iGameTurn % 2 == 1:
- if percentage_chance(32, strict=True):
- tCity = self.selectRandomCityRegion(tMaghrebAndalusia, Religion.ISLAM, True)
- if tCity:
- self.spreadReligion(tCity, Religion.ISLAM)
- if year(800) < iGameTurn < year(1200) and iGameTurn % 3 == 2:
- if percentage_chance(28, strict=True):
- tCity = self.selectRandomCityRegion(tMaghrebAndalusia, Religion.ISLAM, True)
- if tCity:
- self.spreadReligion(tCity, Religion.ISLAM)
-
- # Bulgaria and Balkans:
- if year(700) < iGameTurn < year(800) and iGameTurn % 3 == 1:
- if percentage_chance(25, strict=True):
- tCity = self.selectRandomCityRegion(tBulgariaBalkans, Religion.ORTHODOXY, True)
- if tCity:
- self.spreadReligion(tCity, Religion.ORTHODOXY)
- if year(800) < iGameTurn < year(1000) and iGameTurn % 4 == 1:
- if percentage_chance(15, strict=True):
- tCity = self.selectRandomCityRegion(tBulgariaBalkans, Religion.ORTHODOXY, True)
- if tCity:
- self.spreadReligion(tCity, Religion.ORTHODOXY)
- # Old Rus territories:
- if year(852) < iGameTurn < year(1300) and iGameTurn % 4 == 3:
- if percentage_chance(25, strict=True):
- tCity = self.selectRandomCityRegion(tOldRus, Religion.ORTHODOXY, True)
- if tCity:
- self.spreadReligion(tCity, Religion.ORTHODOXY)
-
- # Extra chance for early Orthodoxy spread in Novgorod:
- if year(852) < iGameTurn < year(960) and iGameTurn % 5 == 2:
- if percentage_chance(34, strict=True):
- tCity = self.selectRandomCityRegion(
- [Province.NOVGOROD, Province.POLOTSK, Province.SMOLENSK],
- Religion.ORTHODOXY,
- True,
- )
- if tCity:
- self.spreadReligion(tCity, Religion.ORTHODOXY)
- # Hungary:
- if year(960) < iGameTurn < year(1200) and iGameTurn % 4 == 2:
- if percentage_chance(21, strict=True):
- tCity = self.selectRandomCityRegion(tHungary, Religion.CATHOLICISM, True)
- if tCity:
- self.spreadReligion(tCity, Religion.CATHOLICISM)
-
- # Scandinavia:
- if year(1000) < iGameTurn < year(1300) and iGameTurn % 4 == 0:
- if percentage_chance(24, strict=True):
- tCity = self.selectRandomCityRegion(tSouthScandinavia, Religion.CATHOLICISM, True)
- if tCity:
- self.spreadReligion(tCity, Religion.CATHOLICISM)
-
- # Absinthe: Persecution cooldown
- for i in civilizations().majors().ids():
- pPlayer = gc.getPlayer(i)
- if pPlayer.getProsecutionCount() > 0:
- pPlayer.changeProsecutionCount(-1)
- # Religious Law means a bigger decrease in persecution points
- if pPlayer.getCivics(1) == Civic.RELIGIOUS_LAW:
- if pPlayer.getProsecutionCount() > 0:
- pPlayer.changeProsecutionCount(-1)
-
- # Absinthe: Resettle Jewish refugees
- iRefugies = gc.getMinorReligionRefugies()
- for i in range(iRefugies):
- self.resettleRefugies()
- gc.setMinorReligionRefugies(0)
-
- # Absinthe: Benefits for Catholics from the Pope
- catholic_civs = civilizations().main().catholic().open_borders(Civ.POPE)
- # Gold gift
- if iGameTurn >= year(752):
- if iGameTurn > year(1648): # End of religious wars
- iDivBy = 14
- elif iGameTurn > year(1517): # Protestantism
- iDivBy = 11
- elif iGameTurn > year(1053): # Schism
- iDivBy = 6
- else:
- iDivBy = 9
- if (
- iGameTurn % iDivBy == 3
- and player(Civ.POPE).getGold() > 100
- and percentage_chance(90)
- ):
- weights = []
- for civ in catholic_civs:
- iCatholicFaith = 0
- # Relations with the Pope are much more important here
- iCatholicFaith += civ.player.getFaith()
- iCatholicFaith += 8 * max(0, player(Civ.POPE).AI_getAttitude(civ.id))
- if iCatholicFaith > 0:
- weights.append(iCatholicFaith)
- else:
- weights.append(0)
-
- if catholic_civs:
- iChosenPlayer = choice(catholic_civs, weights)
- if iGameTurn < 100:
- iGift = min(
- player(Civ.POPE).getGold() / 5, 40
- ) # between 20-40, based on the Pope's wealth
- else:
- iGift = min(
- player(Civ.POPE).getGold() / 2, 80
- ) # between 50-80, based on the Pope's wealth
- civilization(Civ.POPE).send_gold(iChosenPlayer, iGift)
-
- if iChosenPlayer.is_human():
- sText = text("TXT_KEY_FAITH_GOLD_GIFT", iGift)
- message(civ.id, sText, color=MessageData.BLUE)
- # Free religious building
- if iGameTurn > year(800): # The crowning of Charlemagne
- if iGameTurn > year(1648): # End of religious wars
- iDivBy = 21
- elif iGameTurn > year(1517): # Protestantism
- iDivBy = 14
- elif iGameTurn > year(1053): # Schism
- iDivBy = 8
- else:
- iDivBy = 11
- if iGameTurn % iDivBy == 2 and percentage_chance(80, strict=True):
- weights = []
- iJerusalemOwner = (
- gc.getMap().plot(*CITIES[City.JERUSALEM]).getPlotCity().getOwner()
- )
- for civ in catholic_civs:
- iCatholicFaith = 0
- # Faith points are the deciding factor for buildings
- iCatholicFaith += civ.player.getFaith()
- iCatholicFaith += 2 * max(0, player(Civ.POPE).AI_getAttitude(civ.id))
- if (
- civ.id == iJerusalemOwner
- ): # The Catholic owner of Jerusalem has a greatly improved chance
- iCatholicFaith += 30
- if iCatholicFaith > 0:
- weights.append(iCatholicFaith)
-
- if catholic_civs:
- iChosenPlayer = choice(catholic_civs, weights)
- iCatholicBuilding = Building.CATHOLIC_TEMPLE
- # No chance for monastery if the selected player knows the Scientific Method tech (which obsoletes monasteries), otherwise 50-50% for temple and monastery
- if not iChosenPlayer.has_tech(
- Technology.SCIENTIFIC_METHOD
- ) and percentage_chance(50):
- iCatholicBuilding = Building.CATHOLIC_MONASTERY
- self.buildInRandomCity(
- iChosenPlayer.id, iCatholicBuilding, Religion.CATHOLICISM
- )
- # Free technology
- if iGameTurn > year(843): # Treaty of Verdun, the Carolingian Empire divided into 3 parts
- if (
- iGameTurn % 13 == 4
- ): # checked every 13th turn - won't change it as the game progresses, as the number of available techs will already change with the number of Catholic civs
- weights = []
- for civ in catholic_civs:
- iCatholicFaith = 0
- # Faith points are the deciding factor for techs
- iCatholicFaith += civ.player.getFaith()
- iCatholicFaith += 2 * max(0, player(Civ.POPE).AI_getAttitude(civ.id))
- if iCatholicFaith > 0:
- weights.append(iCatholicFaith)
- else:
- weights.append(0)
-
- if catholic_civs:
- iChosenPlayer = choice(catholic_civs, weights)
- # look for techs which are known by the Pope but unknown to the chosen civ
- for tech in Technology:
- if (
- civilization(Civ.POPE).has_tech(tech)
- and not iChosenPlayer.has_tech(tech)
- and iChosenPlayer.player.getFaith() + 20 > rand(70)
- ):
- # chance for actually giving this tech, based on faith points
- # +20, to have a real chance with low faith points as well
- iChosenPlayer.add_tech(tech, annoncing=True)
- if iChosenPlayer.is_human():
- sText = text(
- "TXT_KEY_FAITH_TECH_GIFT",
- gc.getTechInfo(tech).getDescription(),
- )
- message(
- iChosenPlayer.id, sText, force=True, color=MessageData.BLUE
- )
- # don't continue if a tech was already given - this also means that there is bigger chance for getting a tech if the chosen civ is multiple techs behind
- break
-
- if iGameTurn % 6 == 3:
- self.update_pope_techs(catholic_civs)
-
- # Absinthe: Reformation
- if self.getCounterReformationActive():
- self.doCounterReformation()
- if self.getReformationActive():
- self.reformationArrayChoice()
- if self.getReformationActive():
- self.reformationArrayChoice()
- if self.getReformationActive():
- self.reformationArrayChoice()
-
- def update_pope_techs(self, catholic_civs):
- # Absinthe: Pope gets all techs known by at least 3 Catholic civs
- catholic_civs = civilizations().main().catholic()
- for tech in Technology:
- if not civilization(Civ.POPE).has_tech(tech):
- counter = 0
- for civ in catholic_civs:
- if civ.has_tech(tech):
- counter += 1
- if counter >= 3:
- civilization(Civ.POPE).add_tech(tech)
- break
-
- def onReligionSpread(self, iReligion, iPlayer):
- pPlayer = gc.getPlayer(iPlayer)
- if pPlayer.getStateReligion() == iReligion:
- pPlayer.changeFaith(1)
- else:
- pPlayer.changeFaith(-1)
-
- def onBuildingBuilt(seld, iPlayer, iBuilding):
- pPlayer = gc.getPlayer(iPlayer)
- iStateReligion = pPlayer.getStateReligion()
- if iStateReligion != -1:
- if iBuilding in RELIGIOUS_BUILDINGS[iStateReligion]:
- pPlayer.changeFaith(1)
- if iBuilding in [
- Building.CATHOLIC_CATHEDRAL,
- Building.ORTHODOX_CATHEDRAL,
- Building.ISLAMIC_CATHEDRAL,
- Building.PROTESTANT_CATHEDRAL,
- Wonder.KAZIMIERZ,
- ]:
- pPlayer.changeFaith(3)
- if pPlayer.countNumBuildings(Wonder.PALAIS_DES_PAPES) > 0:
- pPlayer.changeFaith(1)
-
- # Absinthe: Wonders: Mont Saint-Michel wonder effect
- if getBaseBuilding(iBuilding) in [Building.WALLS, Building.CASTLE]:
- if pPlayer.countNumBuildings(Wonder.MONT_SAINT_MICHEL) > 0:
- pPlayer.changeFaith(1)
- if iBuilding in RELIGIOUS_WONDERS:
- pPlayer.changeFaith(4)
- if pPlayer.countNumBuildings(Wonder.PALAIS_DES_PAPES) > 0:
- pPlayer.changeFaith(1)
- if iStateReligion != Religion.JUDAISM and iBuilding == Wonder.KAZIMIERZ:
- pPlayer.changeFaith(-min(1, pPlayer.getFaith()))
- # Kazimierz tries to spread Judaism to a couple new cities
- cityList = cities().owner(iPlayer).entities()
- iJewCityNum = int(max((len(cityList) + 2) / 3 + 1, 3))
- # number of tries are based on number of cities, but at least 3
- for i in range(iJewCityNum):
- city = choice(cityList)
- if not city.isHasReligion(Religion.JUDAISM):
- city.setHasReligion(Religion.JUDAISM, True, True, False)
- # Adds Jewish Quarter to all cities which already has Judaism (including the ones where it just spread)
- for city in cityList:
- if city.isHasReligion(Religion.JUDAISM):
- city.setHasRealBuilding(Building.JEWISH_QUARTER, True)
-
- def selectRandomCityRegion(self, tProvinces, iReligionToSpread, bNoSpreadWithReligion=False):
- cityList = []
- for iPlayer in civilizations().ids():
- if not gc.getPlayer(iPlayer).isAlive():
- continue
- for city in cities().owner(iPlayer).entities():
- if PROVINCES_MAP[city.getY()][city.getX()] in tProvinces:
- # do not try to spread to cities which already have the desired religion
- if not city.isHasReligion(iReligionToSpread):
- if bNoSpreadWithReligion:
- # check if there is any religion already present in the city
- bAlreadyHasReligion = False
- for iReligion in range(len(Religion)):
- if city.isHasReligion(iReligion):
- bAlreadyHasReligion = True
- break
- if not bAlreadyHasReligion:
- cityList.append(city)
- else:
- cityList.append(city)
- if cityList:
- city = choice(cityList)
- return (city.getX(), city.getY())
- return False
-
- def spreadReligion(self, tPlot, iReligion):
- x, y = location(tPlot)
- pPlot = gc.getMap().plot(x, y)
- if pPlot.isCity():
- pPlot.getPlotCity().setHasReligion(
- iReligion, True, True, False
- ) # Absinthe: puts the given religion into this city, with interface message
-
- def buildInRandomCity(self, iPlayer, iBuilding, iReligion):
- cityList = []
- for city in cities().owner(iPlayer).entities():
- if not city.hasBuilding(iBuilding) and city.isHasReligion(iReligion):
- cityList.append(city)
- if cityList:
- city = choice(cityList)
- city.setHasRealBuilding(iBuilding, True)
- gc.getPlayer(iPlayer).changeFaith(1)
- if human() == iPlayer:
- sText = (
- text("TXT_KEY_FAITH_BUILDING1")
- + " "
- + gc.getBuildingInfo(iBuilding).getDescription()
- + " "
- + text("TXT_KEY_FAITH_BUILDING2")
- + " "
- + city.getName()
- )
- message(
- iPlayer,
- sText,
- button=gc.getBuildingInfo(iBuilding).getButton(),
- color=MessageData.BLUE,
- location=city,
- )
-
- # Absinthe: free religious revolution
- def onPlayerChangeAllCivics(self, iPlayer, lNewCivics, lOldCivics):
- # free religion change when switching away from Paganism
- if lOldCivics[4] == Civic.PAGANISM:
- if lNewCivics[4] in [
- Civic.STATE_RELIGION,
- Civic.THEOCRACY,
- Civic.ORGANIZED_RELIGION,
- ]:
- if iPlayer == human():
- # check the available religions
- religionList = []
- for city in cities().owner(iPlayer).entities():
- for iReligion in range(gc.getNumReligionInfos()):
- if iReligion not in religionList:
- if city.isHasReligion(iReligion):
- religionList.append(iReligion)
- if (
- len(religionList) == gc.getNumReligionInfos()
- ): # no need to check any further, if we already have all religions in the list
- break
- if (
- len(religionList) == gc.getNumReligionInfos()
- ): # no need to check any further, if we already have all religions in the list
- break
- data.lReligionChoices = religionList
- # no popup if no available religions
- if religionList:
- self.showFreeRevolutionPopup(iPlayer, religionList)
- elif iPlayer < civilizations().main().len():
- iBestReligionPoint = 0
- iBestReligion = Religion.CATHOLICISM
- # loop through all religions
- for iReligion in range(gc.getNumReligionInfos()):
- iReligionPoint = 0
- # check cities for religions and holy cities
- for city in cities().owner(iPlayer).entities():
- if city.isHasReligion(iReligion):
- iReligionPoint += 10
- if city.isHolyCityByType(iReligion):
- iReligionPoint += 1000
- spread_factor = civilization(iPlayer).religion.spreading_threshold[
- iReligion
- ]
- if spread_factor < 60:
- iReligionPoint = (iReligionPoint * 5) / 10
- elif spread_factor < 100:
- iReligionPoint = (iReligionPoint * 8) / 10
- elif spread_factor > 200:
- iReligionPoint = (iReligionPoint * 12) / 10
- # update if better
- if iReligionPoint > iBestReligionPoint:
- iBestReligionPoint = iReligionPoint
- iBestReligion = iReligion
- # convert to the best religion
- pPlayer = gc.getPlayer(iPlayer)
- pPlayer.convertForFree(iBestReligion)
-
- # Absinthe: free religion change popup
- def showFreeRevolutionPopup(self, iPlayer, religionList):
- """Possibility for the human player to select a religion anarchy-free."""
- popup = Popup.PyPopup(7629, EventContextTypes.EVENTCONTEXT_ALL)
- popup.setHeaderString("Religious Revolution")
- popup.setBodyString("Choose the religion you want to adopt as your State Religion:")
- for iReligion in religionList:
- strIcon = gc.getReligionInfo(iReligion).getType()
- strIcon = "[%s]" % (strIcon.replace("RELIGION_", "ICON_"))
- strButtonText = "%s %s" % (text(strIcon), gc.getReligionInfo(iReligion).getText())
- popup.addButton(strButtonText)
- popup.addButton("We don't want to adopt a State Religion right now")
- popup.launch(False)
-
- # Absinthe: event of the free religion change popup
- def eventApply7629(self, playerID, popupReturn):
- """Free religious revolution."""
- # the last option is the no change option
- player(playerID).convertForFree(data.lReligionChoices[popupReturn.getButtonClicked()])
-
- # REFORMATION
-
- def eventApply7624(self, popupReturn):
- iHuman = human()
- if popupReturn.getButtonClicked() == 0:
- self.reformationyes(iHuman)
- elif popupReturn.getButtonClicked() == 1:
- self.reformationno(iHuman)
-
- def onTechAcquired(self, iTech, iPlayer):
- if iTech == Technology.PRINTING_PRESS:
- if gc.getPlayer(iPlayer).getStateReligion() == Religion.CATHOLICISM:
- if not gc.getGame().isReligionFounded(Religion.PROTESTANTISM):
- gc.getPlayer(iPlayer).foundReligion(
- Religion.PROTESTANTISM, Religion.PROTESTANTISM, False
- )
- gc.getGame().getHolyCity(Religion.PROTESTANTISM).setNumRealBuilding(
- Building.PROTESTANT_SHRINE, 1
- )
- self.setReformationActive(True)
- self.reformationchoice(iPlayer)
- self.reformationOther(Civ.INDEPENDENT)
- self.reformationOther(Civ.INDEPENDENT_2)
- self.reformationOther(Civ.INDEPENDENT_3)
- self.reformationOther(Civ.INDEPENDENT_4)
- self.reformationOther(Civ.BARBARIAN)
- self.setReformationHitMatrix(iPlayer, 2)
- self.spread_reform_to_neighbour(iPlayer)
-
- def spread_reform_to_neighbour(self, player_id):
- for neighbour in civilization(player_id).location.reformation_neighbours:
- if self.getReformationHitMatrix(neighbour) == 0:
- self.setReformationHitMatrix(neighbour, 1)
-
- def reformationArrayChoice(self):
- civ = (
- civilizations()
- .majors()
- .filter(lambda c: self.getReformationHitMatrix(c.id) == 1)
- .random_entry()
- )
- if civ is not None:
- if civ.is_alive() and civ.is_catholic():
- self.reformationchoice(civ.id)
- else:
- self.reformationOther(civ.id)
- self.setReformationHitMatrix(civ.id, 2)
- self.spread_reform_to_neighbour(civ.id)
-
- if sum(self.getReformationHitMatrixAll()) == 2 * civilizations().majors().len():
- self.setReformationActive(False)
- # after all players have been hit by the Reformation
- self.setCounterReformationActive(True)
-
- def reformationchoice(self, iCiv):
- if iCiv == Civ.POPE:
- return # Absinthe: totally exclude the Pope from the Reformation
-
- if civilization(iCiv).has_state_religion(Religion.PROTESTANTISM) or percentage_chance(
- civilization(iCiv).ai.reformation_threshold
- ):
- self.reformationyes(iCiv)
- elif civilization(iCiv).is_human():
- event_popup(
- 7624,
- text("TXT_KEY_REFORMATION_TITLE"),
- text("TXT_KEY_REFORMATION_MESSAGE"),
- [text("TXT_KEY_POPUP_YES"), text("TXT_KEY_POPUP_NO")],
- )
- else:
- self.reformationno(iCiv)
-
- def reformationyes(self, iCiv):
- iFaith = 0
- for city in cities().owner(iCiv).entities():
- if city.isHasReligion(Religion.CATHOLICISM):
- iFaith += self.reformationReformCity(city, iCiv)
-
- # disband catholic missionaries of the AI civs on reformation
- if iCiv != human():
- for pUnit in units().owner(iCiv).entities():
- iUnitType = pUnit.getUnitType()
- if iUnitType == Unit.CATHOLIC_MISSIONARY:
- pUnit.kill(0, -1)
-
- pPlayer = gc.getPlayer(iCiv)
- # iStateReligion = pPlayer.getStateReligion()
- # if (pPlayer.getStateReligion() == Religion.CATHOLICISM):
- pPlayer.setLastStateReligion(Religion.PROTESTANTISM)
- pPlayer.setConversionTimer(10)
- pPlayer.setFaith(iFaith)
-
- def reformationno(self, iCiv):
- iLostFaith = 0
- pPlayer = gc.getPlayer(iCiv)
- for city in cities().owner(iCiv).entities():
- if city.isHasReligion(Religion.CATHOLICISM) and not city.isHasReligion(
- Religion.PROTESTANTISM
- ):
- if percentage_chance(25 + civilization(iCiv).ai.reformation_threshold / 2):
- city.setHasReligion(
- Religion.PROTESTANTISM, True, False, False
- ) # no announcement in this case
- if pPlayer.isHuman():
- CityName = city.getNameKey()
- message(
- human(),
- text("TXT_KEY_REFORMATION_RELIGION_STILL_SPREAD", CityName),
- event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
- color=MessageData.WHITE,
- )
- iLostFaith += 1
- gc.getPlayer(iCiv).changeFaith(-min(gc.getPlayer(iCiv).getFaith(), iLostFaith))
-
- def reformationOther(self, iCiv):
- for city in cities().owner(iCiv).entities():
- if city.isHasReligion(Religion.CATHOLICISM):
- self.reformationOtherCity(city, iCiv)
-
- def reformationReformCity(self, pCity, iCiv):
- iFaith = 0
- iPopBonus = 0
- iAIBonus = 0
- pPlayer = gc.getPlayer(iCiv)
- # bigger cities have more chance for a new religion to spread
- if pCity.getPopulation() > 11:
- iPopBonus = 20
- elif pCity.getPopulation() > 8:
- iPopBonus = 15
- elif pCity.getPopulation() > 5:
- iPopBonus = 10
- elif pCity.getPopulation() > 2:
- iPopBonus = 5
- # civ-specific modifier, between 3 and 27
- iCivRef = (civilization(pCity).ai.reformation_threshold / 10) * 3
- # AI bonus
- if human() == iCiv:
- iAIBonus = 10
-
- # spread the religion: range goes from 48-68% (Catholicism-lovers) to 72-92% (Protestantism-lovers), based on lReformationMatrix
- # +10% extra bonus for the AI
- if percentage_chance(45 + iCivRef + iPopBonus + iAIBonus, strict=True):
- pCity.setHasReligion(Religion.PROTESTANTISM, True, True, False)
- iFaith += 1
- iChance = 55 + iCivRef
- # if protestantism has spread, chance for replacing the buildings: between 58% and 82%, based on lReformationMatrix
- if pCity.hasBuilding(Building.CATHOLIC_CHAPEL) and percentage_chance(
- iChance, strict=True
- ):
- pCity.setHasRealBuilding(Building.CATHOLIC_CHAPEL, False)
- pCity.setHasRealBuilding(Building.PROTESTANT_CHAPEL, True)
- if pCity.hasBuilding(Building.CATHOLIC_TEMPLE) and percentage_chance(
- iChance, strict=True
- ):
- pCity.setHasRealBuilding(Building.CATHOLIC_TEMPLE, False)
- pCity.setHasRealBuilding(Building.PROTESTANT_TEMPLE, True)
- iFaith += 1
- if pCity.hasBuilding(Building.CATHOLIC_MONASTERY) and percentage_chance(
- iChance, strict=True
- ):
- pCity.setHasRealBuilding(Building.CATHOLIC_MONASTERY, False)
- pCity.setHasRealBuilding(Building.PROTESTANT_SEMINARY, True)
- iFaith += 1
- if pCity.hasBuilding(Building.CATHOLIC_CATHEDRAL) and percentage_chance(
- iChance, strict=True
- ):
- pCity.setHasRealBuilding(Building.CATHOLIC_CATHEDRAL, False)
- pCity.setHasRealBuilding(Building.PROTESTANT_CATHEDRAL, True)
- iFaith += 2
-
- # remove Catholicism if there are no religious buildings left, and there are no catholic wonders in the city
- # range goes from 39-59% to 71-91%, based on lReformationMatrix
- if percentage_chance(
- 55 + ((civilization(iCiv).ai.reformation_threshold / 5) * 2) - iPopBonus,
- strict=True,
- ):
- lCathlist = [
- Building.CATHOLIC_TEMPLE,
- Building.CATHOLIC_CHAPEL,
- Building.CATHOLIC_MONASTERY,
- Building.CATHOLIC_CATHEDRAL,
- Wonder.MONASTERY_OF_CLUNY,
- Wonder.KRAK_DES_CHEVALIERS,
- Wonder.PALAIS_DES_PAPES,
- Wonder.NOTRE_DAME,
- Wonder.WESTMINSTER,
- ]
- bCathBuildings = False
- for iBuilding in lCathlist:
- if pCity.hasBuilding(iBuilding):
- bCathBuildings = True
- break
- if not bCathBuildings:
- pCity.setHasReligion(Religion.CATHOLICISM, False, False, False)
- if pPlayer.isHuman():
- CityName = pCity.getNameKey()
- message(
- human(),
- text("TXT_KEY_REFORMATION_PEOPLE_ABANDON_CATHOLICISM_1", CityName),
- event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
- color=MessageData.WHITE,
- )
-
- return iFaith
-
- def reformationOtherCity(self, pCity, iCiv):
- iPopBonus = 0
- pPlayer = gc.getPlayer(iCiv)
- # bigger cities have more chance for a new religion to spread
- if pCity.getPopulation() > 11:
- iPopBonus = 30
- elif pCity.getPopulation() > 7:
- iPopBonus = 20
- elif pCity.getPopulation() > 3:
- iPopBonus = 10
- # civ-specific, between 3 and 27
- iCivRef = (civilization(pCity).ai.reformation_threshold / 10) * 3
-
- # spread the religion: range goes from 23-53% (Catholicism-lovers) to 47-77% (Protestantism-lovers), based on lReformationMatrix
- if percentage_chance(20 + iCivRef + iPopBonus, strict=True):
- pCity.setHasReligion(Religion.PROTESTANTISM, True, True, False)
- # if protestantism has spread, chance for replacing the buildings: between 31% and 79%, based on lReformationMatrix
- iChance = 25 + 2 * iCivRef
- if pCity.hasBuilding(Building.CATHOLIC_CHAPEL) and percentage_chance(
- iChance, strict=True
- ):
- pCity.setHasRealBuilding(Building.CATHOLIC_CHAPEL, False)
- pCity.setHasRealBuilding(Building.PROTESTANT_CHAPEL, True)
- if pCity.hasBuilding(Building.CATHOLIC_TEMPLE) and percentage_chance(
- iChance, strict=True
- ):
- pCity.setHasRealBuilding(Building.CATHOLIC_TEMPLE, False)
- pCity.setHasRealBuilding(Building.PROTESTANT_TEMPLE, True)
- if pCity.hasBuilding(Building.CATHOLIC_MONASTERY) and percentage_chance(
- iChance, strict=True
- ):
- pCity.setHasRealBuilding(Building.CATHOLIC_MONASTERY, False)
- pCity.setHasRealBuilding(Building.PROTESTANT_SEMINARY, True)
- if pCity.hasBuilding(Building.CATHOLIC_CATHEDRAL) and percentage_chance(
- iChance, strict=True
- ):
- pCity.setHasRealBuilding(Building.CATHOLIC_CATHEDRAL, False)
- pCity.setHasRealBuilding(Building.PROTESTANT_CATHEDRAL, True)
-
- # remove Catholicism if there are no religious buildings left, and there are no catholic wonders in the city
- # range goes from 39-54% to 71-86%, based on lReformationMatrix
- if percentage_chance(
- 50 + ((civilization(iCiv).ai.reformation_threshold / 5) * 2) - (iPopBonus / 2),
- strict=True,
- ):
- lCathlist = [
- Building.CATHOLIC_TEMPLE,
- Building.CATHOLIC_CHAPEL,
- Building.CATHOLIC_MONASTERY,
- Building.CATHOLIC_CATHEDRAL,
- Wonder.MONASTERY_OF_CLUNY,
- Wonder.KRAK_DES_CHEVALIERS,
- Wonder.PALAIS_DES_PAPES,
- Wonder.NOTRE_DAME,
- Wonder.WESTMINSTER,
- ]
- bCathBuildings = False
- for iBuilding in lCathlist:
- if pCity.hasBuilding(iBuilding):
- bCathBuildings = True
- break
- if not bCathBuildings:
- pCity.setHasReligion(Religion.CATHOLICISM, False, False, False)
- if pPlayer.isHuman(): # message for the human player
- CityName = pCity.getNameKey()
- if pPlayer.getStateReligion() == Religion.ISLAM:
- message(
- human(),
- text("TXT_KEY_REFORMATION_PEOPLE_ABANDON_CATHOLICISM_2", CityName),
- event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
- color=MessageData.WHITE,
- )
- else:
- message(
- human(),
- text("TXT_KEY_REFORMATION_PEOPLE_ABANDON_CATHOLICISM_3", CityName),
- event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
- color=MessageData.WHITE,
- )
-
- def doCounterReformation(self):
- for iPlayer in range(Civ.POPE - 1):
- pPlayer = gc.getPlayer(iPlayer)
- if pPlayer.isAlive() and pPlayer.getStateReligion() == Religion.CATHOLICISM:
- if pPlayer.isHuman():
- self.doCounterReformationHuman(iPlayer)
- elif percentage_chance(
- civilization(iPlayer).ai.reformation_threshold, strict=True, reverse=True
- ):
- self.doCounterReformationYes(iPlayer)
- else:
- self.doCounterReformationNo(iPlayer)
- self.setCounterReformationActive(False)
-
- def doCounterReformationHuman(self, iPlayer):
- pPlayer = gc.getPlayer(iPlayer)
- szMessageYes = (
- text("TXT_KEY_COUNTER_REFORMATION_MESSAGE_YES_1")
- + " +%d " % (max(1, pPlayer.getNumCities() / 3))
- + text("TXT_KEY_COUNTER_REFORMATION_MESSAGE_YES_2")
- )
- szMessageNo = (
- text("TXT_KEY_COUNTER_REFORMATION_MESSAGE_NO_1")
- + " +%d " % (max(1, pPlayer.getNumCities() / 3))
- + text("TXT_KEY_COUNTER_REFORMATION_MESSAGE_NO_2")
- )
- self.showCounterPopup(
- 7626,
- text("TXT_KEY_COUNTER_REFORMATION_TITLE"),
- text("TXT_KEY_COUNTER_REFORMATION_MESSAGE"),
- (szMessageYes, szMessageNo),
- )
-
- def showCounterPopup(self, popupID, title, message, labels):
- popup = Popup.PyPopup(popupID, EventContextTypes.EVENTCONTEXT_ALL)
- popup.setHeaderString(title)
- popup.setBodyString(message)
- for i in labels:
- popup.addButton(i)
- popup.launch(False)
-
- def eventApply7626(self, popupReturn):
- iHuman = human()
- if popupReturn.getButtonClicked() == 0:
- self.doCounterReformationYes(iHuman)
- elif popupReturn.getButtonClicked() == 1:
- self.doCounterReformationNo(iHuman)
-
- def eventApply7628(self, popupReturn): # Absinthe: persecution popup
- """Persecution popup event."""
- iPlotX, iPlotY, iUnitID = data.lPersecutionData
- iChosenReligion = data.lPersecutionReligions[popupReturn.getButtonClicked()]
- prosecute(iPlotX, iPlotY, iUnitID, iChosenReligion)
-
- def doCounterReformationYes(self, iPlayer):
- pPlayer = gc.getPlayer(iPlayer)
- pCapital = pPlayer.getCapitalCity()
- iX = pCapital.getX()
- iY = pCapital.getY()
- if not pCapital.isNone():
- if pPlayer.getNumCities() > 0:
- pCapital = cities().owner(iPlayer).random_entry()
- iX = pCapital.getX()
- iY = pCapital.getY()
- else:
- return
- iNumProsecutors = max(1, pPlayer.getNumCities() / 3)
- for i in range(iNumProsecutors):
- pPlayer.initUnit(
- Unit.PROSECUTOR,
- iX,
- iY,
- UnitAITypes.UNITAI_MISSIONARY,
- DirectionTypes.DIRECTION_SOUTH,
- )
-
- for neighbour in civilization(iPlayer).location.reformation_neighbours:
- civ = civilization(neighbour)
- if civ.is_alive() and civ.is_protestant():
- if not civ.player.getCapitalCity().isNone() and civ.player.getNumCities() > 0:
- capital = cities().owner(neighbour).random_entry()
- else:
- return
-
- civ.player.initUnit(
- Unit.PROSECUTOR,
- capital.getX(),
- capital.getY(),
- UnitAITypes.UNITAI_MISSIONARY,
- DirectionTypes.DIRECTION_SOUTH,
- )
-
- def doCounterReformationNo(self, iPlayer):
- pPlayer = gc.getPlayer(iPlayer)
- pPlayer.changeStabilityBase(StabilityCategory.CITIES, max(1, pPlayer.getNumCities() / 3))
-
- ### End Reformation ###
-
- def resettleRefugies(self):
- intolerance = [-1] * civilizations().len()
- for iPlayer in civilizations().ids():
- pPlayer = gc.getPlayer(iPlayer)
- if pPlayer.isAlive():
- if iPlayer < Civ.POPE:
- # add a random element
- intolerance[iPlayer] += percentage()
- intolerance[iPlayer] += 10 * pPlayer.getProsecutionCount()
- if pPlayer.getProsecutionCount() == 0:
- intolerance[iPlayer] = max(
- 0, intolerance[iPlayer] - 30
- ) # if this player doesn't prosecute, decrease intolerance
- iRCivic = pPlayer.getCivics(4)
- if iRCivic == Civic.THEOCRACY:
- intolerance[iPlayer] += 50
- elif iRCivic == Civic.FREE_RELIGION:
- intolerance[iPlayer] = max(0, intolerance[iPlayer] - 30)
- if iPlayer > Civ.POPE:
- intolerance[iPlayer] += percentage()
- # once we have the list of potential nations
- iCandidate1 = 0
- for iPlayer in civilizations().ids():
- if intolerance[iPlayer] > -1 and intolerance[iPlayer] < intolerance[iCandidate1]:
- iCandidate1 = iPlayer
- iCandidate2 = 0
- if iCandidate2 == iCandidate1:
- iCandidate2 = 1
- for iPlayer in civilizations().ids():
- if (
- intolerance[iPlayer] > -1
- and iPlayer != iCandidate1
- and intolerance[iPlayer] < intolerance[iCandidate1]
- ):
- iCandidate2 = iPlayer
-
- if percentage_chance(50, strict=True):
- self.migrateJews(iCandidate1)
- else:
- self.migrateJews(iCandidate2)
-
- def migrateJews(self, iPlayer):
- pPlayer = gc.getPlayer(iPlayer)
-
- lCityList = [
- city
- for city in cities().owner(iPlayer).entities()
- if not city.isHasReligion(Religion.JUDAISM)
- ]
-
- if lCityList:
- city = choice(lCityList)
- city.setHasReligion(Religion.JUDAISM, True, True, False)
-
- def spread1200ADJews(self):
- # Spread Judaism to a random city in Africa
- tCity = self.selectRandomCityRegion(tWestAfrica, Religion.JUDAISM)
- if tCity:
- self.spreadReligion(tCity, Religion.JUDAISM)
- # Spread Judaism to another city in Spain
- tCity = self.selectRandomCityRegion(tSpain, Religion.JUDAISM)
- if tCity:
- self.spreadReligion(tCity, Religion.JUDAISM)
- # Spread Judaism to a city in France/Germany
- tCity = self.selectRandomCityRegion(tGermany, Religion.JUDAISM)
- if tCity:
- self.spreadReligion(tCity, Religion.JUDAISM)
diff --git a/Assets/Python/components/Resources.py b/Assets/Python/components/Resources.py
deleted file mode 100644
index 2b2e87b38..000000000
--- a/Assets/Python/components/Resources.py
+++ /dev/null
@@ -1,103 +0,0 @@
-# Rhye's and Fall of Civilization: Europe - Dynamic resources
-# Based on SoI version, added by Absinthe
-
-from CvPythonExtensions import *
-
-from Consts import MessageData
-from Core import text, message, year
-from CoreTypes import Improvement, Bonus
-
-# globals
-gc = CyGlobalContext()
-
-
-class Resources:
- def createResource(self, iX, iY, iBonus, textKey="TXT_KEY_RESOURCE_DISCOVERED"):
- """Creates a bonus resource and alerts the plot owner"""
-
- if (
- gc.getMap().plot(iX, iY).getBonusType(-1) == -1 or iBonus == -1
- ): # Absinthe: only proceed if there isn't any bonus resources on the plot, or if we're removing the bonus
- if iBonus == -1:
- iBonus = gc.getMap().plot(iX, iY).getBonusType(-1) # for alert
- gc.getMap().plot(iX, iY).setBonusType(-1)
- else:
- gc.getMap().plot(iX, iY).setBonusType(iBonus)
-
- iOwner = gc.getMap().plot(iX, iY).getOwner()
- if iOwner >= 0 and textKey != -1: # Absinthe: only show alert to the tile owner
- city = gc.getMap().findCity(
- iX,
- iY,
- iOwner,
- TeamTypes.NO_TEAM,
- True,
- False,
- TeamTypes.NO_TEAM,
- DirectionTypes.NO_DIRECTION,
- CyCity(),
- )
- if not city.isNone():
- szText = text(
- textKey,
- gc.getBonusInfo(iBonus).getTextKey(),
- city.getName(),
- gc.getPlayer(iOwner).getCivilizationAdjective(0),
- )
- message(
- iOwner,
- szText,
- sound="AS2D_DISCOVERBONUS",
- event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
- button=gc.getBonusInfo(iBonus).getButton(),
- color=MessageData.LIME,
- location=(iX, iY),
- )
-
- def removeResource(self, iX, iY, textKey="TXT_KEY_RESOURCE_EXHAUSTED"):
- """Removes a bonus resource and alerts the plot owner"""
-
- if (
- gc.getMap().plot(iX, iY).getBonusType(-1) != -1
- ): # only proceed if there is a bonus resource on the plot
- iBonusType = gc.getMap().plot(iX, iY).getBonusType(-1)
- iImprovementType = gc.getMap().plot(iX, iY).getImprovementType()
- self.createResource(iX, iY, -1, textKey)
- # Absinthe: remove the improvement too, but only if it improves the given resource
- # for now only adding the ones we actually use
- # Pasture, Camp and Colonial Trade Route cannot be built on base terrain (only with resource), so it is always safe to remove those
- # the question is whether we should also remove Farms and Lumbermills for example
- if iBonusType == Bonus.HORSE and iImprovementType == Improvement.PASTURE:
- gc.getMap().plot(iX, iY).setImprovementType(-1)
- elif (
- iBonusType == Bonus.NORTH_ACCESS and iImprovementType == Improvement.COLONIAL_TRADE
- ):
- gc.getMap().plot(iX, iY).setImprovementType(-1)
-
- def checkTurn(self, iGameTurn):
- # Absinthe: note that all actions are taken place in the end of the turn, so actually the resources will appear/disappear for the next turn
- if iGameTurn == year(552):
- self.createResource(80, 24, Bonus.SILK) # Silk near Constantinople
- elif iGameTurn == year(1000):
- self.createResource(36, 24, Bonus.RICE) # Rice in Iberia
- self.createResource(86, 2, Bonus.RICE) # Rice in the Middle East
- elif iGameTurn == (year(1066) + 1):
- self.removeResource(2, 69) # Remove the NAA from Iceland
- elif iGameTurn == year(1452): # Coffee spawns instead of being preplaced
- self.createResource(93, 0, Bonus.COFFEE) # near Sinai
- self.createResource(99, 13, Bonus.COFFEE) # between Damascus and Edessa
- elif iGameTurn == year(1500):
- self.createResource(
- 55, 35, Bonus.RICE
- ) # Rice in Italy - represents trade of the merchant republics
- elif iGameTurn == year(1580):
- self.createResource(32, 59, Bonus.POTATO) # Potatoes in Ireland
- self.createResource(29, 57, Bonus.POTATO)
- self.createResource(69, 49, Bonus.POTATO) # Poland
- self.createResource(66, 46, Bonus.POTATO)
- self.createResource(60, 48, Bonus.POTATO) # Northern Germany
- self.createResource(55, 52, Bonus.POTATO)
- self.createResource(59, 61, Bonus.ACCESS) # Atlantic Access in Scandinavia
-
- def onTechAcquired(self, iTech, iPlayer):
- pass
diff --git a/Assets/Python/components/RiseAndFall.py b/Assets/Python/components/RiseAndFall.py
deleted file mode 100644
index 23cc4894b..000000000
--- a/Assets/Python/components/RiseAndFall.py
+++ /dev/null
@@ -1,1444 +0,0 @@
-from CvPythonExtensions import *
-from Civilizations import (
- set_initial_contacts,
- reveal_areas,
- set_starting_techs_1200AD,
- set_starting_gold,
- set_starting_techs,
- create_starting_units_1200AD,
- create_starting_units_500AD,
- create_starting_workers,
- set_starting_diplomacy_1200AD,
- set_starting_faith,
-)
-from Consts import MessageData
-from Core import (
- civilization,
- civilizations,
- event_popup,
- get_scenario,
- get_scenario_start_turn,
- human,
- is_major_civ,
- is_minor_civ,
- location,
- make_unit,
- make_units,
- player,
- text,
- message,
- turn,
- year,
- cities,
- plots,
-)
-from History import ottoman_invasion
-from PyUtils import percentage, percentage_chance, rand, choice
-import Provinces
-from RFCUtils import (
- clearPlague,
- convertPlotCulture,
- cultureManager,
- flipCity,
- flipUnitsInArea,
- flipUnitsInCityAfter,
- flipUnitsInCityBefore,
- flipUnitsInPlots,
- forcedInvasion,
- getLastTurnAlive,
- getPlagueCountdown,
- getUniqueBuilding,
- goodPlots,
- innerSpawn,
- killAllUnitsInArea,
- killUnitsInPlots,
- outerInvasion,
- ownedCityPlots,
- setPlagueCountdown,
- squareSearch,
- updateMinorTechs,
-)
-import Religions
-from Collapse import collapseByBarbs, collapseGeneric, collapseMotherland
-from Secession import secession, secessionCloseCollapse
-from Resurrection import resurectCiv, resurrection
-import Victory
-from StoredData import data
-import Crusades
-
-from MiscData import PLAGUE_IMMUNITY
-from CoreTypes import (
- Area,
- AreaType,
- Building,
- Civ,
- LeaderType,
- PlayerType,
- Scenario,
- Religion,
- Terrain,
- Feature,
- Improvement,
- StabilityCategory,
- Unit,
-)
-from LocationsData import CIV_CAPITAL_LOCATIONS
-from Wonders import leaning_tower_effect
-
-gc = CyGlobalContext()
-rel = Religions.Religions()
-vic = Victory.Victory()
-cru = Crusades.Crusades()
-
-iCheatersPeriod = 12
-iBetrayalPeriod = 8
-iBetrayalThreshold = 66
-iRebellionDelay = 15
-iEscapePeriod = 30
-
-
-class RiseAndFall:
- def __init__(self):
- self.pm = Provinces.ProvinceManager()
- # Init the Province Manager
-
- ##################################################
- ### Secure storage & retrieval of script data ###
- ################################################
-
- def getNewCiv(self):
- return data.iNewCiv
-
- def setNewCiv(self, iNewValue):
- data.iNewCiv = iNewValue
-
- def getNewCivFlip(self):
- return data.iNewCivFlip
-
- def setNewCivFlip(self, iNewValue):
- data.iNewCivFlip = iNewValue
-
- def getOldCivFlip(self):
- return data.iOldCivFlip
-
- def setOldCivFlip(self, iNewValue):
- data.iOldCivFlip = iNewValue
-
- def getTempTopLeft(self):
- return data.iTempTopLeft
-
- def setTempTopLeft(self, tNewValue):
- data.iTempTopLeft = tNewValue
-
- def getTempBottomRight(self):
- return data.iTempBottomRight
-
- def setTempBottomRight(self, tNewValue):
- data.iTempBottomRight = tNewValue
-
- def getSpawnWar(self):
- return data.iSpawnWar
-
- def setSpawnWar(self, iNewValue):
- data.iSpawnWar = iNewValue
-
- def getAlreadySwitched(self):
- return data.bAlreadySwitched
-
- def setAlreadySwitched(self, bNewValue):
- data.bAlreadySwitched = bNewValue
-
- def getSpawnDelay(self, iCiv):
- return data.lSpawnDelay[iCiv]
-
- def setSpawnDelay(self, iCiv, iNewValue):
- data.lSpawnDelay[iCiv] = iNewValue
-
- def getFlipsDelay(self, iCiv):
- return data.lFlipsDelay[iCiv]
-
- def setFlipsDelay(self, iCiv, iNewValue):
- data.lFlipsDelay[iCiv] = iNewValue
-
- def getBetrayalTurns(self):
- return data.iBetrayalTurns
-
- def setBetrayalTurns(self, iNewValue):
- data.iBetrayalTurns = iNewValue
-
- def getRebelCiv(self):
- return data.iRebelCiv
-
- def getRebelCities(self):
- return data.lRebelCities
-
- def getRebelSuppress(self):
- return data.lRebelSuppress
-
- def setRebelSuppress(self, lSuppressList):
- data.lRebelSuppress = lSuppressList
-
- def getTempFlippingCity(self):
- return data.iTempFlippingCity
-
- def setTempFlippingCity(self, tNewValue):
- data.iTempFlippingCity = tNewValue
-
- def getCheatersCheck(self, i):
- return data.lCheatersCheck[i]
-
- def setCheatersCheck(self, i, iNewValue):
- data.lCheatersCheck[i] = iNewValue
-
- def getDeleteMode(self, i):
- return data.lDeleteMode[i]
-
- def setDeleteMode(self, i, iNewValue):
- data.lDeleteMode[i] = iNewValue
-
- # Sedna17 Respawn
- def setSpecialRespawnTurn(self, iCiv, iNewValue):
- data.lSpecialRespawnTurn[iCiv] = iNewValue
-
- def getSpecialRespawnTurns(self):
- return data.lSpecialRespawnTurn
-
- ###############
- ### Popups ###
- #############
-
- """ popupID has to be a registered ID in CvRhyesCatapultEventManager.__init__!! """
-
- def newCivPopup(self, iCiv):
- event_popup(
- 7614,
- text("TXT_KEY_NEWCIV_TITLE"),
- text("TXT_KEY_NEWCIV_MESSAGE", player(iCiv).getCivilizationAdjectiveKey()),
- [text("TXT_KEY_POPUP_YES"), text("TXT_KEY_POPUP_NO")],
- )
- self.setNewCiv(iCiv)
-
- def eventApply7614(self, popupReturn):
- if popupReturn.getButtonClicked() == 0: # 1st button
- iOldHandicap = gc.getActivePlayer().getHandicapType()
- iNewCiv = self.getNewCiv()
- vic.switchUHV(iNewCiv, human())
- gc.getActivePlayer().setHandicapType(gc.getPlayer(iNewCiv).getHandicapType())
- gc.getGame().setActivePlayer(iNewCiv, False)
- gc.getPlayer(iNewCiv).setHandicapType(iOldHandicap)
- for iMaster in civilizations().majors().ids():
- if gc.getTeam(gc.getPlayer(iNewCiv).getTeam()).isVassal(iMaster):
- gc.getTeam(gc.getPlayer(iNewCiv).getTeam()).setVassal(iMaster, False, False)
- self.setAlreadySwitched(True)
- gc.getPlayer(iNewCiv).setPlayable(True)
-
- def flipPopup(self, iNewCiv, tTopLeft, tBottomRight):
- iHuman = human()
- flipText = text("TXT_KEY_FLIPMESSAGE1")
-
- for city in (
- plots()
- .rectangle(tTopLeft, tBottomRight)
- .add(civilization(iNewCiv).location.area[AreaType.CORE][Area.ADDITIONAL_TILES])
- .cities()
- .filter(lambda c: c.getOwner() == iHuman and not c.isCapital())
- .entities()
- ):
- flipText += city.getName() + "\n"
- flipText += text("TXT_KEY_FLIPMESSAGE2")
-
- event_popup(
- 7615,
- text("TXT_KEY_NEWCIV_TITLE"),
- flipText,
- [text("TXT_KEY_POPUP_YES"), text("TXT_KEY_POPUP_NO")],
- )
- self.setNewCivFlip(iNewCiv)
- self.setOldCivFlip(iHuman)
- self.setTempTopLeft(tTopLeft)
- self.setTempBottomRight(tBottomRight)
-
- def eventApply7615(self, popupReturn):
- iHuman = human()
- tTopLeft = self.getTempTopLeft()
- tBottomRight = self.getTempBottomRight()
- iNewCivFlip = self.getNewCivFlip()
-
- humanCityList = []
-
- for city in (
- plots()
- .rectangle(tTopLeft, tBottomRight)
- .add(civilization(iNewCivFlip).location.area[AreaType.CORE][Area.ADDITIONAL_TILES])
- .cities()
- .filter(lambda c: c.getOwner() == iHuman and not c.isCapital())
- .entities()
- ):
- humanCityList.append(city)
-
- if popupReturn.getButtonClicked() == 0: # 1st button
- message(iHuman, text("TXT_KEY_FLIP_AGREED"), force=True, color=MessageData.GREEN)
-
- if humanCityList:
- for city in humanCityList:
- tCity = (city.getX(), city.getY())
- cultureManager(tCity, 100, iNewCivFlip, iHuman, False, False, False)
- flipUnitsInCityBefore(tCity, iNewCivFlip, iHuman)
- self.setTempFlippingCity(tCity)
- flipCity(tCity, 0, 0, iNewCivFlip, [iHuman])
- flipUnitsInCityAfter(tCity, iNewCivFlip)
-
- # same code as Betrayal - done just once to make sure human player doesn't hold a stack just outside of the cities
- for plot in plots().rectangle(tTopLeft, tBottomRight).entities():
- iNumUnitsInAPlot = plot.getNumUnits()
- if iNumUnitsInAPlot > 0:
- for i in range(iNumUnitsInAPlot):
- unit = plot.getUnit(i)
- if unit.getOwner() == iHuman:
- rndNum = percentage()
- if rndNum >= iBetrayalThreshold:
- if unit.getDomainType() == DomainTypes.DOMAIN_SEA: # land unit
- iUnitType = unit.getUnitType()
- unit.kill(False, iNewCivFlip)
- make_unit(iNewCivFlip, iUnitType, location(plot))
- i = i - 1
-
- if self.getCheatersCheck(0) == 0:
- self.setCheatersCheck(0, iCheatersPeriod)
- self.setCheatersCheck(1, self.getNewCivFlip())
-
- elif popupReturn.getButtonClicked() == 1: # 2nd button
- message(iHuman, text("TXT_KEY_FLIP_REFUSED"), force=True, color=MessageData.RED)
-
- if humanCityList:
- for city in humanCityList:
- pCurrent = gc.getMap().plot(city.getX(), city.getY())
- oldCulture = pCurrent.getCulture(iHuman)
- # Absinthe: changeCulture instead of setCulture, otherwise previous culture will be lost
- pCurrent.changeCulture(iNewCivFlip, oldCulture / 2, True)
- pCurrent.setCulture(iHuman, oldCulture / 2, True)
- iWar = self.getSpawnWar() + 1
- self.setSpawnWar(iWar)
- if self.getSpawnWar() == 1:
- # safety check - don't want to use canDeclareWar, as here we want to always declare war
- if not gc.getTeam(gc.getPlayer(iNewCivFlip).getTeam()).isAtWar(iHuman):
- gc.getTeam(gc.getPlayer(iNewCivFlip).getTeam()).declareWar(
- iHuman, False, -1
- )
- self.setBetrayalTurns(iBetrayalPeriod)
- self.initBetrayal()
-
- # resurrection when some human controlled cities are also included
- def eventApply7622(self, popupReturn):
- iHuman = human()
- iRebelCiv = self.getRebelCiv()
- iChoice = popupReturn.getButtonClicked()
- iHumanCity = 0
- lCityList = self.getRebelCities()
- for (x, y) in lCityList:
- iOwner = gc.getMap().plot(x, y).getPlotCity().getOwner()
- if iOwner == iHuman:
- iHumanCity += 1
-
- if iChoice == 1:
- lList = self.getRebelSuppress()
- lList[iHuman] = 2 # let go + war
- self.setRebelSuppress(lList)
- elif iChoice == 2:
- if percentage_chance(40, strict=True):
- lCityList = self.getRebelCities()
- for (x, y) in lCityList:
- pCity = gc.getMap().plot(x, y).getPlotCity()
- if pCity.getOwner() == iHuman:
- pCity.changeOccupationTimer(2)
- pCity.changeHurryAngerTimer(10)
- lList = self.getRebelSuppress()
- lList[iHuman] = 3 # keep cities + war
- self.setRebelSuppress(lList)
- else:
- lList = self.getRebelSuppress()
- lList[iHuman] = 4 # let go + war
- self.setRebelSuppress(lList)
- elif iChoice == 3:
- iLoyalPrice = min((10 * gc.getPlayer(iHuman).getGold()) / 100, 50 * iHumanCity)
- gc.getPlayer(iHuman).setGold(gc.getPlayer(iHuman).getGold() - iLoyalPrice)
- if percentage_chance(iLoyalPrice / iHumanCity, strict=True):
- lList = self.getRebelSuppress()
- lList[iHuman] = 1 # keep + no war
- self.setRebelSuppress(lList)
- else:
- lList = self.getRebelSuppress()
- lList[iHuman] = 4 # let go + war
- self.setRebelSuppress(lList)
- elif iChoice == 4:
- iLoyalPrice = min((10 * gc.getPlayer(iHuman).getGold()) / 100, 50 * iHumanCity)
- gc.getPlayer(iHuman).setGold(gc.getPlayer(iHuman).getGold() - iLoyalPrice)
- if percentage_chance(iLoyalPrice / iHumanCity + 40, strict=True):
- lCityList = self.getRebelCities()
- for (x, y) in lCityList:
- pCity = gc.getMap().plot(x, y).getPlotCity()
- if pCity.getOwner() == iHuman:
- pCity.changeOccupationTimer(2)
- pCity.changeHurryAngerTimer(10)
- lList = self.getRebelSuppress()
- lList[iHuman] = 3 # keep + war
- self.setRebelSuppress(lList)
- else:
- lList = self.getRebelSuppress()
- lList[iHuman] = 2 # let go + war
- self.setRebelSuppress(lList)
- resurectCiv(self.getRebelCiv())
-
- #######################################
- ### Main methods (Event-Triggered) ###
- #####################################
-
- def setup(self):
- self.setEarlyLeaders()
-
- # Sedna17 Respawn setup special respawn turns
- self.setupRespawnTurns()
-
- iHuman = human()
- if get_scenario() == Scenario.i500AD:
- create_starting_units_500AD()
- for civ in civilizations().majors().filter(lambda c: c.date.birth == year(500)).ids():
- reveal_areas(civ)
- set_initial_contacts(civ)
-
- else:
- create_starting_units_1200AD()
- for civ in (
- civilizations()
- .main()
- .filter(lambda c: c.date.birth < get_scenario_start_turn(Scenario.i1200AD))
- .ids()
- ):
- reveal_areas(civ)
- set_initial_contacts(civ, False)
- # Temporarily all civs get the same starting techs as Aragon
- set_starting_techs_1200AD(civ)
-
- set_starting_faith()
- set_starting_diplomacy_1200AD()
- leaning_tower_effect()
- rel.spread1200ADJews() # Spread Jews to some random cities
- vic.set1200UHVDone(iHuman)
- # Temporarily all civs get the same starting techs as Aragon
- set_starting_techs_1200AD(Civ.POPE)
- cru.do1200ADCrusades()
-
- set_starting_gold()
-
- def onCityBuilt(self, iPlayer, pCity):
- tCity = (pCity.getX(), pCity.getY())
- x, y = tCity
- self.pm.onCityBuilt(iPlayer, pCity.getX(), pCity.getY())
- # Absinthe: We can add free buildings for new cities here
- # Note that it will add the building every time a city is founded on the plot, not just on the first time
- # Venice (56, 35), Augsburg (55, 41), Porto (23, 31), Prague (60, 44), Riga (74, 58), Perekop (87, 36)
- # London (41, 52), Novgorod (80, 62) currently has preplaced fort on the map instead
- if tCity in [(56, 35), (55, 41), (23, 31), (60, 44), (74, 58), (87, 36)]:
- pCity.setHasRealBuilding(getUniqueBuilding(iPlayer, Building.WALLS), True)
- elif tCity == (75, 53): # Vilnius - important for AI Lithuania against Prussia
- if not gc.getPlayer(Civ.LITHUANIA).isHuman():
- pCity.setHasRealBuilding(getUniqueBuilding(iPlayer, Building.WALLS), True)
-
- def onCityAcquired(self, owner, iPlayer, city, bConquest, bTrade):
- self.pm.onCityAcquired(owner, iPlayer, city, bConquest, bTrade)
- # Constantinople -> Istanbul
- if iPlayer == Civ.OTTOMAN:
- cityList = cities().owner(iPlayer).entities()
- if (city.getX(), city.getY()) == CIV_CAPITAL_LOCATIONS[Civ.BYZANTIUM]:
- for loopCity in cityList:
- if loopCity != city:
- loopCity.setHasRealBuilding((Building.PALACE), False)
- city.setHasRealBuilding(Building.PALACE, True)
- if civilization(Civ.OTTOMAN).has_state_religion(Religion.ISLAM):
- city.setHasReligion(Religion.ISLAM, True, True, False)
- # some stability boost and flavour message
- player(Civ.OTTOMAN).changeStabilityBase(StabilityCategory.EXPANSION, 6)
- if human() == iPlayer:
- message(
- iPlayer,
- text("TXT_KEY_GLORY_ON_CONQUEST"),
- force=True,
- color=MessageData.GREEN,
- )
-
- # Absinthe: Edirne becomes capital if conquered before Constantinople
- else:
- if (city.getX(), city.getY()) == (76, 25):
- bHasIstanbul = False
- IstanbulPlot = gc.getMap().plot(*CIV_CAPITAL_LOCATIONS[Civ.BYZANTIUM])
- if IstanbulPlot.isCity():
- if IstanbulPlot.getPlotCity().getOwner() == iPlayer:
- bHasIstanbul = True
- if not bHasIstanbul:
- gc.getPlayer(iPlayer).getCapitalCity().setHasRealBuilding(
- Building.PALACE, False
- )
- city.setHasRealBuilding(Building.PALACE, True)
- if civilization(Civ.OTTOMAN).has_state_religion(Religion.ISLAM):
- city.setHasReligion(Religion.ISLAM, True, True, False)
-
- # Absinthe: Message for the human player, if the last city of a known civ is conquered
- iOriginalOwner = owner
- pOriginalOwner = gc.getPlayer(iOriginalOwner)
- if not pOriginalOwner.isHuman():
- iNumCities = pOriginalOwner.getNumCities()
- if iNumCities == 0:
- # all collapses operate with flips, so if the last city was conquered, we are good to go (this message won't come after a collapse message)
- if bConquest:
- iHuman = human()
- if gc.getPlayer(iHuman).canContact(iOriginalOwner):
- message(
- iHuman,
- pOriginalOwner.getCivilizationDescription(0)
- + " "
- + text("TXT_KEY_STABILITY_CONQUEST_LAST_CITY"),
- color=MessageData.RED,
- )
-
- def onCityRazed(self, iOwner, iPlayer, city):
- self.pm.onCityRazed(iOwner, iPlayer, city) # Province Manager
-
- # Sedna17 Respawn
- def setupRespawnTurns(self):
- for iCiv in civilizations().majors().ids():
- self.setSpecialRespawnTurn(
- iCiv, civilization(iCiv).date.respawning + (rand(21) - 10) + (rand(21) - 10)
- ) # bell-curve-like spawns within +/- 10 turns of desired turn (3Miro: Uniform, not a bell-curve)
-
- def setEarlyLeaders(self):
- for civ in civilizations().majors().ai():
- if civ.leaders[LeaderType.EARLY] != civ.leaders[LeaderType.PRIMARY]:
- leader = civ.leaders[LeaderType.EARLY]
- civ.player.setLeader(leader)
-
- def setWarOnSpawn(self):
- for civ in civilizations():
- wars = civ.scenario.get("wars")
- if wars is not None:
- for other, war_threshold in wars.items():
- if percentage_chance(war_threshold, strict=True) and not civ.at_war(other):
- civ.set_war(other)
-
- def checkTurn(self, iGameTurn):
- # Trigger betrayal mode
- if self.getBetrayalTurns() > 0:
- self.initBetrayal()
-
- if self.getCheatersCheck(0) > 0:
- teamPlayer = gc.getTeam(gc.getPlayer(human()).getTeam())
- if teamPlayer.isAtWar(self.getCheatersCheck(1)):
- self.initMinorBetrayal(self.getCheatersCheck(1))
- self.setCheatersCheck(0, 0)
- self.setCheatersCheck(1, -1)
- else:
- self.setCheatersCheck(0, self.getCheatersCheck(0) - 1)
-
- if iGameTurn % 20 == 0:
- for civ in civilizations().independents().alive():
- updateMinorTechs(civ.id, Civ.BARBARIAN)
-
- # Absinthe: checking the spawn dates
- for iLoopCiv in civilizations().majors().ids():
- if (
- civilization(iLoopCiv).date.birth != 0
- and iGameTurn >= civilization(iLoopCiv).date.birth - 2
- and iGameTurn <= civilization(iLoopCiv).date.birth + 4
- ):
- self.initBirth(iGameTurn, civilization(iLoopCiv).date.birth, iLoopCiv)
-
- # Fragment minor civs:
- # 3Miro: Shuffle cities between Indies and Barbs to make sure there is no big Independent nation
- if iGameTurn >= 20:
- if iGameTurn % 15 == 6:
- self.fragmentIndependents()
- if iGameTurn % 30 == 12:
- self.fragmentBarbarians(iGameTurn)
-
- # Fall of civs:
- # Barb collapse: if more than 1/3 of the empire is conquered and/or held by barbs = collapse
- # Generic collapse: if 1/2 of the empire is lost in only a few turns (16 ATM) = collapse
- # Motherland collapse: if no city is in the core area and the number of cities in the normal area is less than the number of foreign cities = collapse
- # Secession: if stability is negative there is a chance (bigger chance with worse stability) for a random city to declare it's independence
- if iGameTurn >= 64 and iGameTurn % 7 == 0: # mainly for Seljuks, Mongols, Timurids
- collapseByBarbs(iGameTurn)
- if iGameTurn >= 34 and iGameTurn % 16 == 0:
- collapseGeneric(iGameTurn)
- if iGameTurn >= 34 and iGameTurn % 9 == 7:
- collapseMotherland(iGameTurn)
- if iGameTurn > 20 and iGameTurn % 3 == 1:
- secession(iGameTurn)
- if iGameTurn > 20 and iGameTurn % 7 == 3:
- secessionCloseCollapse(iGameTurn)
-
- # Resurrection of civs:
- # This is one place to control the frequency of resurrection; will not be called with high iNumDeadCivs
- # Generally we want to allow Kiev, Bulgaria, Cordoba, Burgundy, Byzantium at least to be dead in late game without respawning
- # Absinthe: was 12 and 8 originally in RFCE, but we don't need that many dead civs
- iNumDeadCivs1 = 8 # 5 in vanilla RFC, 8 in warlords RFC
- iNumDeadCivs2 = 5 # 3 in vanilla RFC, 6 in warlords RFC
-
- iCiv = self.getSpecialRespawn(iGameTurn)
- if iCiv > -1:
- resurrection(iGameTurn, iCiv)
- elif (
- gc.getGame().countCivPlayersEverAlive() - gc.getGame().countCivPlayersAlive()
- > iNumDeadCivs1
- ):
- if iGameTurn % 10 == 7:
- resurrection(iGameTurn, -1)
- elif (
- gc.getGame().countCivPlayersEverAlive() - gc.getGame().countCivPlayersAlive()
- > iNumDeadCivs2
- ):
- if iGameTurn % 23 == 11:
- resurrection(iGameTurn, -1)
-
- # Absinthe: Reduce cities to towns, in order to make room for new civs
- if iGameTurn == civilization(Civ.SCOTLAND).date.birth - 3:
- # Reduce Inverness and Scone, so more freedom in where to found cities in Scotland
- self.reduceCity((37, 65))
- self.reduceCity((37, 67))
- elif iGameTurn == civilization(Civ.ENGLAND).date.birth - 3:
- # Reduce Norwich and Nottingham, so more freedom in where to found cities in England
- self.reduceCity((43, 55))
- self.reduceCity((39, 56))
- elif iGameTurn == civilization(Civ.SWEDEN).date.birth - 2:
- # Reduce Uppsala
- self.reduceCity((65, 66))
- # Absinthe: Reduce cities to town, if not owned by the human player
- if iGameTurn == year(1057):
- # Reduce Kairouan
- pPlot = gc.getMap().plot(43, 55)
- if pPlot.isCity():
- if pPlot.getPlotCity().getOwner() != human():
- self.reduceCity((43, 55))
-
- def reduceCity(self, tPlot):
- # Absinthe: disappearing cities (reducing them to an improvement)
- pPlot = gc.getMap().plot(tPlot[0], tPlot[1])
- if pPlot.isCity():
- # Absinthe: apologize from the player:
- msgString = (
- text("TXT_KEY_REDUCE_CITY_1")
- + " "
- + pPlot.getPlotCity().getName()
- + " "
- + text("TXT_KEY_REDUCE_CITY_2")
- )
- message(
- pPlot.getPlotCity().getOwner(), msgString, color=MessageData.ORANGE, location=pPlot
- )
-
- pPlot.eraseCityDevelopment()
- pPlot.setImprovementType(Improvement.TOWN) # Improvement Town instead of the city
- pPlot.setRouteType(0) # Also adding a road there
-
- def checkPlayerTurn(self, iGameTurn, iPlayer):
- # Absinthe & Merijn: leader switching with any number of leaders
- late_leaders = civilization(iPlayer).leaders[LeaderType.LATE]
- if late_leaders:
- for tLeader in reversed(late_leaders):
- if iGameTurn >= year(tLeader[1]):
- self.switchLateLeaders(iPlayer, tLeader)
- break
-
- # 3Miro: English cheat, the AI is utterly incompetent when it has to launch an invasion on an island
- # if in 1300AD Dublin is still Barbarian, it will flip to England
- if (
- iGameTurn == year(1300)
- and human() != Civ.ENGLAND
- and iPlayer == Civ.ENGLAND
- and player(Civ.ENGLAND).isAlive()
- ):
- tDublin = (32, 58)
- pPlot = gc.getMap().plot(tDublin[0], tDublin[1])
- if pPlot.isCity():
- if pPlot.getPlotCity().getOwner() == Civ.BARBARIAN:
- pDublin = pPlot.getPlotCity()
- cultureManager(tDublin, 50, Civ.ENGLAND, Civ.BARBARIAN, False, True, True)
- flipUnitsInCityBefore(tDublin, Civ.ENGLAND, Civ.BARBARIAN)
- self.setTempFlippingCity(tDublin)
- flipCity(
- tDublin, 0, 0, Civ.ENGLAND, [Civ.BARBARIAN]
- ) # by trade because by conquest may raze the city
- flipUnitsInCityAfter(tDublin, Civ.ENGLAND)
-
- # Absinthe: Another English AI cheat, extra defenders and defensive buildings in Normandy some turns after spawn - from RFCE++
- if (
- iGameTurn == year(1066) + 3
- and human() != Civ.ENGLAND
- and iPlayer == Civ.ENGLAND
- and player(Civ.ENGLAND).isAlive()
- ):
- for city in (
- plots().rectangle((39, 46), (45, 50)).cities().owner(Civ.ENGLAND).entities()
- ):
- make_unit(Civ.ENGLAND, Unit.GUISARME, city)
- make_unit(Civ.ENGLAND, Unit.ARBALEST, city)
- city.setHasRealBuilding(Building.WALLS, True)
- city.setHasRealBuilding(Building.CASTLE, True)
-
- def switchLateLeaders(self, iPlayer, tLeader):
- iLeader, iDate, iThreshold, iEra = tLeader
- if iLeader == gc.getPlayer(iPlayer).getLeader():
- return
- if gc.getPlayer(iPlayer).getCurrentEra() >= iEra:
- iThreshold *= 2
- if (
- gc.getPlayer(iPlayer).getAnarchyTurns() != 0
- or getPlagueCountdown(iPlayer) > 0
- or player(iPlayer).getStability() <= -10
- or percentage_chance(iThreshold, strict=True)
- ):
- gc.getPlayer(iPlayer).setLeader(iLeader)
-
- # Absinthe: message about the leader switch for the human player
- iHuman = human()
- HumanTeam = gc.getTeam(gc.getPlayer(iHuman).getTeam())
- PlayerTeam = gc.getPlayer(iPlayer).getTeam()
- if HumanTeam.isHasMet(PlayerTeam) and player().isExisting():
- message(
- iHuman,
- text(
- "TXT_KEY_LEADER_SWITCH",
- gc.getPlayer(iPlayer).getName(),
- gc.getPlayer(iPlayer).getCivilizationDescriptionKey(),
- ),
- event=InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
- color=MessageData.PURPLE,
- )
-
- def fragmentIndependents(self):
- for iIndep1 in civilizations().independents().ids():
- pIndep1 = gc.getPlayer(iIndep1)
- iNumCities1 = pIndep1.getNumCities()
- for iIndep2 in civilizations().independents().ids():
- if iIndep1 == iIndep2:
- continue
- pIndep2 = gc.getPlayer(iIndep2)
- iNumCities2 = pIndep2.getNumCities()
- if abs(iNumCities1 - iNumCities2) > 5:
- if iNumCities1 > iNumCities2:
- iBig = iIndep1
- iSmall = iIndep2
- else:
- iBig = iIndep2
- iSmall = iIndep1
- iDivideCounter = 0
- iCounter = 0
- for city in cities().owner(iBig).entities():
- iDivideCounter += 1
- if iDivideCounter % 2 == 1:
- tCity = (city.getX(), city.getY())
- pCurrent = gc.getMap().plot(tCity[0], tCity[1])
- cultureManager(tCity, 50, iSmall, iBig, False, True, True)
- flipUnitsInCityBefore(tCity, iSmall, iBig)
- self.setTempFlippingCity(tCity)
- flipCity(
- tCity, 0, 0, iSmall, [iBig]
- ) # by trade because by conquest may raze the city
- flipUnitsInCityAfter(tCity, iSmall)
- iCounter += 1
- if iCounter == 3:
- break
-
- def fragmentBarbarians(self, iGameTurn):
- iRndnum = rand(civilizations().majors().len())
- for j in civilizations().majors().ids():
- iDeadCiv = (j + iRndnum) % civilizations().majors().len()
- if (
- not gc.getPlayer(iDeadCiv).isAlive()
- and iGameTurn > civilization(iDeadCiv).date.birth + 50
- ):
- lCities = [
- location(city)
- for city in (
- plots()
- .rectangle(
- civilization(iDeadCiv).location.area[AreaType.NORMAL][Area.TILE_MIN],
- civilization(iDeadCiv).location.area[AreaType.NORMAL][Area.TILE_MAX],
- )
- .cities()
- .owner(Civ.BARBARIAN)
- .entities()
- )
- ]
- if len(lCities) > 5:
- iDivideCounter = 0
- for tCity in lCities:
- iNewCiv = min(civilizations().independents().ids()) + rand(
- max(civilizations().independents().ids())
- - min(civilizations().independents().ids())
- + 1
- )
- if iDivideCounter % 4 in [0, 1]:
- cultureManager(tCity, 50, iNewCiv, Civ.BARBARIAN, False, True, True)
- flipUnitsInCityBefore(tCity, iNewCiv, Civ.BARBARIAN)
- self.setTempFlippingCity(tCity)
- flipCity(
- tCity, 0, 0, iNewCiv, [Civ.BARBARIAN]
- ) # by trade because by conquest may raze the city
- flipUnitsInCityAfter(tCity, iNewCiv)
- iDivideCounter += 1
- return
-
- def initBirth(self, iCurrentTurn, iBirthYear, iCiv):
- iHuman = human()
- if iCurrentTurn == iBirthYear - 1 + self.getSpawnDelay(iCiv) + self.getFlipsDelay(iCiv):
- tCapital = civilization(iCiv).location.capital
- core_tile_min = civilization(iCiv).location.area[AreaType.CORE][Area.TILE_MIN]
- core_tile_max = civilization(iCiv).location.area[AreaType.CORE][Area.TILE_MAX]
- broader_tile_min = civilization(iCiv).location.area[AreaType.BROADER][Area.TILE_MIN]
- broader_tile_max = civilization(iCiv).location.area[AreaType.BROADER][Area.TILE_MAX]
- if self.getFlipsDelay(iCiv) == 0: # city hasn't already been founded
-
- # Absinthe: for the human player, kill all foreign units on the capital plot - this probably fixes a couple instances of the -1 turn autoplay bug
- if iCiv == iHuman:
- killPlot = gc.getMap().plot(tCapital[0], tCapital[1])
- iNumUnitsInAPlot = killPlot.getNumUnits()
- if iNumUnitsInAPlot > 0:
- iSkippedUnit = 0
- for i in range(iNumUnitsInAPlot):
- unit = killPlot.getUnit(iSkippedUnit)
- if unit.getOwner() != iCiv:
- unit.kill(False, Civ.BARBARIAN)
- else:
- iSkippedUnit += 1
-
- # Absinthe: if the plot is owned by a civ, bDeleteEverything becomes True unless there is a human city in the 1+8 neighbour plots.
- bDeleteEverything = False
- if gc.getMap().plot(tCapital[0], tCapital[1]).isOwned():
- if iCiv == iHuman or not gc.getPlayer(iHuman).isAlive():
- bDeleteEverything = True
- else:
- bDeleteEverything = True
- if plots().surrounding(tCapital).cities().owner(iHuman).entities():
- bDeleteEverything = False
-
- if not gc.getMap().plot(tCapital[0], tCapital[1]).isOwned():
- self.birthInFreeRegion(iCiv, tCapital, core_tile_min, core_tile_max)
- elif bDeleteEverything:
- self.setDeleteMode(0, iCiv)
- # Absinthe: kill off units near the starting plot
- killAllUnitsInArea(
- (tCapital[0] - 1, tCapital[1] - 1), (tCapital[0] + 1, tCapital[1] + 1)
- )
- for plot in plots().surrounding(tCapital).entities():
- if plot.isCity():
- plot.eraseAIDevelopment() # new function, similar to erase but won't delete rivers, resources and features
- for civ in civilizations().ids():
- if iCiv != civ:
- plot.setCulture(civ, 0, True)
- plot.setOwner(-1)
- self.birthInFreeRegion(iCiv, tCapital, core_tile_min, core_tile_max)
- else:
- self.birthInForeignBorders(
- iCiv,
- core_tile_min,
- core_tile_max,
- broader_tile_min,
- broader_tile_max,
- tCapital,
- )
- else:
- self.birthInFreeRegion(iCiv, tCapital, core_tile_min, core_tile_max)
-
- # 3MiroCrusader modification. Crusaders cannot change nations.
- # Sedna17: Straight-up no switching within 40 turns of your birth
- if iCurrentTurn == iBirthYear + self.getSpawnDelay(iCiv):
- if (
- gc.getPlayer(iCiv).isAlive()
- and not self.getAlreadySwitched()
- and iCurrentTurn > civilization(iHuman).date.birth + 40
- and not gc.getPlayer(iHuman).getIsCrusader()
- ):
- self.newCivPopup(iCiv)
-
- def deleteMode(self, iCurrentPlayer):
- iCiv = self.getDeleteMode(0)
- tCapital = civilization(iCiv).location.capital
- if iCurrentPlayer == iCiv:
- for plot in plots().surrounding(tCapital, radius=2).entities():
- plot.setCulture(iCiv, 300, True)
- for plot in plots().surrounding(tCapital).entities():
- convertPlotCulture(plot, iCiv, 100, True)
- if plot.getCulture(iCiv) < 3000:
- # 2000 in vanilla/warlords, cos here Portugal is choked by Spanish culture
- plot.setCulture(iCiv, 3000, True)
- plot.setOwner(iCiv)
- self.setDeleteMode(0, -1)
- return
-
- if iCurrentPlayer != iCiv - 1:
- return
-
- for plot in plots().surrounding(tCapital).entities():
- if plot.isOwned():
- for iLoopCiv in civilizations().ids():
- if iLoopCiv != iCiv:
- plot.setCulture(iLoopCiv, 0, True)
- plot.setOwner(iCiv)
-
- # Absinthe: what's this +-11? do we really want to move all flipped units in the initial turn to the starting plot??
-
- def birthInFreeRegion(self, iCiv, tCapital, tTopLeft, tBottomRight):
- startingPlot = gc.getMap().plot(tCapital[0], tCapital[1])
- if self.getFlipsDelay(iCiv) == 0:
- iFlipsDelay = self.getFlipsDelay(iCiv) + 2
-
- if iFlipsDelay > 0:
- # Absinthe: kill off units near the starting plot
- killAllUnitsInArea(
- (tCapital[0] - 1, tCapital[1] - 1), (tCapital[0] + 1, tCapital[1] + 1)
- )
- self.createStartingUnits(iCiv, (tCapital[0], tCapital[1]))
- reveal_areas(iCiv)
- set_initial_contacts(iCiv)
- # Absinthe: there was another mistake here with barbarian and indy unit flips...
- # we don't simply want to check an area based on distance from capital, as it might lead out from the actual spawn area
- # so we only check plots which are in the core area: in 4 distance for barb units, 2 distance for indies
- lPlotBarbFlip = []
- lPlotIndyFlip = []
- # if inside the core rectangle and extra plots, and in 4 (barb) or 2 (indy) distance from the starting plot, append to barb or indy flip zone
-
- lSurroundingPlots4 = [
- location(plot) for plot in plots().surrounding(tCapital, radius=4).entities()
- ]
- lSurroundingPlots2 = [
- location(plot) for plot in plots().surrounding(tCapital, radius=2).entities()
- ]
- for tPlot in (
- plots()
- .rectangle(tTopLeft, tBottomRight)
- .add(civilization(iCiv).location.area[AreaType.CORE][Area.ADDITIONAL_TILES])
- .apply(location) # TODO fix this with _keyify by default
- ):
- if tPlot in lSurroundingPlots2:
- lPlotIndyFlip.append(tPlot)
- lPlotBarbFlip.append(tPlot)
- elif tPlot in lSurroundingPlots4:
- lPlotBarbFlip.append(tPlot)
- # remaining barbs in the region: killed for the human player, flipped for the AI
- if iCiv == human():
- killUnitsInPlots(lPlotBarbFlip, Civ.BARBARIAN)
- else:
- flipUnitsInPlots(lPlotBarbFlip, iCiv, Civ.BARBARIAN, True, True)
- for iIndyCiv in civilizations().independents().ids():
- # remaining independents in the region: killed for the human player, flipped for the AI
- if iCiv == human():
- killUnitsInPlots(lPlotIndyFlip, iIndyCiv)
- else:
- flipUnitsInPlots(lPlotIndyFlip, iCiv, iIndyCiv, True, False)
- set_starting_techs(iCiv)
- setPlagueCountdown(iCiv, -PLAGUE_IMMUNITY)
- clearPlague(iCiv)
- self.setFlipsDelay(iCiv, iFlipsDelay) # save
-
- else: # starting units have already been placed, now the second part
- iNumAICitiesConverted, iNumHumanCitiesToConvert = self.convertSurroundingCities(
- iCiv, tTopLeft, tBottomRight
- )
- self.convertSurroundingPlotCulture(iCiv, tTopLeft, tBottomRight)
- if iCiv != human():
- flipUnitsInArea(
- tTopLeft, tBottomRight, iCiv, Civ.BARBARIAN, False, True
- ) # remaining barbs in the region now belong to the new civ
- flipUnitsInPlots(
- civilization(iCiv).location.area[AreaType.CORE][Area.ADDITIONAL_TILES],
- iCiv,
- Civ.BARBARIAN,
- False,
- True,
- ) # remaining barbs in the region now belong to the new civ
- for iIndyCiv in civilizations().independents().ids():
- if iCiv != human():
- flipUnitsInArea(
- tTopLeft, tBottomRight, iCiv, iIndyCiv, False, False
- ) # remaining independents in the region now belong to the new civ
- flipUnitsInPlots(
- civilization(iCiv).location.area[AreaType.CORE][Area.ADDITIONAL_TILES],
- iCiv,
- iIndyCiv,
- False,
- False,
- ) # remaining independents in the region now belong to the new civ
- # cover plots revealed by the catapult
- plotZero = gc.getMap().plot(32, 0) # sync with rfcebalance module
- if plotZero.getNumUnits():
- catapult = plotZero.getUnit(0)
- catapult.kill(False, iCiv)
- gc.getMap().plot(31, 0).setRevealed(iCiv, False, True, -1)
- gc.getMap().plot(32, 0).setRevealed(iCiv, False, True, -1)
- gc.getMap().plot(33, 0).setRevealed(iCiv, False, True, -1)
- gc.getMap().plot(31, 1).setRevealed(iCiv, False, True, -1)
- gc.getMap().plot(32, 1).setRevealed(iCiv, False, True, -1)
- gc.getMap().plot(33, 1).setRevealed(iCiv, False, True, -1)
-
- if gc.getPlayer(iCiv).getNumCities() > 0:
- capital = gc.getPlayer(iCiv).getCapitalCity()
- create_starting_workers(iCiv, (capital.getX(), capital.getY()))
- if iCiv == Civ.OTTOMAN:
- ottoman_invasion(iCiv, (77, 23))
-
- if iNumHumanCitiesToConvert > 0:
- self.flipPopup(iCiv, tTopLeft, tBottomRight)
-
- def birthInForeignBorders(
- self, iCiv, tTopLeft, tBottomRight, tBroaderTopLeft, tBroaderBottomRight, tCapital
- ):
- iNumAICitiesConverted, iNumHumanCitiesToConvert = self.convertSurroundingCities(
- iCiv, tTopLeft, tBottomRight
- )
- self.convertSurroundingPlotCulture(iCiv, tTopLeft, tBottomRight)
-
- # now starting units must be placed
- if iNumAICitiesConverted > 0:
- # Absinthe: there is an issue that core area is not calculated correctly for flips, as the additional tiles in lExtraPlots are not checked here
- # so if all flipped cities are outside of the core area (they are in the "exceptions"), the civ will start without it's starting units and techs
- plotList = squareSearch(tTopLeft, tBottomRight, ownedCityPlots, iCiv)
- # Absinthe: add the exception plots
- for plot in civilization(iCiv).location.area[AreaType.CORE][Area.ADDITIONAL_TILES]:
- plot = gc.getMap().plot(*plot)
- if plot.getOwner() == iCiv:
- if plot.isCity():
- plotList.append(plot)
- if plotList:
- plot = choice(plotList)
- self.createStartingUnits(iCiv, plot)
- reveal_areas(iCiv)
- set_initial_contacts(iCiv)
- set_starting_techs(iCiv)
- setPlagueCountdown(iCiv, -PLAGUE_IMMUNITY)
- clearPlague(iCiv)
- flipUnitsInArea(
- tTopLeft, tBottomRight, iCiv, Civ.BARBARIAN, False, True
- ) # remaining barbs in the region now belong to the new civ
- flipUnitsInPlots(
- civilization(iCiv).location.area[AreaType.CORE][Area.ADDITIONAL_TILES],
- iCiv,
- Civ.BARBARIAN,
- False,
- True,
- ) # remaining barbs in the region now belong to the new civ
- for iIndyCiv in civilizations().independents().ids():
- flipUnitsInArea(
- tTopLeft, tBottomRight, iCiv, iIndyCiv, False, False
- ) # remaining independents in the region now belong to the new civ
- flipUnitsInPlots(
- civilization(iCiv).location.area[AreaType.CORE][Area.ADDITIONAL_TILES],
- iCiv,
- iIndyCiv,
- False,
- False,
- ) # remaining independents in the region now belong to the new civ
-
- else:
- # Absinthe: there is an issue that core area is not calculated correctly for flips, as the additional tiles in lExtraPlots are not checked here
- # so if all flipped cities are outside of the core area (they are in the "exceptions"), the civ will start without it's starting units and techs
- plotList = squareSearch(tTopLeft, tBottomRight, goodPlots, [])
- # Absinthe: add the exception plots
- for plot in civilization(iCiv).location.area[AreaType.CORE][Area.ADDITIONAL_TILES]:
- plot = gc.getMap().plot(*plot)
- if (plot.isHills() or plot.isFlatlands()) and not plot.isImpassable():
- if not plot.isUnit():
- if plot.getTerrainType() not in [
- Terrain.DESERT,
- Terrain.TUNDRA,
- ] and plot.getFeatureType() not in [
- Feature.MARSH,
- Feature.JUNGLE,
- ]:
- if plot.countTotalCulture() == 0:
- plotList.append(plot)
- if plotList:
- plot = choice(plotList)
- self.createStartingUnits(iCiv, plot)
- reveal_areas(iCiv)
- set_initial_contacts(iCiv)
- set_starting_techs(iCiv)
- setPlagueCountdown(iCiv, -PLAGUE_IMMUNITY)
- clearPlague(iCiv)
- else:
- plotList = squareSearch(tBroaderTopLeft, tBroaderBottomRight, goodPlots, [])
- if plotList:
- plot = choice(plotList)
- self.createStartingUnits(iCiv, plot)
- reveal_areas(iCiv)
- set_initial_contacts(iCiv)
- create_starting_workers(iCiv, plot)
- if iCiv == Civ.OTTOMAN:
- ottoman_invasion(iCiv, (77, 23))
- set_starting_techs(iCiv)
- setPlagueCountdown(iCiv, -PLAGUE_IMMUNITY)
- clearPlague(iCiv)
- flipUnitsInArea(
- tTopLeft, tBottomRight, iCiv, Civ.BARBARIAN, True, True
- ) # remaining barbs in the region now belong to the new civ
- flipUnitsInPlots(
- civilization(iCiv).location.area[AreaType.CORE][Area.ADDITIONAL_TILES],
- iCiv,
- Civ.BARBARIAN,
- True,
- True,
- ) # remaining barbs in the region now belong to the new civ
- for iIndyCiv in civilizations().independents().ids():
- flipUnitsInArea(
- tTopLeft, tBottomRight, iCiv, iIndyCiv, True, False
- ) # remaining independents in the region now belong to the new civ
- flipUnitsInPlots(
- civilization(iCiv).location.area[AreaType.CORE][Area.ADDITIONAL_TILES],
- iCiv,
- iIndyCiv,
- True,
- False,
- ) # remaining independents in the region now belong to the new civ
-
- if iNumHumanCitiesToConvert > 0:
- self.flipPopup(iCiv, tTopLeft, tBottomRight)
-
- def convertSurroundingCities(self, iCiv, tTopLeft, tBottomRight):
- iConvertedCitiesCount = 0
- iNumHumanCities = 0
- self.setSpawnWar(0)
-
- # collect all the cities in the spawn region
- for city in (
- plots()
- .rectangle(tTopLeft, tBottomRight)
- .add(civilization(iCiv).location.area[AreaType.CORE][Area.ADDITIONAL_TILES])
- .cities()
- .not_owner(iCiv)
- .entities()
- ):
- # if 0, no flip; if > 0, flip will occur with the value as variable for CultureManager()
- iCultureChange = 0
-
- if is_minor_civ(city):
- iCultureChange = 100
- # case 2: human city
- elif city.getOwner() == human() and not city.isCapital():
- if iNumHumanCities == 0:
- iNumHumanCities += 1
- # case 3: other
- elif not city.isCapital(): # 3Miro: this keeps crashing in the C++, makes no sense
- if iConvertedCitiesCount < 6: # there won't be more than 5 flips in the area
- iCultureChange = 50
- if turn() <= civilization(iCiv).date.birth + 5: # if we're during a birth
- rndNum = percentage()
- # 3Miro: I don't know why the iOwner check is needed below, but the module crashes sometimes
- if (
- is_major_civ(city)
- and rndNum >= civilization(city).ai.stop_birth_threshold
- ):
- if not civilization(iCiv).at_war(city):
- civilization(iCiv).declare_war(city)
- if player(iCiv).getNumCities() > 0:
- if location(player(iCiv).getCapitalCity()) != (-1, -1):
- # this check is needed, otherwise game crashes
- self.createAdditionalUnits(
- iCiv, player(iCiv).getCapitalCity()
- )
- else:
- self.createAdditionalUnits(
- iCiv, civilization(iCiv).location.capital
- )
-
- if iCultureChange > 0:
- cultureManager(
- location(city), iCultureChange, iCiv, city.getOwner(), True, False, False
- )
- flipUnitsInCityBefore(location(city), iCiv, city.getOwner())
- self.setTempFlippingCity(location(city)) # necessary for the (688379128, 0) bug
- flipCity(location(city), 0, 0, iCiv, [city.getOwner()])
- flipUnitsInCityAfter(self.getTempFlippingCity(), iCiv)
- iConvertedCitiesCount += 1
-
- if iConvertedCitiesCount > 0:
- if player(iCiv).isHuman():
- message(iCiv, text("TXT_KEY_FLIP_TO_US"), force=True, color=MessageData.GREEN)
- return (iConvertedCitiesCount, iNumHumanCities)
-
- def convertSurroundingPlotCulture(self, iCiv, tTopLeft, tBottomRight):
- for plot in (
- plots()
- .rectangle(tTopLeft, tBottomRight)
- .add(civilization(iCiv).location.area[AreaType.CORE][Area.ADDITIONAL_TILES])
- .filter(lambda p: not p.isCity())
- .entities()
- ):
- convertPlotCulture(plot, iCiv, 100, False)
-
- def findSeaPlots(self, tCoords, iRange):
- """Searches a sea plot that isn't occupied by a unit within range of the starting coordinates"""
- # we can search inside other players territory, since all naval units can cross sea borders
- seaPlotList = [
- location(plot)
- for plot in (
- plots()
- .surrounding(tCoords, radius=iRange)
- .water()
- .filter(lambda p: not p.isUnit())
- .entities()
- )
- ]
- # this is a good plot, so paint it and continue search
- if seaPlotList:
- return choice(seaPlotList)
- return None
-
- def giveColonists(self, iCiv, tBroaderAreaTL, tBroaderAreaBR):
- # 3Miro: Conquistador event
- pass
-
- def onFirstContact(self, iTeamX, iHasMetTeamY):
- # 3Miro: Conquistador event
- pass
-
- def getSpecialRespawn(
- self, iGameTurn
- ): # Absinthe: only the first civ for which it is True is returned, so the order of the civs is very important here
- if self.canSpecialRespawn(Civ.FRANCE, iGameTurn, 12):
- # France united in it's modern borders, start of the Bourbon royal line
- if year(1588) < iGameTurn < year(1700) and iGameTurn % 5 == 3:
- return Civ.FRANCE
- if self.canSpecialRespawn(Civ.ARABIA, iGameTurn):
- # Saladin, Ayyubid Dynasty
- if year(1080) < iGameTurn < year(1291) and iGameTurn % 7 == 3:
- return Civ.ARABIA
- if self.canSpecialRespawn(Civ.BULGARIA, iGameTurn):
- # second Bulgarian Empire
- if year(1080) < iGameTurn < year(1299) and iGameTurn % 5 == 1:
- return Civ.BULGARIA
- if self.canSpecialRespawn(Civ.CORDOBA, iGameTurn):
- # special respawn as the Hafsid dynasty in North Africa
- if year(1229) < iGameTurn < year(1540) and iGameTurn % 5 == 3:
- return Civ.CORDOBA
- if self.canSpecialRespawn(Civ.BURGUNDY, iGameTurn, 20):
- # Burgundy in the 100 years war
- if year(1336) < iGameTurn < year(1453) and iGameTurn % 8 == 1:
- return Civ.BURGUNDY
- if self.canSpecialRespawn(Civ.PRUSSIA, iGameTurn):
- # respawn as the unified Prussia
- if iGameTurn > year(1618) and iGameTurn % 3 == 1:
- return Civ.PRUSSIA
- if self.canSpecialRespawn(Civ.HUNGARY, iGameTurn):
- # reconquest of Buda from the Ottomans
- if iGameTurn > year(1680) and iGameTurn % 6 == 2:
- return Civ.HUNGARY
- if self.canSpecialRespawn(Civ.CASTILE, iGameTurn, 25):
- # respawn as the Castile/Aragon Union
- if year(1470) < iGameTurn < year(1580) and iGameTurn % 5 == 0:
- return Civ.CASTILE
- if self.canSpecialRespawn(Civ.ENGLAND, iGameTurn, 12):
- # restoration of monarchy
- if iGameTurn > year(1660) and iGameTurn % 6 == 2:
- return Civ.ENGLAND
- if self.canSpecialRespawn(Civ.SCOTLAND, iGameTurn, 30):
- if iGameTurn <= year(1600) and iGameTurn % 6 == 3:
- return Civ.SCOTLAND
- if self.canSpecialRespawn(Civ.PORTUGAL, iGameTurn):
- # respawn to be around for colonies
- if year(1431) < iGameTurn < year(1580) and iGameTurn % 5 == 3:
- return Civ.PORTUGAL
- if self.canSpecialRespawn(Civ.AUSTRIA, iGameTurn):
- # increasing Habsburg influence in Hungary
- if year(1526) < iGameTurn < year(1690) and iGameTurn % 8 == 3:
- return Civ.AUSTRIA
- if self.canSpecialRespawn(Civ.KIEV, iGameTurn):
- # Cossack Hetmanate
- if year(1620) < iGameTurn < year(1750) and iGameTurn % 5 == 3:
- return Civ.KIEV
- if self.canSpecialRespawn(Civ.MOROCCO, iGameTurn):
- # Alaouite Dynasty
- if iGameTurn > year(1631) and iGameTurn % 8 == 7:
- return Civ.MOROCCO
- if self.canSpecialRespawn(Civ.ARAGON, iGameTurn):
- # Kingdom of Sicily
- if iGameTurn > year(1700) and iGameTurn % 8 == 7:
- return Civ.ARAGON
- if self.canSpecialRespawn(Civ.VENECIA, iGameTurn):
- if year(1401) < iGameTurn < year(1571) and iGameTurn % 8 == 7:
- return Civ.VENECIA
- if self.canSpecialRespawn(Civ.POLAND, iGameTurn):
- if year(1410) < iGameTurn < year(1570) and iGameTurn % 8 == 7:
- return Civ.POLAND
- if self.canSpecialRespawn(Civ.OTTOMAN, iGameTurn):
- # Mehmed II's conquests
- if year(1453) < iGameTurn < year(1514) and iGameTurn % 6 == 3:
- return Civ.OTTOMAN
- return -1
-
- def canSpecialRespawn(self, iPlayer, iGameTurn, iLastAliveInterval=10):
- pPlayer = gc.getPlayer(iPlayer)
- if pPlayer.isAlive():
- return False
- if pPlayer.getEverRespawned():
- return False
- if iGameTurn <= civilization(iPlayer).date.birth + 25:
- return False
- if iGameTurn <= (getLastTurnAlive(iPlayer) + iLastAliveInterval):
- return False
- return True
-
- def initMinorBetrayal(self, iCiv):
- iHuman = human()
- plotList = squareSearch(
- civilization(iCiv).location.area[AreaType.CORE][Area.TILE_MIN],
- civilization(iCiv).location.area[AreaType.CORE][Area.TILE_MAX],
- outerInvasion,
- [],
- )
- if plotList:
- tPlot = choice(plotList)
- self.createAdditionalUnits(iCiv, tPlot)
- self.unitsBetrayal(
- iCiv,
- iHuman,
- civilization(iCiv).location.area[AreaType.CORE][Area.TILE_MIN],
- civilization(iCiv).location.area[AreaType.CORE][Area.TILE_MAX],
- tPlot,
- )
-
- def initBetrayal(self):
- iHuman = human()
- turnsLeft = self.getBetrayalTurns()
- plotList = squareSearch(
- self.getTempTopLeft(), self.getTempBottomRight(), outerInvasion, []
- )
- if not plotList:
- plotList = squareSearch(
- self.getTempTopLeft(),
- self.getTempBottomRight(),
- innerSpawn,
- [self.getOldCivFlip(), self.getNewCivFlip()],
- )
- if not plotList:
- plotList = squareSearch(
- self.getTempTopLeft(),
- self.getTempBottomRight(),
- forcedInvasion,
- [self.getOldCivFlip(), self.getNewCivFlip()],
- )
- if plotList:
- tPlot = choice(plotList)
- if turnsLeft == iBetrayalPeriod:
- self.createAdditionalUnits(self.getNewCivFlip(), tPlot)
- self.unitsBetrayal(
- self.getNewCivFlip(),
- self.getOldCivFlip(),
- self.getTempTopLeft(),
- self.getTempBottomRight(),
- tPlot,
- )
- self.setBetrayalTurns(turnsLeft - 1)
-
- def unitsBetrayal(self, iNewOwner, iOldOwner, tTopLeft, tBottomRight, tPlot):
- if gc.getPlayer(self.getOldCivFlip()).isHuman():
- message(self.getOldCivFlip(), text("TXT_KEY_FLIP_BETRAYAL"), color=MessageData.RED)
- elif gc.getPlayer(self.getNewCivFlip()).isHuman():
- message(
- self.getNewCivFlip(), text("TXT_KEY_FLIP_BETRAYAL_NEW"), color=MessageData.GREEN
- )
- for unit in plots().rectangle(tTopLeft, tBottomRight).units().owner(iOldOwner).entities():
- if percentage_chance(iBetrayalThreshold, reverse=True):
- if unit.getDomainType() == DomainTypes.DOMAIN_LAND:
- iUnitType = unit.getUnitType()
- unit.kill(False, iNewOwner)
- make_unit(iNewOwner, iUnitType, tPlot)
- i = i - 1
-
- def createAdditionalUnits(self, iCiv, tPlot):
- # additional starting units if someone declares war on the civ during birth
- units = civilization(iCiv).initial.get("additional_units")
- if units is not None:
- if iCiv != human():
- for unit, number in units.get(PlayerType.AI, {}).items():
- make_units(iCiv, unit, tPlot, number)
- else:
- for unit, number in units.get(PlayerType.HUMAN, {}).items():
- make_units(iCiv, unit, tPlot, number)
-
- def createStartingUnits(self, iCiv, tPlot):
- # set the provinces
- self.pm.onSpawn(iCiv)
-
- units = civilization(iCiv).initial.get("units")
- if units is not None:
- for unit, number in units.get(PlayerType.ANY, {}).items():
- make_units(iCiv, unit, tPlot, number)
-
- if iCiv != human():
- for unit, number in units.get(PlayerType.AI, {}).items():
- make_units(iCiv, unit, tPlot, number)
- else:
- for unit, number in units.get(PlayerType.HUMAN, {}).items():
- make_units(iCiv, unit, tPlot, number)
-
- if iCiv == Civ.VENECIA:
- tSeaPlot = self.findSeaPlots((57, 35), 2)
- if tSeaPlot:
- make_unit(iCiv, Unit.WORKBOAT, tSeaPlot)
- make_unit(iCiv, Unit.GALLEY, tSeaPlot, UnitAITypes.UNITAI_SETTLER_SEA)
- make_unit(iCiv, Unit.GALLEY, tSeaPlot, UnitAITypes.UNITAI_ESCORT_SEA)
- make_unit(iCiv, Unit.SETTLER, tSeaPlot)
- make_unit(iCiv, Unit.ARCHER, tSeaPlot)
- make_unit(iCiv, Unit.GALLEY, tSeaPlot, UnitAITypes.UNITAI_SETTLER_SEA)
- make_unit(iCiv, Unit.SETTLER, tSeaPlot)
- make_unit(iCiv, Unit.SPEARMAN, tSeaPlot)
- elif iCiv == Civ.NORWAY:
- tSeaPlot = self.findSeaPlots(tPlot, 2)
- if tSeaPlot:
- make_unit(iCiv, Unit.GALLEY, tSeaPlot, UnitAITypes.UNITAI_SETTLER_SEA)
- make_unit(iCiv, Unit.GALLEY, tSeaPlot, UnitAITypes.UNITAI_ESCORT_SEA)
- make_unit(iCiv, Unit.GALLEY, tSeaPlot, UnitAITypes.UNITAI_ESCORT_SEA)
- make_unit(iCiv, Unit.SETTLER, tSeaPlot)
- make_unit(iCiv, Unit.ARCHER, tSeaPlot)
- elif iCiv == Civ.DENMARK:
- tSeaPlot = self.findSeaPlots((60, 57), 2)
- if tSeaPlot:
- make_unit(iCiv, Unit.GALLEY, tSeaPlot, UnitAITypes.UNITAI_SETTLER_SEA)
- make_unit(iCiv, Unit.GALLEY, tSeaPlot, UnitAITypes.UNITAI_SETTLER_SEA)
- make_unit(iCiv, Unit.GALLEY, tSeaPlot, UnitAITypes.UNITAI_ESCORT_SEA)
- make_unit(iCiv, Unit.SETTLER, tSeaPlot)
- make_unit(iCiv, Unit.CROSSBOWMAN, tSeaPlot)
- make_unit(iCiv, Unit.SETTLER, tSeaPlot)
- make_unit(iCiv, Unit.CROSSBOWMAN, tSeaPlot)
- elif iCiv == Civ.GENOA:
- tSeaPlot = self.findSeaPlots(tPlot, 2)
- if tSeaPlot:
- make_unit(iCiv, Unit.GALLEY, tSeaPlot, UnitAITypes.UNITAI_SETTLER_SEA)
- make_unit(iCiv, Unit.WAR_GALLEY, tSeaPlot, UnitAITypes.UNITAI_ESCORT_SEA)
- make_unit(iCiv, Unit.SETTLER, tSeaPlot)
- make_unit(iCiv, Unit.CROSSBOWMAN, tSeaPlot)
- make_unit(iCiv, Unit.WORKBOAT, tSeaPlot)
- elif iCiv == Civ.ENGLAND:
- tSeaPlot = self.findSeaPlots((43, 53), 1)
- if tSeaPlot:
- make_unit(iCiv, Unit.GALLEY, tSeaPlot, UnitAITypes.UNITAI_SETTLER_SEA)
- make_unit(iCiv, Unit.WAR_GALLEY, tSeaPlot, UnitAITypes.UNITAI_ESCORT_SEA)
- elif iCiv == Civ.ARAGON:
- tSeaPlot = self.findSeaPlots((42, 29), 1)
- if tSeaPlot:
- make_units(iCiv, Unit.WAR_GALLEY, tSeaPlot, 2, UnitAITypes.UNITAI_ESCORT_SEA)
- make_unit(iCiv, Unit.COGGE, tSeaPlot, UnitAITypes.UNITAI_SETTLER_SEA)
- make_unit(iCiv, Unit.SETTLER, tSeaPlot)
- make_unit(iCiv, Unit.CROSSBOWMAN, tSeaPlot)
- make_unit(iCiv, Unit.WORKBOAT, tSeaPlot)
- elif iCiv == Civ.SWEDEN:
- tSeaPlot = self.findSeaPlots((69, 65), 2)
- if tSeaPlot:
- make_unit(iCiv, Unit.WORKBOAT, tSeaPlot)
- make_unit(iCiv, Unit.WAR_GALLEY, tSeaPlot, UnitAITypes.UNITAI_ESCORT_SEA)
- make_units(iCiv, Unit.COGGE, tSeaPlot, 2, UnitAITypes.UNITAI_SETTLER_SEA)
- make_unit(iCiv, Unit.SETTLER, tSeaPlot)
- make_unit(iCiv, Unit.ARBALEST, tSeaPlot)
- elif iCiv == Civ.DUTCH:
- tSeaPlot = self.findSeaPlots(tPlot, 2)
- if tSeaPlot:
- make_units(iCiv, Unit.WORKBOAT, tSeaPlot, 2)
- make_units(iCiv, Unit.GALLEON, tSeaPlot, 2)
diff --git a/Assets/Python/components/Stability.py b/Assets/Python/components/Stability.py
deleted file mode 100644
index 11790a3b0..000000000
--- a/Assets/Python/components/Stability.py
+++ /dev/null
@@ -1,1012 +0,0 @@
-# Rhye's and Fall of Civilization: Europe - Stability
-
-from CvPythonExtensions import *
-from Core import get_scenario, civilization, civilizations, message, human, cities, text
-
-from Consts import MessageData
-from CoreTypes import (
- Building,
- Civ,
- Civic,
- Project,
- Scenario,
- Religion,
- FaithPointBonusCategory,
- ProvinceType,
- SpecialParameter,
- UniquePower,
- StabilityCategory,
- Technology,
- Wonder,
-)
-from PyUtils import percentage_chance, rand
-
-from ProvinceMapData import PROVINCES_MAP
-from RFCUtils import collapseImmune, getLastRespawnTurn, getUniqueBuilding, killAndFragmentCiv
-import RiseAndFall
-import Provinces
-from Secession import revoltCity
-
-rnf = RiseAndFall.RiseAndFall()
-pm = Provinces.ProvinceManager()
-
-gc = CyGlobalContext()
-
-tStabilityPenalty = (-5, -2, 0, 0, 0) # province type: unstable, border, potential, historic, core
-
-
-class Stability:
- def setup(self): # Sets starting stability
- for iPlayer in civilizations().majors().ids():
- pPlayer = gc.getPlayer(iPlayer)
- for iCath in range(4):
- pPlayer.changeStabilityBase(iCath, -pPlayer.getStabilityBase(iCath))
- pPlayer.setStabilityVary(iCath, 0)
- pPlayer.setStabilitySwing(0)
- # Absinthe: bonus stability for the human player based on difficulty level
- iHandicap = gc.getGame().getHandicapType()
- if iHandicap == 0:
- gc.getPlayer(human()).changeStabilityBase(StabilityCategory.EXPANSION, 6)
- elif iHandicap == 1:
- gc.getPlayer(human()).changeStabilityBase(StabilityCategory.EXPANSION, 2)
-
- # Absinthe: Stability is accounted properly for stuff preplaced in the scenario file - from RFCE++
- for iPlayer in civilizations().majors().ids():
- pPlayer = gc.getPlayer(iPlayer)
- teamPlayer = gc.getTeam(pPlayer.getTeam())
- iCounter = 0
- for pCity in cities().owner(iPlayer).entities():
- iCounter += 1
- iOldStab = pPlayer.getStability()
-
- # Province stability
- iProv = PROVINCES_MAP[pCity.getY()][pCity.getX()]
- iProvinceType = pPlayer.getProvinceType(iProv)
- if iProvinceType == ProvinceType.CORE:
- pPlayer.changeStabilityBase(StabilityCategory.EXPANSION, 1)
- elif not gc.hasUP(
- iPlayer, UniquePower.STABILITY_BONUS_FOUNDING
- ): # no instability with the Settler UP
- if iProvinceType == ProvinceType.CONTESTED:
- pPlayer.changeStabilityBase(StabilityCategory.EXPANSION, -1)
- elif iProvinceType == ProvinceType.NONE:
- pPlayer.changeStabilityBase(StabilityCategory.EXPANSION, -2)
-
- # Building stability: only a chance for these, as all the permanent negative stability modifiers are missing up to the start
- if pCity.hasBuilding(
- getUniqueBuilding(iPlayer, Building.MANOR_HOUSE)
- ) and percentage_chance(70, strict=True):
- pPlayer.changeStabilityBase(StabilityCategory.ECONOMY, 1)
- if pCity.hasBuilding(
- getUniqueBuilding(iPlayer, Building.CASTLE)
- ) and percentage_chance(70, strict=True):
- pPlayer.changeStabilityBase(StabilityCategory.EXPANSION, 1)
- if pCity.hasBuilding(
- getUniqueBuilding(iPlayer, Building.NIGHT_WATCH)
- ) and percentage_chance(70, strict=True):
- pPlayer.changeStabilityBase(StabilityCategory.CIVICS, 1)
- if pCity.hasBuilding(
- getUniqueBuilding(iPlayer, Building.COURTHOUSE)
- ) and percentage_chance(70, strict=True):
- pPlayer.changeStabilityBase(StabilityCategory.CITIES, 1)
-
- # Small boost for small civs
- if iCounter < 6: # instead of the additional boost for the first few cities
- pPlayer.changeStabilityBase(StabilityCategory.EXPANSION, (6 - iCounter) / 2 + 1)
-
- # Known techs which otherwise give instability should also give the penalty here
- for iTech in [
- Technology.FEUDALISM,
- Technology.GUILDS,
- Technology.GUNPOWDER,
- Technology.PROFESSIONAL_ARMY,
- Technology.NATIONALISM,
- Technology.CIVIL_SERVICE,
- Technology.ECONOMICS,
- Technology.MACHINERY,
- Technology.ARISTOCRACY,
- ]:
- if teamPlayer.isHasTech(iTech):
- gc.getPlayer(iPlayer).changeStabilityBase(StabilityCategory.ECONOMY, -1)
-
- # Absinthe: update all potential provinces at the start for all living players (needed for the scenario)
- if pPlayer.isAlive():
- pm.updatePotential(iPlayer)
-
- # Absinthe: AI stability bonus - for civs that have a hard time at the beginning
- # for example France, Arabia, Bulgaria, Cordoba, Ottomans
- for iPlayer in civilizations().main().ids():
- pPlayer = gc.getPlayer(iPlayer)
- if iPlayer != human():
- pPlayer.changeStabilityBase(
- StabilityCategory.EXPANSION, civilization(iPlayer).ai.stability_bonus
- )
-
- # Absinthe: update Byzantine stability on the start of the game
- if get_scenario() == Scenario.i500AD:
- # small stability boost for the human player for the first UHV
- if Civ.BYZANTIUM == human():
- pByzantium = gc.getPlayer(Civ.BYZANTIUM)
- pByzantium.changeStabilityBase(StabilityCategory.EXPANSION, 4)
- self.recalcEpansion(Civ.BYZANTIUM)
-
- def checkTurn(self, iGameTurn):
- # Absinthe: logging AI stability levels
- if iGameTurn % 9 == 2:
- for iPlayer in civilizations().main().ids():
- pPlayer = gc.getPlayer(iPlayer)
- if pPlayer.getStability() != 0:
- print(
- "AI stability check:",
- pPlayer.getCivilizationDescription(0),
- pPlayer.getStability(),
- )
-
- def updateBaseStability(
- self, iGameTurn, iPlayer
- ): # Base stability is temporary (i.e. turn-based) stability
- # 3Miro: this is called for every player
-
- pPlayer = gc.getPlayer(iPlayer)
- teamPlayer = gc.getTeam(pPlayer.getTeam())
-
- # Swing stability converges to zero very fast
- iStabilitySwing = pPlayer.getStabilitySwing()
- if iStabilitySwing < -3 or iStabilitySwing > 3:
- pPlayer.setStabilitySwing(pPlayer.getStabilitySwing() / 2)
- elif iStabilitySwing < 0:
- pPlayer.setStabilitySwing(min(0, pPlayer.getStabilitySwing() + 2))
- elif iStabilitySwing > 0:
- pPlayer.setStabilitySwing(max(0, pPlayer.getStabilitySwing() - 2))
-
- # Absinthe: Anarchy swing stability gets halved every turn
- iStabSwingAnarchy = pPlayer.getStabSwingAnarchy()
- if iStabSwingAnarchy > 1:
- pPlayer.setStabSwingAnarchy(pPlayer.getStabSwingAnarchy() / 2)
- elif iStabSwingAnarchy == 1:
- pPlayer.setStabSwingAnarchy(0)
-
- # Absinthe: anarchy timer refreshes later in the turn, so it should be reduced by 1 if we want to have it on the correct turns (if nothing else then for the human player)
- # but this also means that all 1st turn instability has to be added directly on the revolution / converting - CvPlayer::revolution and CvPlayer::convert
- if pPlayer.getAnarchyTurns() - 1 > 0:
- self.recalcCivicCombos(iPlayer)
- self.recalcEpansion(iPlayer)
- iNumCities = pPlayer.getNumCities()
-
- if iPlayer != Civ.PRUSSIA: # Absinthe: Prussian UP
- if pPlayer.isHuman():
- # Absinthe: anarchy base instability
- pPlayer.changeStabilityBase(
- StabilityCategory.CIVICS, min(0, max(-2, (-iNumCities + 4) / 7))
- ) # 0 with 1-4 cities, -1 with 5-11 cities, -2 with at least 12 cities
-
- # Absinthe: more constant swing instability during anarchy, instead of ever-increasing instability from it
- iStabSwingAnarchy = pPlayer.getStabSwingAnarchy()
- if (
- iStabSwingAnarchy > 0
- ): # half of it is already included in the swing, we only add the other half
- pPlayer.setStabSwingAnarchy(4)
- else: # safety net (should be positive, as we add it before the first check)
- pPlayer.setStabSwingAnarchy(8)
- pPlayer.setStabilitySwing(
- pPlayer.getStabilitySwing() - pPlayer.getStabSwingAnarchy()
- )
-
- else:
- # Absinthe: anarchy base instability
- pPlayer.changeStabilityBase(
- StabilityCategory.CIVICS, min(0, max(-1, (-iNumCities + 6) / 7))
- ) # Absinthe: reduced for the AI: 0 with 1-6 cities, -1 with at least 7
-
- # Absinthe: more constant swing instability during anarchy, instead of ever-increasing instability from it
- iStabSwingAnarchy = pPlayer.getStabSwingAnarchy()
- if (
- iStabSwingAnarchy > 0
- ): # half of it is already included in the swing, we only add the other half
- pPlayer.setStabSwingAnarchy(2)
- else: # safety net (should be positive, as we add it before the first check)
- pPlayer.setStabSwingAnarchy(4)
- pPlayer.setStabilitySwing(
- pPlayer.getStabilitySwing() - pPlayer.getStabSwingAnarchy()
- )
-
- if (
- pPlayer.getWarPeaceChange() == -1
- ): # Whenever your nation switches from peace to the state of war (with a major nation)
- gc.getPlayer(iPlayer).changeStabilityBase(
- StabilityCategory.CITIES, -1
- ) # 1 permanent stability loss, since your people won't appreciate leaving the state of peace
- pPlayer.setStabilitySwing(pPlayer.getStabilitySwing() - 3)
-
- if (iGameTurn + iPlayer) % 3 == 0: # Economy Check every 3 turns
- self.recalcEconomy(iPlayer)
-
- self.recalcCity(iPlayer) # update city stability
-
- # Absinthe: Collapse dates for AI nations
- if (
- iGameTurn > civilization(iPlayer).date.collapse
- and iPlayer != human()
- and pPlayer.isAlive()
- ):
- # Absinthe: -1 stability every 4 turns up to a total of -15 stability
- if iGameTurn % 4 == 0 and iGameTurn <= civilization(iPlayer).date.collapse + 60:
- pPlayer.changeStabilityBase(StabilityCategory.CITIES, -1)
-
- def refreshBaseStability(
- self, iPlayer
- ): # Base stability is temporary (i.e. turn-based) stability
- # Absinthe: this is called upon entering the stability/finance screen (F2)
-
- pPlayer = gc.getPlayer(iPlayer)
-
- self.recalcCivicCombos(iPlayer)
- self.recalcEpansion(iPlayer)
- self.recalcEconomy(iPlayer)
- self.recalcCity(iPlayer)
-
- def continentsNormalization(self, iGameTurn): # Sedna17
- pass
-
- def onCityBuilt(self, iPlayer, x, y):
- iProv = PROVINCES_MAP[y][x]
- pPlayer = gc.getPlayer(iPlayer)
- # Absinthe: +1 for core, -1 for contested, -2 for foreign provinces
- iProvinceType = pPlayer.getProvinceType(iProv)
- if iProvinceType == ProvinceType.CORE:
- pPlayer.changeStabilityBase(StabilityCategory.EXPANSION, 1)
- elif not gc.hasUP(
- iPlayer, UniquePower.STABILITY_BONUS_FOUNDING
- ): # no instability with the Settler UP
- if iProvinceType == ProvinceType.CONTESTED:
- pPlayer.changeStabilityBase(StabilityCategory.EXPANSION, -1)
- elif iProvinceType == ProvinceType.NONE:
- pPlayer.changeStabilityBase(StabilityCategory.EXPANSION, -2)
- if pPlayer.getNumCities() < 5: # early boost to small civs
- pPlayer.changeStabilityBase(StabilityCategory.EXPANSION, 1)
- self.recalcEpansion(iPlayer)
- self.recalcCivicCombos(iPlayer)
-
- def onCityAcquired(self, iOwner, playerType, city, bConquest, bTrade):
- pOwner = gc.getPlayer(iOwner)
- pConq = gc.getPlayer(playerType)
-
- if city.hasBuilding(Wonder.ESCORIAL):
- pConq.setPicklefreeParameter(SpecialParameter.HAS_ESCORIAL, 1)
- pOwner.setPicklefreeParameter(SpecialParameter.HAS_ESCORIAL, 0)
- if city.hasBuilding(Wonder.STEPHANSDOM):
- pConq.setPicklefreeParameter(SpecialParameter.HAS_STEPHANSDOM, 1)
- pOwner.setPicklefreeParameter(SpecialParameter.HAS_STEPHANSDOM, 0)
- if city.hasBuilding(Wonder.SHRINE_OF_UPPSALA):
- pConq.setPicklefreeParameter(SpecialParameter.HAS_UPPSALA_SHRINE, 1)
- pOwner.setPicklefreeParameter(SpecialParameter.HAS_UPPSALA_SHRINE, 0)
- if city.hasBuilding(Wonder.KOUTOUBIA_MOSQUE):
- pConq.setPicklefreeParameter(SpecialParameter.HAS_KOUTOUBIA_MOSQUE, 1)
- pOwner.setPicklefreeParameter(SpecialParameter.HAS_KOUTOUBIA_MOSQUE, 0)
- if city.hasBuilding(Wonder.MAGNA_CARTA):
- pConq.setPicklefreeParameter(SpecialParameter.HAS_MAGNACARTA, 1)
- pOwner.setPicklefreeParameter(SpecialParameter.HAS_MAGNACARTA, 0)
-
- self.recalcCivicCombos(playerType)
- self.recalcCivicCombos(iOwner)
- iProv = city.getProvince()
- iProvOwnerType = pOwner.getProvinceType(iProv)
- iProvConqType = pConq.getProvinceType(iProv)
-
- if iProvOwnerType >= ProvinceType.HISTORICAL:
- if iOwner == Civ.SCOTLAND: # Scotland UP part 2
- pOwner.changeStabilityBase(StabilityCategory.EXPANSION, -2)
- pOwner.setStabilitySwing(pOwner.getStabilitySwing() - 2)
- else:
- pOwner.changeStabilityBase(StabilityCategory.EXPANSION, -3)
- pOwner.setStabilitySwing(pOwner.getStabilitySwing() - 4)
- elif iProvOwnerType < ProvinceType.HISTORICAL:
- if iOwner == Civ.SCOTLAND: # Scotland UP part 2
- pOwner.setStabilitySwing(pOwner.getStabilitySwing() - 1)
- else:
- pOwner.setStabilitySwing(pOwner.getStabilitySwing() - 2)
-
- if iProvConqType >= ProvinceType.HISTORICAL:
- pConq.changeStabilityBase(StabilityCategory.EXPANSION, 1)
- pConq.setStabilitySwing(pConq.getStabilitySwing() + 3)
-
- if pConq.getCivics(5) == Civic.OCCUPATION:
- pConq.changeStabilityBase(StabilityCategory.EXPANSION, 1)
-
- if (
- iOwner < civilizations().majors().len()
- and (city.getX(), city.getY()) == civilization(iOwner).location.capital
- ):
- if iOwner == Civ.SCOTLAND: # Scotland UP part 2
- pOwner.changeStabilityBase(StabilityCategory.EXPANSION, -5)
- pOwner.setStabilitySwing(pOwner.getStabilitySwing() - 5)
- elif gc.hasUP(
- iOwner, UniquePower.NO_COLLAPSE_IN_CORE_AND_NORMAL_AREAS
- ): # If Byzantium loses Constantinople, they should lose all non-core cities
- pOwner.changeStabilityBase(StabilityCategory.EXPANSION, -20)
- pOwner.setStabilitySwing(pOwner.getStabilitySwing() - 20)
- else:
- pOwner.changeStabilityBase(StabilityCategory.EXPANSION, -10)
- pOwner.setStabilitySwing(pOwner.getStabilitySwing() - 10)
- self.recalcEpansion(iOwner)
- self.recalcEpansion(playerType)
-
- def onCityRazed(self, iOwner, iPlayer, city):
- # Sedna17: Not sure what difference between iOwner and iPlayer is here
- # 3Miro: iOwner owns the city (victim) and I think iPlayer is the one razing the city
- # On second thought, if iOwner (the previous owner) doesn't have enough culture, then iOwner == playerType
- # AbsintheRed: iPlayer is the one razing city, iOwner is the previous owner of the city (right before iPlayer)
- pPlayer = gc.getPlayer(iPlayer)
- pOwner = gc.getPlayer(iOwner)
- if city.hasBuilding(Wonder.ESCORIAL):
- pPlayer.setPicklefreeParameter(SpecialParameter.HAS_ESCORIAL, 0)
- pOwner.setPicklefreeParameter(SpecialParameter.HAS_ESCORIAL, 0)
- if city.hasBuilding(Wonder.STEPHANSDOM):
- pPlayer.setPicklefreeParameter(SpecialParameter.HAS_STEPHANSDOM, 0)
- pOwner.setPicklefreeParameter(SpecialParameter.HAS_STEPHANSDOM, 0)
- if city.hasBuilding(Wonder.SHRINE_OF_UPPSALA):
- pPlayer.setPicklefreeParameter(SpecialParameter.HAS_UPPSALA_SHRINE, 0)
- pOwner.setPicklefreeParameter(SpecialParameter.HAS_UPPSALA_SHRINE, 0)
- if city.hasBuilding(Wonder.KOUTOUBIA_MOSQUE):
- pPlayer.setPicklefreeParameter(SpecialParameter.HAS_KOUTOUBIA_MOSQUE, 0)
- pOwner.setPicklefreeParameter(SpecialParameter.HAS_KOUTOUBIA_MOSQUE, 0)
- if city.hasBuilding(Wonder.MAGNA_CARTA):
- pPlayer.setPicklefreeParameter(SpecialParameter.HAS_MAGNACARTA, 0)
- pOwner.setPicklefreeParameter(SpecialParameter.HAS_MAGNACARTA, 0)
- self.recalcCivicCombos(iPlayer)
- self.recalcCivicCombos(iOwner)
-
- # Absinthe: city razing penalty - permanent, based on city population
- # note that the city is already reduced by 1 on city conquest, so city.getPopulation() is one less than the original size
- # so currently: 0 with 1-2 population, -1 with 3-5 population, -2 with 6-9 population, -3 with 10+ population
- iRazeStab = 0
- if city.getPopulation() >= 9:
- iRazeStab = 3
- elif city.getPopulation() >= 5:
- iRazeStab = 2
- elif city.getPopulation() >= 2:
- iRazeStab = 1
- # Absinthe: Norwegian UP - one less stability penalty
- if iPlayer == Civ.NORWAY:
- iRazeStab -= 1
- if iRazeStab > 0:
- pPlayer.changeStabilityBase(StabilityCategory.EXPANSION, -iRazeStab)
- # temporary, 3 for everyone but Norway
- if iPlayer != Civ.NORWAY:
- pPlayer.setStabilitySwing(pPlayer.getStabilitySwing() - 3)
- self.recalcEpansion(iPlayer)
-
- def onImprovementDestroyed(self, owner):
- pPlayer = gc.getPlayer(owner)
- pPlayer.setStabilitySwing(pPlayer.getStabilitySwing() - 2)
-
- def onTechAcquired(self, iTech, iPlayer):
- if iTech in [
- Technology.FEUDALISM,
- Technology.GUILDS,
- Technology.GUNPOWDER,
- Technology.PROFESSIONAL_ARMY,
- Technology.NATIONALISM,
- Technology.CIVIL_SERVICE,
- Technology.ECONOMICS,
- Technology.MACHINERY,
- Technology.ARISTOCRACY,
- ]:
- gc.getPlayer(iPlayer).changeStabilityBase(StabilityCategory.ECONOMY, -1)
- pass
-
- def onBuildingBuilt(self, iPlayer, iBuilding):
- pPlayer = gc.getPlayer(iPlayer)
- if iBuilding == getUniqueBuilding(iPlayer, Building.MANOR_HOUSE):
- pPlayer.changeStabilityBase(StabilityCategory.ECONOMY, 1)
- self.recalcEconomy(iPlayer)
- elif iBuilding == getUniqueBuilding(iPlayer, Building.CASTLE):
- pPlayer.changeStabilityBase(StabilityCategory.EXPANSION, 1)
- self.recalcEpansion(iPlayer)
- elif iBuilding == getUniqueBuilding(iPlayer, Building.NIGHT_WATCH):
- pPlayer.changeStabilityBase(StabilityCategory.CIVICS, 1)
- self.recalcCivicCombos(iPlayer)
- elif iBuilding == getUniqueBuilding(iPlayer, Building.COURTHOUSE):
- pPlayer.changeStabilityBase(StabilityCategory.CITIES, 1)
- self.recalcCity(iPlayer)
- elif iBuilding == Wonder.ESCORIAL:
- pPlayer.setPicklefreeParameter(SpecialParameter.HAS_ESCORIAL, 1)
- elif iBuilding == Wonder.STEPHANSDOM:
- pPlayer.setPicklefreeParameter(SpecialParameter.HAS_STEPHANSDOM, 1)
- elif iBuilding == Wonder.SHRINE_OF_UPPSALA:
- pPlayer.setPicklefreeParameter(SpecialParameter.HAS_UPPSALA_SHRINE, 1)
- elif iBuilding == Wonder.KOUTOUBIA_MOSQUE:
- pPlayer.setPicklefreeParameter(SpecialParameter.HAS_KOUTOUBIA_MOSQUE, 1)
- elif iBuilding == Wonder.MAGNA_CARTA:
- pPlayer.setPicklefreeParameter(SpecialParameter.HAS_MAGNACARTA, 1)
- elif iBuilding == Building.PALACE:
- pPlayer.changeStabilityBase(StabilityCategory.EXPANSION, -2)
- pPlayer.setStabilitySwing(pPlayer.getStabilitySwing() - 5)
- self.recalcEpansion(iPlayer)
- elif iBuilding == Building.RELIQUARY:
- pPlayer.changeStabilityBase(StabilityCategory.EXPANSION, 1)
- self.recalcEpansion(iPlayer)
-
- def onProjectBuilt(self, iPlayer, iProject):
- pPlayer = gc.getPlayer(iPlayer)
- iCivic5 = pPlayer.getCivics(5)
- if iProject >= len(Project):
- pPlayer.changeStabilityBase(
- StabilityCategory.EXPANSION, -2
- ) # -2 stability for each colony
- if iCivic5 == Civic.COLONIALISM:
- pPlayer.changeStabilityBase(
- StabilityCategory.EXPANSION, 1
- ) # one less stability penalty if civ is in Colonialism
- self.recalcEpansion(iPlayer)
-
- def onCombatResult(self, argsList):
- pass
-
- def onReligionFounded(self, iPlayer):
- pass
-
- def onReligionSpread(self, iReligion, iPlayer):
- pass
-
- def checkImplosion(self, iGameTurn):
- if iGameTurn > 14 and iGameTurn % 6 == 3:
- for iPlayer in civilizations().main().ids():
- pPlayer = gc.getPlayer(iPlayer)
- # Absinthe: no city secession for 15 turns after spawn, for 10 turns after respawn
- iRespawnTurn = getLastRespawnTurn(iPlayer)
- if (
- pPlayer.isAlive()
- and iGameTurn >= civilization(iPlayer).date.birth + 15
- and iGameTurn >= iRespawnTurn + 10
- ):
- iStability = pPlayer.getStability()
- # Absinthe: human player with very bad stability should have a much bigger chance for collapse
- if iStability < -14 and iPlayer == human():
- if percentage_chance(-2 * iStability, strict=True):
- # 30 chance with -15, 50% with -25, 70% with -35, 100% with -50 or less
- if not collapseImmune(iPlayer):
- self.collapseCivilWar(iPlayer, iStability)
- else: # when won't collapse, secession should always happen
- revoltCity(iPlayer, False)
- # Absinthe: if stability is less than -3, there is a chance that the secession/revolt or collapse mechanics start
- # if more than 8 cities: high chance for secession mechanics, low chance for collapse
- # elif more than 4 cities: medium chance for collapse mechanics, medium chance for secession
- # otherwise big chance for collapse mechanics
- # the actual chance for both secession/revolt and total collapse is increasing with lower stability
- elif iStability < -3:
- iRand1 = rand(10)
- iRand2 = rand(10)
- iRand3 = rand(10)
- if pPlayer.getNumCities() > 8:
- if iRand1 < 8: # 80 chance for secession start
- if iRand2 < (
- -3 - iStability
- ): # 10% at -4, increasing by 10% with each point (100% with -13 or less)
- revoltCity(iPlayer, False)
- elif (
- iRand3 < 1
- and iGameTurn >= civilization(iPlayer).date.birth + 20
- and not collapseImmune(iPlayer)
- ): # 10 chance for collapse start
- if iRand2 < (
- -1.5 - (iStability / 2)
- ): # 10% at -4, increasing by 10% with 2 points (100% with -22 or less)
- self.collapseCivilWar(iPlayer, iStability)
- elif pPlayer.getNumCities() > 4:
- if iRand1 < 4: # 40 chance for secession start
- if iRand2 < (
- -3 - iStability
- ): # 10% at -4, increasing by 10% with each point (100% with -13 or less)
- revoltCity(iPlayer, False)
- elif (
- iRand3 < 4
- and iGameTurn >= civilization(iPlayer).date.birth + 20
- and not collapseImmune(iPlayer)
- ): # 40 chance for collapse start
- if iRand2 < (
- -1.5 - (iStability / 2)
- ): # 10% at -4, increasing by 10% with 2 points (100% with -22 or less)
- self.collapseCivilWar(iPlayer, iStability)
- elif (
- iRand1 < 7
- and iGameTurn >= civilization(iPlayer).date.birth + 20
- and not collapseImmune(iPlayer)
- ): # 70 chance for collapse start
- if iRand2 < (
- -1.5 - (iStability / 2)
- ): # 10% at -4, increasing by 10% with 2 points (100% with -22 or less)
- self.collapseCivilWar(iPlayer, iStability)
-
- def collapseCivilWar(self, iPlayer, iStability):
- pPlayer = gc.getPlayer(iPlayer)
- iHuman = human()
- if iPlayer != iHuman:
- if gc.getPlayer(iHuman).canContact(iPlayer):
- message(
- iHuman,
- pPlayer.getCivilizationDescription(0)
- + " "
- + text("TXT_KEY_STABILITY_CIVILWAR_STABILITY"),
- color=MessageData.RED,
- )
- killAndFragmentCiv(iPlayer, False, False)
- elif pPlayer.getNumCities() > 1:
- message(
- iPlayer,
- text("TXT_KEY_STABILITY_CIVILWAR_STABILITY_HUMAN"),
- force=True,
- color=MessageData.RED,
- )
- killAndFragmentCiv(iPlayer, False, True)
- self.zeroStability(iPlayer)
-
- def printStability(self, iGameTurn, iPlayer):
- pPlayer = gc.getPlayer(iPlayer)
- print(" Turn: ", iGameTurn)
- print(" ---------------- New Stability For " + pPlayer.getCivilizationShortDescription())
- print(" Stability : ", pPlayer.getStability())
- print(
- " Cities : ",
- pPlayer.getStabilityBase(StabilityCategory.CITIES)
- + pPlayer.getStabilityVary(StabilityCategory.CITIES),
- )
- print(
- " Civics : ",
- pPlayer.getStabilityBase(StabilityCategory.CIVICS)
- + pPlayer.getStabilityVary(StabilityCategory.CIVICS),
- )
- print(
- " Economy : ",
- pPlayer.getStabilityBase(StabilityCategory.ECONOMY)
- + pPlayer.getStabilityVary(StabilityCategory.ECONOMY),
- )
- print(
- " Expansion : ",
- pPlayer.getStabilityBase(StabilityCategory.EXPANSION)
- + pPlayer.getStabilityVary(StabilityCategory.EXPANSION),
- )
-
- def zeroStability(self, iPlayer): # Called by Stability.CheckImplosion
- pPlayer = gc.getPlayer(iPlayer)
- pPlayer.changeStabilityBase(
- StabilityCategory.CITIES,
- -pPlayer.getStabilityBase(StabilityCategory.CITIES),
- )
- pPlayer.changeStabilityBase(
- StabilityCategory.CIVICS,
- -pPlayer.getStabilityBase(StabilityCategory.CIVICS),
- )
- pPlayer.changeStabilityBase(
- StabilityCategory.ECONOMY,
- -pPlayer.getStabilityBase(StabilityCategory.ECONOMY),
- )
- pPlayer.changeStabilityBase(
- StabilityCategory.EXPANSION,
- -pPlayer.getStabilityBase(StabilityCategory.EXPANSION),
- )
- pPlayer.setStabilityVary(StabilityCategory.CITIES, 0)
- pPlayer.setStabilityVary(StabilityCategory.CIVICS, 0)
- pPlayer.setStabilityVary(StabilityCategory.ECONOMY, 0)
- pPlayer.setStabilityVary(StabilityCategory.EXPANSION, 0)
- pPlayer.setStabilitySwing(0)
-
- def recalcCity(self, iPlayer):
- pPlayer = gc.getPlayer(iPlayer)
- iCivic4 = pPlayer.getCivics(4)
- iCivic5 = pPlayer.getCivics(5)
- iTotalHappy = (
- pPlayer.calculateTotalCityHappiness() - pPlayer.calculateTotalCityUnhappiness()
- )
- iCityStability = 0
- if pPlayer.getNumCities() == 0:
- iHappyStability = 0
- else:
- iHappyStability = (
- iTotalHappy / pPlayer.getNumCities()
- ) # +k stability for an average city happiness of at least k
- iCivHealthStability = 0
- iHealthStability = 0
- iHurryStability = 0
- iMilitaryStability = 0
- iWarWStability = 0
- iReligionStability = 0
- iCivicReligionInstability = 0
- iCultureStability = 0
-
- for pCity in cities().owner(iPlayer).entities():
- # Absinthe: if your civ is healthy, bonus stability
- # if one of your is cities is unhealthy, -1 stability
- iCivHealthStability += pCity.goodHealth()
- iCivHealthStability -= pCity.badHealth(False)
- if pCity.goodHealth() - pCity.badHealth(False) < 0:
- iHealthStability -= 1
- if pCity.angryPopulation(0) > 0:
- iHappyStability -= 2
-
- # Absinthe: This is the "We desire religious freedom!" unhappiness, from civics - currently from the Religious Law civic
- # also it is a negative counter with the current civic setup, so getReligionBadHappiness() == -1 with one non-state religion in the city
- if pCity.getReligionBadHappiness() < 0:
- if not gc.hasUP(
- iPlayer, UniquePower.NO_INSTABILITY_WITH_FOREIGN_RELIGION
- ): # Polish UP
- iCivicReligionInstability += 1
- if pCity.getHurryAngerModifier() > 0:
- iHurryStability -= 1
- if pCity.getNoMilitaryPercentAnger() > 0:
- iMilitaryStability -= 1
- # Absinthe: getWarWearinessPercentAnger is not a local variable for your cities, but a global one for your entire civ
- # it would results in 1 instability for each city if there is an ongoing war, thus I added some modifications below
- if pCity.getWarWearinessPercentAnger() > 10:
- iWarWStability -= 1
-
- bJewInstability = False
- if (
- iCivic4 != Civic.FREE_RELIGION
- ): # Religious Tolerance negates stability penalties from non-state religions
- if not gc.hasUP(
- iPlayer, UniquePower.NO_INSTABILITY_WITH_FOREIGN_RELIGION
- ): # Polish UP
- if pCity.getNumForeignReligions() > 0:
- # only calculate if Judaism is not the State Religion
- if pPlayer.getStateReligion() != Religion.JUDAISM:
- bJewInstability = True
- if iCivic4 == Civic.PAGANISM: # Pagans are a bit more tolerant
- iReligionStability -= 1
- elif (
- iPlayer == Civ.OTTOMAN
- ): # Janissary UP - not necessarily a historical aspect of it, but important for gameplay
- # elif ( gc.hasUP( iPlayer, UniquePower.FREE_UNITS_WITH_FOREIGN_RELIGIONS )):
- iReligionStability -= 1
- else:
- iReligionStability -= 2
- if (
- pCity.getNumForeignReligions() > 1
- ): # additional -1 stability for every further foreign religion
- iReligionStability -= min(pCity.getNumForeignReligions() - 1, 3)
-
- # Absinthe: Jewish Quarter reduces religion instability if Judaism is present in the city
- if (
- bJewInstability
- and pCity.hasBuilding(Building.JEWISH_QUARTER)
- and pCity.isHasReligion(Religion.JUDAISM)
- ): # only if there are some religious penalties present in the city
- iReligionStability += 1
-
- # Absinthe: -1 stability if own culture is less than 40% of total culture in a city, -2 stability if less than 20%
- iTotalCulture = pCity.countTotalCultureTimes100()
- if (
- (iTotalCulture > 0)
- and ((pCity.getCulture(iPlayer) * 10000) / iTotalCulture < 40)
- and not gc.hasUP(iPlayer, UniquePower.NO_UNHAPPINESS_WITH_FOREIGN_CULTURE)
- ):
- # Absinthe: 1 less instability with the Vassalage Civic, so only -1 with less than 20%, 0 otherwise
- if iCivic5 != Civic.SUBJUGATION:
- iCultureStability -= 1
- if (pCity.getCulture(iPlayer) * 10000) / iTotalCulture < 20:
- iCultureStability -= 1
-
- # Absinthe: if your civ is healthy, bonus stability
- if iCivHealthStability > 0:
- iCivHealthStability = (
- iCivHealthStability / pPlayer.getNumCities()
- ) # +k stability for an average city health of at least k
- iHealthStability += iCivHealthStability
-
- # Absinthe: reduced value for getReligionBadHappiness, shouldn't add -1 for each city if almost all of them has multiple religions
- # switching in and out of the civic won't result in that much fluctuation
- iCivicReligionInstability = min(pPlayer.getNumCities() / 2, iCivicReligionInstability)
-
- # Absinthe: persecution counter - cooldown is handled in Religions.checkTurn
- # 1-3 means 1 instability, 4-6 means 2 instability, 7-9 means 3 instability, etc...
- iProsecutionCount = pPlayer.getProsecutionCount()
- if iProsecutionCount > 0:
- iReligionStability -= (iProsecutionCount + 2) / 3
-
- # Humans are far more competent then the AI, so the AI won't get all the penalties
- if pPlayer.isHuman():
- iCityStability += (
- iHappyStability
- + iHealthStability
- + iReligionStability
- - iCivicReligionInstability
- + iHurryStability
- + iCultureStability
- + iMilitaryStability
- )
- iCityStability += max(
- iWarWStability / 3 - 1, -10
- ) # max 10 instability from war weariness
- iCityStability = min(
- iCityStability, 8
- ) # max 8 extra stability from cities - don't want to add too many bonuses for runaway civs
- else:
- iCityStability += max(iHappyStability, -5) + max(
- iHealthStability, -5
- ) # AI keeps very unhappy cities
- iCityStability += max(
- iReligionStability - iCivicReligionInstability + iHurryStability, -7
- ) + max(iCultureStability, -5)
- iCityStability += max(
- iMilitaryStability + iWarWStability / 3, -3
- ) # AI is also bad at handling war weariness
- iCityStability = min(max(iCityStability, -10), 8)
- iCityStability += pPlayer.getFaithBenefit(FaithPointBonusCategory.BOOST_STABILITY)
- if pPlayer.getGoldenAgeTurns() > 0:
- iCityStability += 8
- # Absinthe: Westminster Abbey faith-stability effect
- if pPlayer.countNumBuildings(Wonder.WESTMINSTER) > 0:
- # would be better, if the stability bonus was also only applied for Divine Monarchy?
- # if pPlayer.getCivics(0) == Civic.DIVINE_MONARCHY:
- iFaith = pPlayer.getFaith()
- iCityStability += iFaith / 20
-
- pPlayer.setStabilityVary(StabilityCategory.CITIES, iCityStability)
-
- def recalcCivicCombos(self, iPlayer):
- # Note: this is more or less the only place where Civics are referenced, yet referring them by number makes this hard to read
- pPlayer = gc.getPlayer(iPlayer)
- iCivicGovernment = pPlayer.getCivics(0)
- iCivicLegal = pPlayer.getCivics(1)
- iCivicLabor = pPlayer.getCivics(2)
- iCivicEconomy = pPlayer.getCivics(3)
- iCivicReligion = pPlayer.getCivics(4)
- iCivicExpansion = pPlayer.getCivics(5)
-
- lCivics = [
- iCivicGovernment,
- iCivicLegal,
- iCivicLabor,
- iCivicEconomy,
- iCivicReligion,
- iCivicExpansion,
- ]
- lCombinations = [
- (iCivic1, iCivic2) for iCivic1 in lCivics for iCivic2 in lCivics if iCivic1 < iCivic2
- ]
-
- iCivicCombo = 0
- # Calculate the combinations
- for lCombination in lCombinations:
- iComboValue = self.getCivicCombinationStability(lCombination[0], lCombination[1])
- if (
- iComboValue < 0
- and pPlayer.getPicklefreeParameter(SpecialParameter.HAS_MAGNACARTA) == 1
- ):
- iComboValue = 0
- iCivicCombo += iComboValue
-
- if pPlayer.getPicklefreeParameter(SpecialParameter.HAS_STEPHANSDOM) == 1:
- if iCivicGovernment in [
- Civic.FEUDAL_MONARCHY,
- Civic.DIVINE_MONARCHY,
- Civic.LIMITE_DMONARCHY,
- ]:
- iCivicCombo += 2
-
- if pPlayer.getPicklefreeParameter(SpecialParameter.HAS_UPPSALA_SHRINE) == 1:
- if iCivicReligion == Civic.PAGANISM:
- iCivicCombo += 3
-
- if pPlayer.getPicklefreeParameter(SpecialParameter.HAS_KOUTOUBIA_MOSQUE) == 1:
- if iCivicLegal == Civic.RELIGIOUS_LAW:
- iCivicCombo += 4
-
- if iCivicLegal == Civic.BUREAUCRACY: # Bureaucracy city cap
- if (
- iPlayer == Civ.NOVGOROD and pPlayer.getNumCities() > 6
- ): # the penalties are halved for Novgorod
- iBureaucracyCap = (6 - pPlayer.getNumCities()) / 2
- else:
- iBureaucracyCap = 6 - pPlayer.getNumCities()
- if not pPlayer.isHuman(): # max -5 penalty for the AI
- iBureaucracyCap = max(-5, iBureaucracyCap)
- iCivicCombo += iBureaucracyCap
-
- if iCivicGovernment == Civic.MERCHANT_REPUBLIC: # Merchant Republic city cap
- if (
- iPlayer == Civ.VENECIA and pPlayer.getNumCities() > 5
- ): # the penalties are halved for Venice
- iMerchantRepublicCap = (5 - pPlayer.getNumCities()) / 2
- else:
- iMerchantRepublicCap = 5 - pPlayer.getNumCities()
- if not pPlayer.isHuman(): # max -5 penalty for the AI
- iMerchantRepublicCap = max(-5, iMerchantRepublicCap)
- iCivicCombo += iMerchantRepublicCap
-
- pPlayer.setStabilityVary(StabilityCategory.CIVICS, iCivicCombo)
-
- def getCivicCombinationStability(self, iCivic0, iCivic1):
- lCivics = set([iCivic0, iCivic1])
-
- if Civic.FEUDAL_MONARCHY in lCivics:
- if Civic.FEUDAL_LAW in lCivics:
- return 3
-
- if (
- Civic.DIVINE_MONARCHY in lCivics
- ): # Divine Monarchy should have an appropriate religious civic
- if Civic.RELIGIOUS_LAW in lCivics:
- return 2
- if Civic.PAGANISM in lCivics:
- return -4
- if Civic.STATE_RELIGION in lCivics:
- return 2
- if Civic.THEOCRACY in lCivics:
- return 3
- if Civic.ORGANIZED_RELIGION in lCivics:
- return 4
- if Civic.FREE_RELIGION in lCivics:
- return -3
-
- if (
- Civic.LIMITE_DMONARCHY in lCivics
- ): # Constitutional Monarchy and Republic both like enlightened civics
- if Civic.COMMON_LAW in lCivics:
- return 3
- if Civic.FREE_PEASANTRY in lCivics:
- return 2
- if Civic.FREE_LABOR in lCivics:
- return 2
-
- if (
- Civic.MERCHANT_REPUBLIC in lCivics
- ): # Constitutional Monarchy and Republic both like enlightened civics
- if Civic.FEUDAL_LAW in lCivics:
- return -3
- if Civic.COMMON_LAW in lCivics:
- return 3
- if Civic.FREE_PEASANTRY in lCivics:
- return 2
- if Civic.FREE_LABOR in lCivics:
- return 2
- if Civic.TRADE_ECONOMY in lCivics:
- return 4
- if Civic.MERCANTILISM in lCivics:
- return -4
- if Civic.IMPERIALISM in lCivics:
- return -2
-
- if Civic.FEUDAL_LAW in lCivics:
- if Civic.SERFDOM in lCivics:
- return 3
- if Civic.FREE_PEASANTRY in lCivics:
- return -4
- if Civic.MANORIALISM in lCivics:
- return 2
- if Civic.VASSALAGE in lCivics:
- return 2
-
- if Civic.RELIGIOUS_LAW in lCivics:
- if Civic.PAGANISM in lCivics:
- return -5
- if Civic.THEOCRACY in lCivics:
- return 5
- if Civic.FREE_RELIGION in lCivics:
- return -3
-
- if Civic.COMMON_LAW in lCivics:
- if Civic.SERFDOM in lCivics:
- return -3
- if Civic.FREE_LABOR in lCivics:
- return 3
- if Civic.THEOCRACY in lCivics:
- return -4
-
- if Civic.SERFDOM in lCivics:
- if Civic.MANORIALISM in lCivics:
- return 2
- if Civic.TRADE_ECONOMY in lCivics:
- return -3
-
- if Civic.APPRENTICESHIP in lCivics:
- if Civic.GUILDS in lCivics:
- return 3
-
- return 0
-
- def recalcEconomy(self, iPlayer):
- pPlayer = gc.getPlayer(iPlayer)
- iPopNum = pPlayer.getTotalPopulation()
- iImports = pPlayer.calculateTotalImports(YieldTypes.YIELD_COMMERCE)
- iExports = pPlayer.calculateTotalExports(YieldTypes.YIELD_COMMERCE)
- # Absinthe: removed - why was Cordoba penalized in the first place?
- # if iPlayer == Civ.CORDOBA:
- # iImports /= 2
- # iExports /= 2
-
- iFinances = pPlayer.getFinancialPower()
- iInflation = pPlayer.calculateInflatedCosts()
- iProduction = pPlayer.calculateTotalYield(YieldTypes.YIELD_PRODUCTION)
- # Absinthe: removed - Venice no longer has that weak production
- # if iPlayer == Civ.VENECIA:
- # iProduction += iPopNum # offset their weak production
- iAgriculture = pPlayer.calculateTotalYield(YieldTypes.YIELD_FOOD)
-
- iLargeCities = 0
- for pCity in cities().owner(iPlayer).entities():
- # Absinthe: production penalty removed - was a mistake to add a city-based modifier to the financial stability which is based on average per population
- # if pCity.isProductionUnit():
- # iUnit = pCity.getProductionUnit()
- # if iUnit < Unit.WORKER or iUnit > Unit.ISLAMIC_MISSIONARY:
- # iProductionPenalty -= 1
- # elif pCity.isProductionBuilding():
- # iBuilding = pCity.getProductionBuilding()
- # if isWonder(iBuilding):
- # iProductionPenalty -= 2
- # else:
- # iProductionPenalty -= 2
- iCityPop = pCity.getPopulation()
- if (
- iCityPop > 10
- ): # large cities should have production bonus buildings, drop by 10 percent
- iProduction -= pCity.getYieldRate(YieldTypes.YIELD_PRODUCTION) / 10
- iLargeCities += 1
-
- iNumCities = pPlayer.getNumCities()
- if iNumCities > 0:
- iIndustrialStability = min(
- max(2 * (2 * iAgriculture + iProduction) / iPopNum - 14, -3), 3
- ) # this is 0 if the average yield per population is a little more than 2 food and 2 production (with bonuses)
- if (
- pPlayer.getPicklefreeParameter(SpecialParameter.HAS_ESCORIAL) == 1
- ): # El Escorial no economic instability effect
- iIndustrialStability = max(iIndustrialStability, 0)
- iFinances = (
- iFinances * (100 - 20 * iLargeCities / iNumCities) / 100
- ) # between 80% and 100%, based on the number of large cities
- iFinancialStability = min(
- max((iFinances - iInflation + iImports + iExports) / iPopNum - 6, -4), 4
- ) # this is 0 if the average financial power per population is around 6
- # iFinancialPowerPerCity = ( iFinances - iInflation + iImports + iExports ) / iNumCities
- if (
- pPlayer.getPicklefreeParameter(SpecialParameter.HAS_ESCORIAL) == 1
- ): # El Escorial no economic instability effect
- iFinancialStability = max(iFinancialStability, 0)
- pPlayer.setStabilityVary(
- StabilityCategory.ECONOMY, iFinancialStability + iIndustrialStability
- )
- else:
- pPlayer.setStabilityVary(StabilityCategory.ECONOMY, 0)
-
- def recalcEpansion(self, iPlayer):
- pPlayer = gc.getPlayer(iPlayer)
- iExpStability = 0
- iCivic5 = pPlayer.getCivics(5)
- bIsUPLandStability = gc.hasUP(iPlayer, UniquePower.LESS_INSTABILITY_WITH_FOREIGN_LAND)
- iCivicBonus = 0
- iUPBonus = 0
- for pCity in cities().owner(iPlayer).entities():
- iProvType = pPlayer.getProvinceType(pCity.getProvince())
- iProvNum = pCity.getProvince()
- CityName = pCity.getNameKey()
- assert 0 <= iProvType < len(tStabilityPenalty), (
- "Bad ProvinceType value for CityName (%s)" % CityName
- )
-
- iExpStability += tStabilityPenalty[iProvType]
- if iProvType <= ProvinceType.CONTESTED:
- if iCivic5 == Civic.IMPERIALISM: # Imperialism
- iCivicBonus += 1
- if bIsUPLandStability: # French UP
- iUPBonus += 1
- iExpStability += iCivicBonus # Imperialism
- iExpStability += iUPBonus # French UP
- if pPlayer.getCivics(5) != Civic.OCCUPATION:
- iExpStability -= 3 * pPlayer.getForeignCitiesInMyProvinceType(
- ProvinceType.CORE
- ) # -3 stability for each foreign/enemy city in your core provinces, without the Militarism civic
- iExpStability -= 1 * pPlayer.getForeignCitiesInMyProvinceType(
- ProvinceType.HISTORICAL
- ) # -1 stability for each foreign/enemy city in your natural provinces, without the Militarism civic
- if pPlayer.getMaster() > -1:
- iExpStability += 8
- if iCivic5 == Civic.VASSALAGE:
- iExpStability += 3 * pPlayer.countVassals()
- else:
- iExpStability += pPlayer.countVassals()
- iNumCities = pPlayer.getNumCities()
- if iPlayer in [Civ.OTTOMAN, Civ.MOSCOW]: # five free cities for those two
- iNumCities = max(0, iNumCities - 5)
- iExpStability -= iNumCities * iNumCities / 40
- pPlayer.setStabilityVary(StabilityCategory.EXPANSION, iExpStability)
diff --git a/Assets/Python/components/UniquePowers.py b/Assets/Python/components/UniquePowers.py
deleted file mode 100644
index cf6e104d9..000000000
--- a/Assets/Python/components/UniquePowers.py
+++ /dev/null
@@ -1,242 +0,0 @@
-# Rhye's and Fall of Civilization: Europe - Unique Powers (only a couple of them is here, most are handled in the .dll)
-
-from CvPythonExtensions import *
-from Core import message, human, make_unit, cities, plots, text
-from CoreTypes import Building, SpecialParameter, Religion, Unit
-from PyUtils import choice
-
-from RFCUtils import getMaster, getUniqueUnit
-import Religions
-
-from Consts import MessageData
-
-gc = CyGlobalContext()
-religion = Religions.Religions()
-
-
-class UniquePowers:
- def checkTurn(self, iGameTurn):
- pass
-
- # Absinthe: Arabian UP
- def faithUP(self, iPlayer, city):
- pFaithful = gc.getPlayer(iPlayer)
- iStateReligion = pFaithful.getStateReligion()
- iTemple = 0
- # Absinthe: shouldn't work on minor religions, to avoid exploit with spreading Judaism this way
- if 0 <= iStateReligion <= 3:
- if not city.isHasReligion(iStateReligion):
- city.setHasReligion(iStateReligion, True, True, False)
- pFaithful.changeFaith(1)
-
- if iStateReligion == 0:
- iTemple = Building.PROTESTANT_TEMPLE
- elif iStateReligion == 1:
- iTemple = Building.ISLAMIC_TEMPLE
- elif iStateReligion == 2:
- iTemple = Building.CATHOLIC_TEMPLE
- elif iStateReligion == 3:
- iTemple = Building.ORTHODOX_TEMPLE
- if not city.hasBuilding(iTemple):
- city.setHasRealBuilding(iTemple, True)
- pFaithful.changeFaith(1)
-
- # Absinthe: Ottoman UP
- def janissaryDraftUP(self, iPlayer):
- pPlayer = gc.getPlayer(iPlayer)
- iStateReligion = pPlayer.getStateReligion()
-
- iNewPoints = 0
- for city in cities().owner(iPlayer).entities():
- for iReligion in range(len(Religion)):
- if iReligion != iStateReligion and city.isHasReligion(iReligion):
- iNewPoints += city.getPopulation()
- break
-
- iOldPoints = pPlayer.getPicklefreeParameter(SpecialParameter.JANISSARY_POINTS)
-
- iNextJanissary = 200
- if pPlayer.isHuman():
- iNextJanissary = 300
-
- iTotalPoints = iOldPoints + iNewPoints
- while iTotalPoints >= iNextJanissary:
- pCity = cities().owner(iPlayer).random_entry()
- if pCity is not None:
- make_unit(iPlayer, Unit.JANISSARY, pCity)
- # interface message for the human player
- if iPlayer == human():
- text_string = text("TXT_KEY_UNIT_NEW_JANISSARY") + " " + pCity.getName() + "!"
- message(
- iPlayer,
- text_string,
- sound="AS2D_UNIT_BUILD_UNIQUE_UNIT",
- button=gc.getUnitInfo(Unit.JANISSARY).getButton(),
- color=MessageData.GREEN,
- location=pCity,
- )
- iTotalPoints -= iNextJanissary
-
- pPlayer.setPicklefreeParameter(SpecialParameter.JANISSARY_POINTS, iTotalPoints)
-
- def janissaryNewCityUP(self, iPlayer, city, bConquest):
- pPlayer = gc.getPlayer(iPlayer)
- iStateReligion = pPlayer.getStateReligion()
- for iReligion in range(len(Religion)):
- if iReligion != iStateReligion and city.isHasReligion(iReligion):
- iCityPopulation = city.getPopulation()
- # more janissary points on conquest, less on flip and trade
- if bConquest:
- iJanissaryPoint = iCityPopulation * 9
- else:
- iJanissaryPoint = iCityPopulation * 4
- iOldPoints = pPlayer.getPicklefreeParameter(SpecialParameter.JANISSARY_POINTS)
- pPlayer.setPicklefreeParameter(
- SpecialParameter.JANISSARY_POINTS, iOldPoints + iJanissaryPoint
- )
- break
-
- # removed free janissary, probably too powerful to add a new janissary unit right on conquest
- iIsHasForeignReligion = 0
- if iIsHasForeignReligion:
- make_unit(iPlayer, Unit.JANISSARY, city)
- if iPlayer == human():
- text_string = text("TXT_KEY_UNIT_NEW_JANISSARY") + " " + city.getName() + "!"
- message(
- iPlayer,
- text_string,
- sound="AS2D_UNIT_BUILD_UNIQUE_UNIT",
- button=gc.getUnitInfo(Unit.JANISSARY).getButton(),
- color=MessageData.GREEN,
- location=city,
- )
-
- # Absinthe: Danish UP
- def soundUP(self, iPlayer):
- lSoundCoords = [(60, 57), (60, 58)]
-
- # Check if we control the Sound
- bControlsSound = False
- for tCoord in lSoundCoords:
- pPlot = gc.getMap().plot(tCoord[0], tCoord[1])
- if pPlot.calculateCulturalOwner() == iPlayer:
- bControlsSound = True
- break
- if not bControlsSound:
- return
-
- iCities = self.getNumForeignCitiesOnBaltic(iPlayer)
-
- iGold = iCities * 2
- gc.getPlayer(iPlayer).changeGold(iGold)
- message(iPlayer, text("TXT_KEY_UP_SOUND_TOLL", iGold), color=MessageData.GREEN)
-
- def getNumForeignCitiesOnBaltic(self, iPlayer, bVassal=False):
- lBalticRects = [
- ((56, 52), (70, 57)),
- ((62, 58), (74, 62)),
- ((64, 63), (79, 66)),
- ((64, 67), (71, 72)),
- ]
-
- # Count foreign coastal cities
- iCities = 0
- for start, end in lBalticRects:
- for city in (
- plots().rectangle(start, end).cities().coastal(5).not_owner(iPlayer).entities()
- ):
- if not bVassal or city.getOwner() != getMaster(city.getOwner()) != iPlayer:
- iCities += 1
- return iCities
-
- # Absinthe: Aragonese UP
- def confederationUP(self, iPlayer):
- pPlayer = gc.getPlayer(iPlayer)
- capital = pPlayer.getCapitalCity()
- iCapitalX = capital.getX()
- iCapitalY = capital.getY()
-
- # Collect all provinces
- cityProvinces = []
- for city in cities().owner(iPlayer).entities():
- pProvince = city.getProvince()
- cityProvinces.append(pProvince)
- # Calculate unique provinces
- uniqueProvinces = set(cityProvinces)
- iProvinces = len(uniqueProvinces)
-
- # Note that Aragon do not use any of its UHV counters, so we can safely use them here
- # Do not recalculate if we have the same number of provinces as in the last check, and the capital has not changed
- if (
- iProvinces == pPlayer.getUHVCounter(1)
- and pPlayer.getUHVCounter(2) == 100 * iCapitalX + iCapitalY
- ):
- return
-
- # Store the province number for the next check
- pPlayer.setUHVCounter(1, iProvinces)
-
- # On capital change, reset yield for the previous capital's tile, also reset the commerce counter
- if pPlayer.getUHVCounter(2) != 100 * iCapitalX + iCapitalY:
- iOldCapitalX = pPlayer.getUHVCounter(2) / 100
- iOldCapitalY = pPlayer.getUHVCounter(2) % 100
- iProvinceCommerceLastBonus = pPlayer.getUHVCounter(0)
- gc.getGame().setPlotExtraYield(
- iOldCapitalX, iOldCapitalY, 2, -iProvinceCommerceLastBonus
- )
- # If there was a capital change, the discount should be 0 for the new capital's tile
- pPlayer.setUHVCounter(0, 0)
- # New capital's coordinates are stored for the next check
- pPlayer.setUHVCounter(2, 100 * iCapitalX + iCapitalY)
-
- # Update tile yield for the capital's plot
- iProvinceCommerceLastBonus = pPlayer.getUHVCounter(0)
- gc.getGame().setPlotExtraYield(iCapitalX, iCapitalY, 2, -iProvinceCommerceLastBonus)
- iProvinceCommerceNextBonus = (
- iProvinces * 2
- ) # <- This number is the amount of extra commerce per province
- gc.getGame().setPlotExtraYield(iCapitalX, iCapitalY, 2, iProvinceCommerceNextBonus)
- # Tile yield is stored for the next check
- pPlayer.setUHVCounter(0, iProvinceCommerceNextBonus)
-
- # Absinthe: Scottish UP
- def defianceUP(self, iPlayer):
- pPlayer = gc.getPlayer(iPlayer)
- # One ranged/gun class
- RangedClass = getUniqueUnit(iPlayer, Unit.ARCHER)
- lRangedList = [
- Unit.LINE_INFANTRY,
- Unit.MUSKETMAN,
- Unit.LONGBOWMAN,
- Unit.ARBALEST,
- Unit.CROSSBOWMAN,
- Unit.ARCHER,
- ]
- for iUnit in lRangedList:
- if pPlayer.canTrain(getUniqueUnit(iPlayer, iUnit), False, False):
- RangedClass = getUniqueUnit(iPlayer, iUnit)
- break
-
- # One polearm class
- PolearmClass = getUniqueUnit(iPlayer, Unit.SPEARMAN)
- lPolearmList = [Unit.LINE_INFANTRY, Unit.PIKEMAN, Unit.GUISARME]
- for iUnit in lPolearmList:
- if pPlayer.canTrain(getUniqueUnit(iPlayer, iUnit), False, False):
- PolearmClass = getUniqueUnit(iPlayer, iUnit)
- break
-
- for city in cities().owner(iPlayer).entities():
- # only in cities with at least 20% Scottish culture
- iTotalCulture = city.countTotalCultureTimes100()
- if iTotalCulture == 0 or (city.getCulture(iPlayer) * 10000) / iTotalCulture > 20:
- make_unit(iPlayer, choice([RangedClass, PolearmClass]), city)
- # interface message for the human player
- if iPlayer == human():
- text_string = text("TXT_KEY_UNIT_NEW_DEFENDER") + " " + city.getName() + "!"
- message(
- iPlayer,
- text_string,
- sound="AS2D_UNIT_BUILD_UNIQUE_UNIT",
- color=MessageData.GREEN,
- location=city,
- )
diff --git a/Assets/Python/components/Victory.py b/Assets/Python/components/Victory.py
deleted file mode 100644
index 030ea5400..000000000
--- a/Assets/Python/components/Victory.py
+++ /dev/null
@@ -1,2094 +0,0 @@
-from CvPythonExtensions import *
-from Core import (
- civilization,
- companies,
- civilizations,
- message,
- human,
- player,
- show,
- team,
- text,
- turn,
- year,
- plots,
- cities,
-)
-from CoreTypes import (
- Building,
- City,
- Civ,
- Civic,
- Colony,
- Company,
- Project,
- ProvinceStatus,
- Region,
- Specialist,
- StabilityCategory,
- Religion,
- Improvement,
- Technology,
- Unit,
- Bonus,
- Wonder,
- Province,
-)
-from LocationsData import CITIES, CIV_CAPITAL_LOCATIONS, REGIONS
-import PyHelpers
-from PyUtils import rand
-from RFCUtils import calculateDistance, countAchievedGoals, getNumberCargoShips, getMostAdvancedCiv
-import UniquePowers
-from StoredData import data
-import random
-
-from Consts import MessageData
-
-up = UniquePowers.UniquePowers()
-gc = CyGlobalContext()
-
-
-tByzantiumControl = [
- Province.CALABRIA,
- Province.APULIA,
- Province.DALMATIA,
- Province.VERONA,
- Province.LOMBARDY,
- Province.LIGURIA,
- Province.TUSCANY,
- Province.LATIUM,
- Province.CORSICA,
- Province.SARDINIA,
- Province.SICILY,
- Province.TRIPOLITANIA,
- Province.IFRIQIYA,
-]
-tByzantiumControlII = [
- Province.COLONEA,
- Province.ANTIOCHIA,
- Province.CHARSIANON,
- Province.CILICIA,
- Province.ARMENIAKON,
- Province.ANATOLIKON,
- Province.PAPHLAGONIA,
- Province.THRAKESION,
- Province.OPSIKION,
- Province.CONSTANTINOPLE,
- Province.THRACE,
- Province.THESSALONIKI,
- Province.MOESIA,
- Province.MACEDONIA,
- Province.SERBIA,
- Province.ARBERIA,
- Province.EPIRUS,
- Province.THESSALY,
- Province.MOREA,
-]
-tFrankControl = [
- Province.SWABIA,
- Province.SAXONY,
- Province.LORRAINE,
- Province.ILE_DE_FRANCE,
- Province.NORMANDY,
- Province.PICARDY,
- Province.AQUITAINE,
- Province.PROVENCE,
- Province.BURGUNDY,
- Province.ORLEANS,
- Province.CHAMPAGNE,
- Province.CATALONIA,
- Province.LOMBARDY,
- Province.TUSCANY,
-]
-tArabiaControlI = [
- Province.ARABIA,
- Province.JERUSALEM,
- Province.SYRIA,
- Province.LEBANON,
- Province.ANTIOCHIA,
- Province.EGYPT,
- Province.CYRENAICA,
- Province.TRIPOLITANIA,
- Province.IFRIQIYA,
- Province.SICILY,
- Province.CRETE,
- Province.CYPRUS,
-]
-tArabiaControlII = [
- Province.ARABIA,
- Province.JERUSALEM,
- Province.SYRIA,
- Province.LEBANON,
- Province.ANTIOCHIA,
- Province.EGYPT,
-]
-tBulgariaControl = [
- Province.CONSTANTINOPLE,
- Province.THESSALONIKI,
- Province.SERBIA,
- Province.THRACE,
- Province.MACEDONIA,
- Province.MOESIA,
- Province.ARBERIA,
-]
-tCordobaWonders = [
- Wonder.ALHAMBRA,
- Wonder.LA_MEZQUITA,
- Wonder.GARDENS_AL_ANDALUS,
-]
-tCordobaIslamize = [
- Province.GALICIA,
- Province.CASTILE,
- Province.LEON,
- Province.LUSITANIA,
- Province.CATALONIA,
- Province.ARAGON,
- Province.NAVARRE,
- Province.VALENCIA,
- Province.LA_MANCHA,
- Province.ANDALUSIA,
-]
-tNorwayControl = [
- Province.THE_ISLES,
- Province.IRELAND,
- Province.SCOTLAND,
- Province.NORMANDY,
- Province.SICILY,
- Province.APULIA,
- Province.CALABRIA,
- Province.ICELAND,
-]
-tNorwayOutrank = [
- Civ.SWEDEN,
- Civ.DENMARK,
- Civ.SCOTLAND,
- Civ.ENGLAND,
- Civ.GERMANY,
- Civ.FRANCE,
-]
-# tNorseControl = [ Province.SICILY, Province.ICELAND, Province.NORTHUMBRIA, Province.SCOTLAND, Province.NORMANDY, Province.IRELAND, Province.NOVGOROD ]
-tVenetianControl = [
- Province.EPIRUS,
- Province.DALMATIA,
- Province.VERONA,
- Province.ARBERIA,
-]
-tVenetianControlII = [
- Province.THESSALY,
- Province.MOREA,
- Province.CRETE,
- Province.CYPRUS,
-]
-tBurgundyControl = [
- Province.FLANDERS,
- Province.PICARDY,
- Province.PROVENCE,
- Province.BURGUNDY,
- Province.CHAMPAGNE,
- Province.LORRAINE,
-]
-tBurgundyOutrank = [Civ.FRANCE, Civ.ENGLAND, Civ.GERMANY]
-tGermanyControl = [
- Province.TUSCANY,
- Province.LIGURIA,
- Province.LOMBARDY,
- Province.LORRAINE,
- Province.SWABIA,
- Province.SAXONY,
- Province.BAVARIA,
- Province.FRANCONIA,
- Province.BRANDENBURG,
- Province.HOLSTEIN,
-]
-tGermanyControlII = [
- Province.AUSTRIA,
- Province.FLANDERS,
- Province.POMERANIA,
- Province.SILESIA,
- Province.BOHEMIA,
- Province.MORAVIA,
- Province.SWABIA,
- Province.SAXONY,
- Province.BAVARIA,
- Province.FRANCONIA,
- Province.BRANDENBURG,
- Province.HOLSTEIN,
-]
-tKievControl = [
- Province.KIEV,
- Province.PODOLIA,
- Province.PEREYASLAVL,
- Province.SLOBODA,
- Province.CHERNIGOV,
- Province.VOLHYNIA,
- Province.MINSK,
- Province.POLOTSK,
- Province.SMOLENSK,
- Province.MOSCOW,
- Province.MUROM,
- Province.ROSTOV,
- Province.NOVGOROD,
- Province.VOLOGDA,
-]
-tHungaryControl = [
- Province.AUSTRIA,
- Province.CARINTHIA,
- Province.MORAVIA,
- Province.SILESIA,
- Province.BOHEMIA,
- Province.DALMATIA,
- Province.BOSNIA,
- Province.BANAT,
- Province.WALLACHIA,
- Province.MOLDOVA,
-]
-tHungaryControlII = [
- Province.THRACE,
- Province.MOESIA,
- Province.MACEDONIA,
- Province.THESSALONIKI,
- Province.WALLACHIA,
- Province.THESSALY,
- Province.MOREA,
- Province.EPIRUS,
- Province.ARBERIA,
- Province.SERBIA,
- Province.BANAT,
- Province.BOSNIA,
- Province.DALMATIA,
- Province.SLAVONIA,
-]
-tSpainConvert = [
- Province.GALICIA,
- Province.CASTILE,
- Province.LEON,
- Province.LUSITANIA,
- Province.CATALONIA,
- Province.ARAGON,
- Province.NAVARRE,
- Province.VALENCIA,
- Province.LA_MANCHA,
- Province.ANDALUSIA,
-]
-tPolishControl = [
- Province.BOHEMIA,
- Province.MORAVIA,
- Province.UPPER_HUNGARY,
- Province.PRUSSIA,
- Province.LITHUANIA,
- Province.LIVONIA,
- Province.POLOTSK,
- Province.MINSK,
- Province.VOLHYNIA,
- Province.PODOLIA,
- Province.MOLDOVA,
- Province.KIEV,
-]
-tGenoaControl = [
- Province.CORSICA,
- Province.SARDINIA,
- Province.CRETE,
- Province.RHODES,
- Province.THRAKESION,
- Province.CYPRUS,
- Province.CRIMEA,
-]
-tEnglandControl = [
- Province.AQUITAINE,
- Province.LONDON,
- Province.WALES,
- Province.WESSEX,
- Province.SCOTLAND,
- Province.EAST_ANGLIA,
- Province.MERCIA,
- Province.NORTHUMBRIA,
- Province.IRELAND,
- Province.NORMANDY,
- Province.BRETAGNE,
- Province.ILE_DE_FRANCE,
- Province.ORLEANS,
- Province.PICARDY,
-]
-tPortugalControlI = [Province.AZORES, Province.CANARIES, Province.MADEIRA]
-tPortugalControlII = [Province.MOROCCO, Province.TETOUAN, Province.ORAN]
-tAustriaControl = [
- Province.HUNGARY,
- Province.UPPER_HUNGARY,
- Province.AUSTRIA,
- Province.CARINTHIA,
- Province.BAVARIA,
- Province.TRANSYLVANIA,
- Province.PANNONIA,
- Province.MORAVIA,
- Province.SILESIA,
- Province.BOHEMIA,
-]
-tOttomanControlI = [
- Province.SERBIA,
- Province.BOSNIA,
- Province.BANAT,
- Province.MACEDONIA,
- Province.THRACE,
- Province.MOESIA,
- Province.CONSTANTINOPLE,
- Province.ARBERIA,
- Province.EPIRUS,
- Province.THESSALONIKI,
- Province.THESSALY,
- Province.MOREA,
- Province.COLONEA,
- Province.ANTIOCHIA,
- Province.CHARSIANON,
- Province.CILICIA,
- Province.ARMENIAKON,
- Province.ANATOLIKON,
- Province.PAPHLAGONIA,
- Province.THRAKESION,
- Province.OPSIKION,
- Province.SYRIA,
- Province.LEBANON,
- Province.JERUSALEM,
- Province.EGYPT,
-]
-tOttomanWonders = [
- Wonder.TOPKAPI_PALACE,
- Wonder.BLUE_MOSQUE,
- Wonder.SELIMIYE_MOSQUE,
- Wonder.TOMB_AL_WALID,
-]
-tOttomanControlII = [Province.AUSTRIA, Province.PANNONIA, Province.LESSER_POLAND]
-tMoscowControl = [
- Province.DONETS,
- Province.KUBAN,
- Province.ZAPORIZHIA,
- Province.SLOBODA,
- Province.KIEV,
- Province.MOLDOVA,
- Province.CRIMEA,
- Province.PEREYASLAVL,
- Province.CHERNIGOV,
- Province.SIMBIRSK,
- Province.NIZHNYNOVGOROD,
- Province.VOLOGDA,
- Province.ROSTOV,
- Province.NOVGOROD,
- Province.KARELIA,
- Province.SMOLENSK,
- Province.POLOTSK,
- Province.MINSK,
- Province.VOLHYNIA,
- Province.PODOLIA,
- Province.MOSCOW,
- Province.MUROM,
-]
-# tSwedenControlI = [ Province.GOTALAND, Province.SVEALAND, Province.NORRLAND, Province.SKANELAND, Province.GOTLAND, Province.OSTERLAND ]
-# tSwedenControlII = [ Province.SAXONY, Province.BRANDENBURG, Province.HOLSTEIN, Province.POMERANIA, Province.PRUSSIA, Province.GREATER_POLAND, Province.MASOVIA, Province.SUVALKIJA, Province.LITHUANIA, Province.LIVONIA, Province.ESTONIA, Province.SMOLENSK, Province.POLOTSK, Province.MINSK, Province.MUROM, Province.CHERNIGOV, Province.MOSCOW, Province.NOVGOROD, Province.ROSTOV ]
-tSwedenControl = [Province.NORRLAND, Province.OSTERLAND, Province.KARELIA]
-tNovgorodControl = [
- Province.NOVGOROD,
- Province.KARELIA,
- Province.ESTONIA,
- Province.LIVONIA,
- Province.ROSTOV,
- Province.VOLOGDA,
- Province.OSTERLAND,
-]
-# tNovgorodControlII = [ Province.KARELIA, Province.VOLOGDA ]
-tMoroccoControl = [
- Province.MOROCCO,
- Province.MARRAKESH,
- Province.FEZ,
- Province.TETOUAN,
- Province.ORAN,
- Province.ALGIERS,
- Province.IFRIQIYA,
- Province.ANDALUSIA,
- Province.VALENCIA,
- Province.BALEARS,
-]
-tAragonControlI = [
- Province.CATALONIA,
- Province.VALENCIA,
- Province.BALEARS,
- Province.SICILY,
-]
-tAragonControlII = [
- Province.CATALONIA,
- Province.VALENCIA,
- Province.ARAGON,
- Province.BALEARS,
- Province.CORSICA,
- Province.SARDINIA,
- Province.SICILY,
- Province.CALABRIA,
- Province.APULIA,
- Province.PROVENCE,
- Province.THESSALY,
-]
-tPrussiaControlI = [
- Province.LITHUANIA,
- Province.SUVALKIJA,
- Province.LIVONIA,
- Province.ESTONIA,
- Province.POMERANIA,
- Province.PRUSSIA,
-]
-tPrussiaDefeat = [
- Civ.AUSTRIA,
- Civ.MOSCOW,
- Civ.GERMANY,
- Civ.SWEDEN,
- Civ.FRANCE,
- Civ.CASTILE,
-]
-tScotlandControl = [
- Province.SCOTLAND,
- Province.THE_ISLES,
- Province.IRELAND,
- Province.WALES,
- Province.BRETAGNE,
-]
-tDenmarkControlI = [
- Province.DENMARK,
- Province.SKANELAND,
- Province.GOTALAND,
- Province.SVEALAND,
- Province.MERCIA,
- Province.LONDON,
- Province.EAST_ANGLIA,
- Province.NORTHUMBRIA,
-]
-# tDenmarkControlII = [ Province.BRANDENBURG, Province.POMERANIA, Province.ESTONIA ]
-tDenmarkControlIII = [
- Province.DENMARK,
- Province.NORWAY,
- Province.VESTFOLD,
- Province.SKANELAND,
- Province.GOTALAND,
- Province.SVEALAND,
- Province.NORRLAND,
- Province.GOTLAND,
- Province.OSTERLAND,
- Province.ESTONIA,
- Province.ICELAND,
-]
-
-# tHugeHungaryControl = ( 0, 23, 99, 72 )
-totalLand = gc.getMap().getLandPlots()
-
-
-class Victory:
- def __init__(self):
- self.switchConditionsPerCiv = {
- Civ.BYZANTIUM: self.checkByzantium,
- Civ.FRANCE: self.checkFrankia,
- Civ.ARABIA: self.checkArabia,
- Civ.BULGARIA: self.checkBulgaria,
- Civ.CORDOBA: self.checkCordoba,
- Civ.VENECIA: self.checkVenecia,
- Civ.BURGUNDY: self.checkBurgundy,
- Civ.GERMANY: self.checkGermany,
- Civ.NOVGOROD: self.checkNovgorod,
- Civ.NORWAY: self.checkNorway,
- Civ.KIEV: self.checkKiev,
- Civ.HUNGARY: self.checkHungary,
- Civ.CASTILE: self.checkSpain,
- Civ.DENMARK: self.checkDenmark,
- Civ.SCOTLAND: self.checkScotland,
- Civ.POLAND: self.checkPoland,
- Civ.GENOA: self.checkGenoa,
- Civ.MOROCCO: self.checkMorocco,
- Civ.ENGLAND: self.checkEngland,
- Civ.PORTUGAL: self.checkPortugal,
- Civ.ARAGON: self.checkAragon,
- Civ.SWEDEN: self.checkSweden,
- Civ.PRUSSIA: self.checkPrussia,
- Civ.LITHUANIA: self.checkLithuania,
- Civ.AUSTRIA: self.checkAustria,
- Civ.OTTOMAN: self.checkTurkey,
- Civ.MOSCOW: self.checkMoscow,
- Civ.DUTCH: self.checkDutch,
- }
-
- ##################################################
- ### Secure storage & retrieval of script data ###
- ################################################
-
- def setup(self):
- # ignore AI goals
- bIgnoreAI = gc.getDefineINT("NO_AI_UHV_CHECKS") == 1
- self.setIgnoreAI(bIgnoreAI)
- if bIgnoreAI:
- for iPlayer in civilizations().majors().ids():
- if human() != iPlayer:
- self.setAllUHVFailed(iPlayer)
-
- def isIgnoreAI(self):
- return data.bIgnoreAIUHV
-
- def setIgnoreAI(self, bVal):
- data.bIgnoreAIUHV = bVal
-
- #######################################
- ### Main methods (Event-Triggered) ###
- #####################################
-
- def checkTurn(self, iGameTurn):
- pass
-
- def checkPlayerTurn(self, iGameTurn, iPlayer):
- # We use Python version of Switch statement, it is supposed to be better, now all condition checks are in separate functions
- pPlayer = gc.getPlayer(iPlayer)
- if iPlayer != human() and self.isIgnoreAI():
- return
- if not gc.getGame().isVictoryValid(7): # 7 == historical
- return
- if not pPlayer.isAlive():
- return
- if iPlayer >= civilizations().main().len():
- return
-
- self.switchConditionsPerCiv[iPlayer](iGameTurn)
-
- # Generic checks:
- if not pPlayer.getUHV2of3():
- if (
- countAchievedGoals(iPlayer) >= 2
- ): # in case the last 2 goals were achieved in the same turn
- # intermediate bonus
- pPlayer.setUHV2of3(True)
- if pPlayer.getNumCities() > 0: # this check is needed, otherwise game crashes
- capital = pPlayer.getCapitalCity()
- # 3Miro: Golden Age after 2/3 victories
- capital.setHasRealBuilding(Building.TRIUMPHAL_ARCH, True)
- if pPlayer.isHuman():
- message(
- iPlayer, text("TXT_KEY_VICTORY_INTERMEDIATE"), color=MessageData.PURPLE
- )
- for iCiv in civilizations().majors().ids():
- if iCiv != iPlayer:
- pCiv = gc.getPlayer(iCiv)
- if pCiv.isAlive():
- iAttitude = pCiv.AI_getAttitude(iPlayer)
- if iAttitude != 0:
- pCiv.AI_setAttitudeExtra(iPlayer, iAttitude - 1)
-
- # Absinthe: maximum 3 of your rivals declare war on you
- lCivs = [
- iCiv
- for iCiv in civilizations().main().ids()
- if iCiv != iPlayer and gc.getPlayer(iCiv).isAlive()
- ]
- iWarCounter = 0
- # we run through a randomized list of all available civs
- random.shuffle(lCivs)
- for iCiv in lCivs:
- pCiv = gc.getPlayer(iCiv)
- teamCiv = gc.getTeam(pCiv.getTeam())
- # skip civ if it's vassal (safety check for own vassals, want to look for the master for other vassals)
- if teamCiv.isAVassal():
- continue
- if teamCiv.canDeclareWar(pPlayer.getTeam()):
- if pCiv.canContact(iPlayer) and not teamCiv.isAtWar(iPlayer):
- iModifier = 0
- # bigger chance for civs which hate you
- if pCiv.AI_getAttitude(iPlayer) == 0:
- iModifier += 3
- elif pCiv.AI_getAttitude(iPlayer) == 1:
- iModifier += 1
- elif pCiv.AI_getAttitude(iPlayer) == 3:
- iModifier -= 1
- elif pCiv.AI_getAttitude(iPlayer) == 4:
- iModifier -= 3
- # bigger chance for close civs
- PlayerCapital = gc.getPlayer(iPlayer).getCapitalCity()
- CivCapital = gc.getPlayer(iCiv).getCapitalCity()
- iDistance = calculateDistance(
- CivCapital.getX(),
- CivCapital.getY(),
- PlayerCapital.getX(),
- PlayerCapital.getY(),
- )
- if iDistance < 20:
- iModifier += 2
- elif iDistance < 40:
- iModifier += 1
- # bigger chance for big civs
- if pCiv.getNumCities() > 19:
- iModifier += 4
- elif pCiv.getNumCities() > 14:
- iModifier += 3
- elif pCiv.getNumCities() > 9:
- iModifier += 2
- elif pCiv.getNumCities() > 4:
- iModifier += 1
- iRndnum = rand(7)
- if iRndnum + iModifier > 6:
- teamCiv.declareWar(pPlayer.getTeam(), True, -1)
- iWarCounter += 1
- if iWarCounter == 3:
- break
- if iWarCounter > 0:
- message(
- iPlayer,
- text("TXT_KEY_VICTORY_RIVAL_CIVS"),
- color=MessageData.LIGHT_RED,
- )
-
- if gc.getGame().getWinner() == -1:
- if pPlayer.getUHV(0) == 1 and pPlayer.getUHV(1) == 1 and pPlayer.getUHV(2) == 1:
- gc.getGame().setWinner(iPlayer, 7) # Historical Victory
-
- def onCityBuilt(self, city, iPlayer): # see onCityBuilt in CvRFCEventHandler
- # Portugal UHV 1: Settle 3 cities on the Azores, Canaries and Madeira and 2 in Morocco, Tetouan and Oran
- if iPlayer == Civ.PORTUGAL:
- if self.isPossibleUHV(iPlayer, 0, False):
- iProv = city.getProvince()
- if iProv in tPortugalControlI or iProv in tPortugalControlII:
- iCounter = player(Civ.PORTUGAL).getUHVCounter(0)
- iIslands = iCounter % 100
- iAfrica = iCounter / 100
- if iProv in tPortugalControlI:
- iIslands += 1
- else:
- iAfrica += 1
- if iIslands >= 3 and iAfrica >= 2:
- self.wonUHV(Civ.PORTUGAL, 0)
- player(Civ.PORTUGAL).setUHVCounter(0, iAfrica * 100 + iIslands)
-
- def onReligionFounded(self, iReligion, iFounder):
- # Germany UHV 2: Start the Reformation (Found Protestantism)
- if iReligion == Religion.PROTESTANTISM:
- if iFounder == Civ.GERMANY:
- self.wonUHV(Civ.GERMANY, 1)
- else:
- self.lostUHV(Civ.GERMANY, 1)
-
- def onCityAcquired(self, owner, iNewOwner, city, bConquest, bTrade):
- if not gc.getGame().isVictoryValid(7): # Victory 7 == historical
- return
-
- iPlayer = owner
- iGameTurn = turn()
-
- # Bulgaria UHV 3: Do not lose a city to Barbarians, Mongols, Byzantines, or Ottomans before 1396
- if iPlayer == Civ.BULGARIA:
- if self.isPossibleUHV(iPlayer, 2, False):
- if iGameTurn <= year(1396):
- if iNewOwner in [Civ.BARBARIAN, Civ.BYZANTIUM, Civ.OTTOMAN]:
- # conquered and flipped cities always count
- # for traded cities, there should be a distinction between traded in peace (gift) and traded in ending a war (peace negotiations)
- # instead of that, we check if the civ is at peace when the trade happens
- # TODO#BUG# unfortunately the trade deal just ending a war is taken into account as a peace deal - maybe check if there was a war in this turn, or the last couple turns?
- if not bTrade:
- self.lostUHV(Civ.BULGARIA, 2)
- else:
- bIsAtWar = False
- for civ in civilizations().take(Civ.BYZANTIUM, Civ.OTTOMAN).alive():
- if civilization(Civ.BULGARIA).at_war(civ):
- bIsAtWar = True
- if bIsAtWar:
- self.lostUHV(Civ.BULGARIA, 2)
-
- # Portugal UHV 2: Do not lose a city before 1640
- elif iPlayer == Civ.PORTUGAL:
- if self.isPossibleUHV(iPlayer, 1, False):
- # conquered and flipped cities always count
- # for traded cities, there should be a distinction between traded in peace (gift) and traded in ending a war (peace negotiations)
- # instead of that, we check if the civ is at peace when the trade happens
- # TODO#BUG# unfortunately the trade deal just ending a war is taken into account as a peace deal - maybe check if there was a war in this turn, or the last couple turns?
- if not bTrade:
- self.lostUHV(Civ.PORTUGAL, 1)
- else:
- bIsAtWar = False
- for civ in civilizations().majors().alive():
- if civilization(Civ.BULGARIA).at_war(civ):
- bIsAtWar = True
- break
- if bIsAtWar:
- self.lostUHV(Civ.PORTUGAL, 1)
-
- # Norway UHV 1: Going Viking
- elif iNewOwner == Civ.NORWAY and iGameTurn < year(1066) + 2:
- # Absinthe: city is already reduced by 1 on city conquest, so city.getPopulation() is one less than the original size (unless it was already 1)
- if bConquest:
- if city.getPopulation() > 1:
- player(Civ.NORWAY).setUHVCounter(
- 0, player(Civ.NORWAY).getUHVCounter(0) + city.getPopulation() + 1
- )
- else:
- player(Civ.NORWAY).setUHVCounter(
- 0, player(Civ.NORWAY).getUHVCounter(0) + city.getPopulation()
- )
-
- # Poland UHV 3: Construct 3 Catholic and Orthodox Cathedrals, 2 Protestant Cathedrals, and have at least 2 Jewish Quarters in your cities
- elif iNewOwner == Civ.POLAND:
- if self.isPossibleUHV(iNewOwner, 2, False):
- if city.hasBuilding(
- Wonder.KAZIMIERZ
- ): # you cannot acquire religious buildings on conquest, only wonders
- iCounter = player(Civ.POLAND).getUHVCounter(2)
- iCathCath = (iCounter / 10000) % 10
- iOrthCath = (iCounter / 1000) % 10
- iProtCath = (iCounter / 100) % 10
- iJewishQu = 99
- iCounter = iJewishQu + 100 * iProtCath + 1000 * iOrthCath + 10000 * iCathCath
- player(Civ.POLAND).setUHVCounter(2, iCounter)
- if iCathCath >= 3 and iOrthCath >= 2 and iProtCath >= 2 and iJewishQu >= 2:
- self.wonUHV(Civ.POLAND, 2)
-
- # Prussia UHV 2: Conquer two cities from each of Austria, Muscovy, Germany, Sweden, France and Spain between 1650 and 1763, if they are still alive
- elif iNewOwner == Civ.PRUSSIA:
- if self.isPossibleUHV(iNewOwner, 1, False):
- if owner in tPrussiaDefeat and year(1650) <= iGameTurn <= year(1763):
- lNumConq = []
- iConqRaw = player(Civ.PRUSSIA).getUHVCounter(1)
- bConq = True
- for iI in range(len(tPrussiaDefeat)):
- lNumConq.append((iConqRaw / pow(10, iI)) % 10)
- if tPrussiaDefeat[iI] == owner:
- lNumConq[iI] += 1
- if lNumConq[iI] > 9:
- # Prevent overflow
- lNumConq[iI] = 9
- if lNumConq[iI] < 2 and gc.getPlayer(tPrussiaDefeat[iI]).isAlive():
- bConq = False
-
- if bConq:
- self.wonUHV(Civ.PRUSSIA, 1)
-
- iConqRaw = 0
- for iI in range(len(tPrussiaDefeat)):
- iConqRaw += lNumConq[iI] * pow(10, iI)
- player(Civ.PRUSSIA).setUHVCounter(1, iConqRaw)
-
- def onCityRazed(self, iPlayer, city):
- # Sweden UHV 2: Raze 5 Catholic cities while being Protestant by 1660
- if iPlayer == Civ.SWEDEN:
- if self.isPossibleUHV(iPlayer, 1, False):
- if civilization(Civ.SWEDEN).has_state_religion(
- Religion.PROTESTANTISM
- ) and city.isHasReligion(Religion.CATHOLICISM):
- iRazed = player(Civ.SWEDEN).getUHVCounter(1) + 1
- player(Civ.SWEDEN).setUHVCounter(1, iRazed)
- if iRazed >= 5:
- self.wonUHV(Civ.SWEDEN, 1)
-
- def onPillageImprovement(self, iPillager, iVictim, iImprovement, iRoute, iX, iY):
- # Norway UHV 1: Going Viking
- if iPillager == Civ.NORWAY and iRoute == -1 and turn() < year(1066) + 2:
- if gc.getMap().plot(iX, iY).getOwner() != Civ.NORWAY:
- player(Civ.NORWAY).setUHVCounter(0, player(Civ.NORWAY).getUHVCounter(0) + 1)
-
- def onCombatResult(self, argsList):
- pWinningUnit, pLosingUnit = argsList
- cLosingUnit = PyHelpers.PyInfo.UnitInfo(pLosingUnit.getUnitType())
-
- # Norway UHV 1: Going Viking
- if pWinningUnit.getOwner() == Civ.NORWAY and turn() < year(1066) + 2:
- if cLosingUnit.getDomainType() == DomainTypes.DOMAIN_SEA:
- # Absinthe: only 1 Viking point for Work Boats
- if pLosingUnit.getUnitType() != Unit.WORKBOAT:
- player(Civ.NORWAY).setUHVCounter(0, player(Civ.NORWAY).getUHVCounter(0) + 2)
- else:
- player(Civ.NORWAY).setUHVCounter(0, player(Civ.NORWAY).getUHVCounter(0) + 1)
-
- def onTechAcquired(self, iTech, iPlayer):
- if not gc.getGame().isVictoryValid(7): # 7 == historical
- return
-
- # England UHV 3: Be the first to enter the Industrial age
- if iTech == Technology.INDUSTRIAL_TECH:
- if self.isPossibleUHV(Civ.ENGLAND, 2, False):
- if iPlayer == Civ.ENGLAND:
- self.wonUHV(Civ.ENGLAND, 2)
- else:
- self.lostUHV(Civ.ENGLAND, 2)
-
- def onBuildingBuilt(self, iPlayer, iBuilding):
- if not gc.getGame().isVictoryValid(7): # 7 == historical
- return
-
- iGameTurn = turn()
-
- # Kiev UHV 1: Build 2 Orthodox cathedrals and 8 Orthodox monasteries by 1250
- if iPlayer == Civ.KIEV:
- if self.isPossibleUHV(iPlayer, 0, False):
- if iBuilding in [
- Building.ORTHODOX_MONASTERY,
- Building.ORTHODOX_CATHEDRAL,
- ]:
- iBuildSoFar = player(Civ.KIEV).getUHVCounter(0)
- iCathedralCounter = iBuildSoFar % 100
- iMonasteryCounter = iBuildSoFar / 100
- if iBuilding == Building.ORTHODOX_MONASTERY:
- iMonasteryCounter += 1
- else:
- iCathedralCounter += 1
- if iCathedralCounter >= 2 and iMonasteryCounter >= 8:
- self.wonUHV(Civ.KIEV, 0)
- player(Civ.KIEV).setUHVCounter(0, 100 * iMonasteryCounter + iCathedralCounter)
-
- # Poland UHV 3: Construct 3 Catholic and Orthodox Cathedrals, 2 Protestant Cathedrals, and have at least 2 Jewish Quarters in your cities
- # HHG: Polish UHV3 now uses Wonder Kazimierz with maximum value 99, and all other buildings have boundary checks
- elif iPlayer == Civ.POLAND:
- if self.isPossibleUHV(iPlayer, 2, False):
- lBuildingList = [
- Building.CATHOLIC_CATHEDRAL,
- Building.ORTHODOX_CATHEDRAL,
- Building.PROTESTANT_CATHEDRAL,
- Building.JEWISH_QUARTER,
- Wonder.KAZIMIERZ,
- ]
- if iBuilding in lBuildingList:
- iCounter = player(Civ.POLAND).getUHVCounter(2)
- iCathCath = (iCounter / 10000) % 10
- iOrthCath = (iCounter / 1000) % 10
- iProtCath = (iCounter / 100) % 10
- iJewishQu = iCounter % 100
- if iBuilding == Building.CATHOLIC_CATHEDRAL and iCathCath < 9:
- iCathCath += 1
- elif iBuilding == Building.ORTHODOX_CATHEDRAL and iOrthCath < 9:
- iOrthCath += 1
- elif iBuilding == Building.PROTESTANT_CATHEDRAL and iProtCath < 9:
- iProtCath += 1
- elif iBuilding == Wonder.KAZIMIERZ:
- iJewishQu = 99
- elif iBuilding == Building.JEWISH_QUARTER and iJewishQu < 99:
- iJewishQu += 1
- if iCathCath >= 3 and iOrthCath >= 3 and iProtCath >= 2 and iJewishQu >= 2:
- self.wonUHV(Civ.POLAND, 2)
- iCounter = iJewishQu + 100 * iProtCath + 1000 * iOrthCath + 10000 * iCathCath
- player(Civ.POLAND).setUHVCounter(2, iCounter)
-
- # Cordoba UHV 2: Build the Alhambra, the Gardens of Al-Andalus, and La Mezquita by 1309
- if iBuilding in tCordobaWonders:
- if self.isPossibleUHV(Civ.CORDOBA, 1, False):
- if iPlayer == Civ.CORDOBA:
- iWondersBuilt = player(Civ.CORDOBA).getUHVCounter(1)
- player(Civ.CORDOBA).setUHVCounter(1, iWondersBuilt + 1)
- if iWondersBuilt == 2: # so we already had 2 wonders, and this is the 3rd one
- self.wonUHV(Civ.CORDOBA, 1)
- else:
- self.lostUHV(Civ.CORDOBA, 1)
-
- # Ottoman UHV 2: Construct the Topkapi Palace, the Blue Mosque, the Selimiye Mosque and the Tomb of Al-Walid by 1616
- if iBuilding in tOttomanWonders:
- if self.isPossibleUHV(Civ.OTTOMAN, 1, False):
- if iPlayer == Civ.OTTOMAN:
- iWondersBuilt = player(Civ.OTTOMAN).getUHVCounter(1)
- player(Civ.OTTOMAN).setUHVCounter(1, iWondersBuilt + 1)
- if iWondersBuilt == 3: # so we already had 3 wonders, and this is the 4th one
- self.wonUHV(Civ.OTTOMAN, 1)
- else:
- self.lostUHV(Civ.OTTOMAN, 1)
-
- def onProjectBuilt(self, iPlayer, iProject):
- bColony = self.isProjectAColony(iProject)
- # Absinthe: note that getProjectCount (thus getNumRealColonies too) won't count the latest project/colony (which was currently built) if called from this function
- # way more straightforward, and also faster to use the UHVCounters for the UHV checks
-
- # Venice UHV 3: Be the first to build a Colony from the Age of Discovery (Vinland is from the Viking Age)
- if self.isPossibleUHV(Civ.VENECIA, 2, False):
- if iProject != Colony.VINLAND:
- if bColony:
- if iPlayer == Civ.VENECIA:
- self.wonUHV(Civ.VENECIA, 2)
- else:
- self.lostUHV(Civ.VENECIA, 2)
-
- # France UHV 3: Build 5 Colonies
- if iPlayer == Civ.FRANCE:
- if self.isPossibleUHV(iPlayer, 2, False):
- if bColony:
- player(Civ.FRANCE).setUHVCounter(2, player(Civ.FRANCE).getUHVCounter(2) + 1)
- if player(Civ.FRANCE).getUHVCounter(2) >= 5:
- self.wonUHV(Civ.FRANCE, 2)
-
- # England UHV 2: Build 7 Colonies
- elif iPlayer == Civ.ENGLAND:
- if self.isPossibleUHV(iPlayer, 1, False):
- if bColony:
- player(Civ.ENGLAND).setUHVCounter(1, player(Civ.ENGLAND).getUHVCounter(1) + 1)
- if player(Civ.ENGLAND).getUHVCounter(1) >= 7:
- self.wonUHV(Civ.ENGLAND, 1)
-
- # Spain UHV 2: Have more Colonies than any other nation in 1588 (while having at least 3)
- # this is only for the Main Screen counter
- elif iPlayer == Civ.CASTILE:
- player(Civ.CASTILE).setUHVCounter(1, player(Civ.CASTILE).getUHVCounter(1) + 1)
-
- # Portugal UHV 3: Build 5 Colonies
- elif iPlayer == Civ.PORTUGAL:
- if self.isPossibleUHV(iPlayer, 2, False):
- if bColony:
- player(Civ.PORTUGAL).setUHVCounter(
- 2, player(Civ.PORTUGAL).getUHVCounter(2) + 1
- )
- if player(Civ.PORTUGAL).getUHVCounter(2) >= 5:
- self.wonUHV(Civ.PORTUGAL, 2)
-
- # Dutch UHV 2: Build 3 Colonies and complete both Trading Companies
- elif iPlayer == Civ.DUTCH:
- if self.isPossibleUHV(iPlayer, 1, False):
- if bColony:
- player(Civ.DUTCH).setUHVCounter(1, player(Civ.DUTCH).getUHVCounter(1) + 1)
- if player(Civ.DUTCH).getUHVCounter(1) >= 3:
- iWestCompany = team(Civ.DUTCH).getProjectCount(Project.WEST_INDIA_COMPANY)
- iEastCompany = team(Civ.DUTCH).getProjectCount(Project.EAST_INDIA_COMPANY)
- # if the companies are already built previously, or currently being built (one of them is the current project)
- if iProject == Project.WEST_INDIA_COMPANY or iWestCompany >= 1:
- if iProject == Project.EAST_INDIA_COMPANY or iEastCompany >= 1:
- self.wonUHV(Civ.DUTCH, 1)
-
- # Denmark UHV 3: Build 3 Colonies and complete both Trading Companies
- elif iPlayer == Civ.DENMARK:
- if self.isPossibleUHV(iPlayer, 2, False):
- if bColony:
- player(Civ.DENMARK).setUHVCounter(2, player(Civ.DENMARK).getUHVCounter(2) + 1)
- if player(Civ.DENMARK).getUHVCounter(2) >= 3:
- iWestCompany = team(Civ.DENMARK).getProjectCount(Project.WEST_INDIA_COMPANY)
- iEastCompany = team(Civ.DENMARK).getProjectCount(Project.EAST_INDIA_COMPANY)
- # if the companies are already built previously, or currently being built (one of them is the current project)
- if iProject == Project.WEST_INDIA_COMPANY or iWestCompany == 1:
- if iProject == Project.EAST_INDIA_COMPANY or iEastCompany == 1:
- self.wonUHV(Civ.DENMARK, 2)
-
- def getOwnedLuxes(self, pPlayer):
- lBonus = [
- Bonus.SHEEP,
- Bonus.DYE,
- Bonus.FUR,
- Bonus.GEMS,
- Bonus.GOLD,
- Bonus.INCENSE,
- Bonus.IVORY,
- Bonus.SILK,
- Bonus.SILVER,
- Bonus.SPICES,
- Bonus.WINE,
- Bonus.HONEY,
- Bonus.WHALE,
- Bonus.AMBER,
- Bonus.COTTON,
- Bonus.COFFEE,
- Bonus.TEA,
- Bonus.TOBACCO,
- ]
- iCount = 0
- for iBonus in lBonus:
- iCount += pPlayer.countOwnedBonuses(iBonus)
- return iCount
-
- def getOwnedGrain(self, pPlayer):
- iCount = 0
- iCount += pPlayer.countOwnedBonuses(Bonus.WHEAT)
- iCount += pPlayer.countOwnedBonuses(Bonus.BARLEY)
- return iCount
-
- def isProjectAColony(self, iProject):
- if iProject >= len(Project):
- return True
- else:
- return False
-
- def getNumRealColonies(self, iPlayer):
- pPlayer = gc.getPlayer(iPlayer)
- tPlayer = gc.getTeam(pPlayer.getTeam())
- iCount = 0
- for col in Colony:
- if tPlayer.getProjectCount(col) > 0:
- iCount += 1
- return iCount
-
- def getTerritoryPercentEurope(self, iPlayer, bReturnTotal=False):
- iTotal = 0
- iCount = 0
- for plot in plots().all().land().not_provinces(*REGIONS[Region.NOT_EUROPE]).entities():
- iTotal += 1
- if plot.getOwner() == iPlayer:
- iCount += 1
- if bReturnTotal:
- return iCount, iTotal
- return iCount
-
- def checkByzantium(self, iGameTurn):
-
- # UHV 1: Own at least 6 cities in Calabria, Apulia, Dalmatia, Verona, Lombardy, Liguria, Tuscany, Latium, Corsica, Sardinia, Sicily, Tripolitania and Ifriqiya provinces in 632
- if iGameTurn == year(632):
- if self.isPossibleUHV(Civ.BYZANTIUM, 0, True):
- iNumCities = 0
- for iProv in tByzantiumControl:
- iNumCities += player(Civ.BYZANTIUM).getProvinceCityCount(iProv)
- if iNumCities >= 6:
- self.wonUHV(Civ.BYZANTIUM, 0)
- else:
- self.lostUHV(Civ.BYZANTIUM, 0)
-
- # UHV 2: Control Constantinople, Thrace, Thessaloniki, Moesia, Macedonia, Serbia, Arberia, Epirus, Thessaly, Morea, Colonea, Antiochia, Charsianon, Cilicia, Armeniakon, Anatolikon, Paphlagonia, Thrakesion and Opsikion in 1282
- elif iGameTurn == year(1282):
- if self.isPossibleUHV(Civ.BYZANTIUM, 1, True):
- if self.checkProvincesStates(Civ.BYZANTIUM, tByzantiumControlII):
- self.wonUHV(Civ.BYZANTIUM, 1)
- else:
- self.lostUHV(Civ.BYZANTIUM, 1)
-
- # UHV 3: Make Constantinople the largest and most cultured city while being the richest empire in the world in 1453
- elif iGameTurn == year(1453):
- if self.isPossibleUHV(Civ.BYZANTIUM, 2, True):
- x, y = CIV_CAPITAL_LOCATIONS[Civ.BYZANTIUM]
- iGold = player(Civ.BYZANTIUM).getGold()
- bMost = True
- for iCiv in civilizations().majors().ids():
- if iCiv != Civ.BYZANTIUM and gc.getPlayer(iCiv).isAlive():
- if gc.getPlayer(iCiv).getGold() > iGold:
- bMost = False
- break
- if (
- gc.isLargestCity(x, y)
- and gc.isTopCultureCity(x, y)
- and gc.getMap().plot(x, y).getPlotCity().getOwner() == Civ.BYZANTIUM
- and bMost
- ):
- self.wonUHV(Civ.BYZANTIUM, 2)
- else:
- self.lostUHV(Civ.BYZANTIUM, 2)
-
- def checkFrankia(self, iGameTurn):
-
- # UHV 1: Achieve Charlemagne's Empire by 840
- if self.isPossibleUHV(Civ.FRANCE, 0, True):
- if self.checkProvincesStates(Civ.FRANCE, tFrankControl):
- self.wonUHV(Civ.FRANCE, 0)
- if iGameTurn == year(840):
- self.expireUHV(Civ.FRANCE, 0)
-
- # UHV 2: Control Jerusalem in 1291
- elif iGameTurn == year(1291):
- if self.isPossibleUHV(Civ.FRANCE, 1, True):
- pJPlot = gc.getMap().plot(*CITIES[City.JERUSALEM])
- if pJPlot.isCity():
- if pJPlot.getPlotCity().getOwner() == Civ.FRANCE:
- self.wonUHV(Civ.FRANCE, 1)
- else:
- self.lostUHV(Civ.FRANCE, 1)
- else:
- self.lostUHV(Civ.FRANCE, 1)
-
- # UHV 3: Build 5 Colonies
- # handled in the onProjectBuilt function
-
- def checkArabia(self, iGameTurn):
-
- # UHV 1: Control all territories from Tunisia to Asia Minor in 850
- if iGameTurn == year(850):
- if self.isPossibleUHV(Civ.ARABIA, 0, True):
- if self.checkProvincesStates(Civ.ARABIA, tArabiaControlI):
- self.wonUHV(Civ.ARABIA, 0)
- else:
- self.lostUHV(Civ.ARABIA, 0)
-
- # UHV 2: Control the Levant and Egypt in 1291AD while being the most advanced civilization
- elif iGameTurn == year(1291):
- if self.isPossibleUHV(Civ.ARABIA, 1, True):
- iMostAdvancedCiv = getMostAdvancedCiv()
- if (
- self.checkProvincesStates(Civ.ARABIA, tArabiaControlII)
- and iMostAdvancedCiv == Civ.ARABIA
- ):
- self.wonUHV(Civ.ARABIA, 1)
- else:
- self.lostUHV(Civ.ARABIA, 1)
-
- # UHV 3: Spread Islam to at least 35% of the population of Europe
- if self.isPossibleUHV(Civ.ARABIA, 2, True):
- iPerc = gc.getGame().calculateReligionPercent(Religion.ISLAM)
- if iPerc >= 35:
- self.wonUHV(Civ.ARABIA, 2)
-
- def checkBulgaria(self, iGameTurn):
-
- # UHV 1: Conquer Moesia, Thrace, Macedonia, Serbia, Arberia, Thessaloniki and Constantinople by 917
- if self.isPossibleUHV(Civ.BULGARIA, 0, True):
- if self.checkProvincesStates(Civ.BULGARIA, tBulgariaControl):
- self.wonUHV(Civ.BULGARIA, 0)
- if iGameTurn == year(917):
- self.expireUHV(Civ.BULGARIA, 0)
-
- # UHV 2: Accumulate at least 100 Orthodox Faith Points by 1259
- if self.isPossibleUHV(Civ.BULGARIA, 1, True):
- if (
- civilization(Civ.BULGARIA).has_state_religion(Religion.ORTHODOXY)
- and player(Civ.BULGARIA).getFaith() >= 100
- ):
- self.wonUHV(Civ.BULGARIA, 1)
- if iGameTurn == year(1259):
- self.expireUHV(Civ.BULGARIA, 1)
-
- # UHV 3: Do not lose a city to Barbarians, Mongols, Byzantines, or Ottomans before 1396
- # Controlled in the onCityAcquired function
- elif iGameTurn == year(1396):
- if self.isPossibleUHV(Civ.BULGARIA, 2, True):
- self.wonUHV(Civ.BULGARIA, 2)
-
- def checkCordoba(self, iGameTurn):
-
- # UHV 1: Make Cordoba the largest city in the world in 961
- if iGameTurn == year(961):
- if self.isPossibleUHV(Civ.CORDOBA, 0, True):
- x, y = CIV_CAPITAL_LOCATIONS[Civ.CORDOBA]
- if (
- gc.isLargestCity(x, y)
- and gc.getMap().plot(x, y).getPlotCity().getOwner() == Civ.CORDOBA
- ):
- self.wonUHV(Civ.CORDOBA, 0)
- else:
- self.lostUHV(Civ.CORDOBA, 0)
-
- # UHV 2: Build the Alhambra, the Gardens of Al-Andalus, and La Mezquita by 1309
- # Controlled in the onBuildingBuilt function
- elif iGameTurn == year(1309):
- self.expireUHV(Civ.CORDOBA, 1)
-
- # UHV 3: Make sure Islam is present in every city in the Iberian peninsula in 1492
- elif iGameTurn == year(1492):
- if self.isPossibleUHV(Civ.CORDOBA, 2, True):
- bIslamized = True
- for iProv in tCordobaIslamize:
- if not player(Civ.CORDOBA).provinceIsSpreadReligion(iProv, Religion.ISLAM):
- bIslamized = False
- break
- if bIslamized:
- self.wonUHV(Civ.CORDOBA, 2)
- else:
- self.lostUHV(Civ.CORDOBA, 2)
-
- def checkNorway(self, iGameTurn):
-
- # Old UHV1: explore all water tiles
- # if ( iGameTurn == year(1009) and pNorway.getUHV( 0 ) == -1 ):
- # if ( gc.canSeeAllTerrain( iNorway, Terrain.OCEAN ) ):
- # self.wonUHV( iNorway, 0 )
- # else:
- # self.lostUHV( iNorway, 0 )
-
- # UHV 1: Gain 100 Viking Points and build Vinland by 1066
- # Viking points counted in the onCityAcquired, onPillageImprovement and onCombatResult functions
- if self.isPossibleUHV(Civ.NORWAY, 0, True):
- if (
- player(Civ.NORWAY).getUHVCounter(0) >= 100
- and team(Civ.NORWAY).getProjectCount(Colony.VINLAND) >= 1
- ):
- self.wonUHV(Civ.NORWAY, 0)
- if iGameTurn == year(1066):
- self.expireUHV(Civ.NORWAY, 0)
-
- # UHV 2: Conquer The Isles, Ireland, Scotland, Normandy, Sicily, Apulia, Calabria and Iceland by 1194
- if iGameTurn <= year(1194):
- if self.isPossibleUHV(Civ.NORWAY, 1, True):
- if self.checkProvincesStates(Civ.NORWAY, tNorwayControl):
- self.wonUHV(Civ.NORWAY, 1)
- if iGameTurn == year(1194):
- self.expireUHV(Civ.NORWAY, 1)
-
- # UHV 3: Have a higher score than Sweden, Denmark, Scotland, England, Germany and France in 1320
- elif iGameTurn == year(1320):
- if self.isPossibleUHV(Civ.NORWAY, 2, True):
- iNorwayRank = gc.getGame().getTeamRank(Civ.NORWAY)
- bIsOnTop = True
- for iTestPlayer in tNorwayOutrank:
- if gc.getGame().getTeamRank(iTestPlayer) < iNorwayRank:
- bIsOnTop = False
- break
- if bIsOnTop:
- self.wonUHV(Civ.NORWAY, 2)
- else:
- self.lostUHV(Civ.NORWAY, 2)
-
- def checkDenmark(self, iGameTurn):
-
- # UHV 1: Control Denmark, Skaneland, G�taland, Svealand, Mercia, London, Northumbria and East Anglia in 1050
- if iGameTurn == year(1050):
- if self.isPossibleUHV(Civ.DENMARK, 0, True):
- if self.checkProvincesStates(Civ.DENMARK, tDenmarkControlI):
- self.wonUHV(Civ.DENMARK, 0)
- else:
- self.lostUHV(Civ.DENMARK, 0)
-
- # UHV 2: Control Denmark, Norway, Vestfold, Skaneland, G�taland, Svealand, Norrland, Gotland, �sterland, Estonia and Iceland in 1523
- elif iGameTurn == year(1523):
- if self.isPossibleUHV(Civ.DENMARK, 1, True):
- if self.checkProvincesStates(Civ.DENMARK, tDenmarkControlIII):
- self.wonUHV(Civ.DENMARK, 1)
- else:
- self.lostUHV(Civ.DENMARK, 1)
-
- # UHV 3: Build 3 Colonies and complete both Trading Companies
- # handled in the onProjectBuilt function
-
- def checkVenecia(self, iGameTurn):
-
- # UHV 1: Conquer the Adriatic by 1004
- if self.isPossibleUHV(Civ.VENECIA, 0, True):
- if self.checkProvincesStates(Civ.VENECIA, tVenetianControl):
- self.wonUHV(Civ.VENECIA, 0)
- if iGameTurn == year(1004):
- self.expireUHV(Civ.VENECIA, 0)
-
- # UHV 2: Conquer Constantinople, Thessaly, Morea, Crete and Cyprus by 1204
- if self.isPossibleUHV(Civ.VENECIA, 1, True):
- if (
- player(Civ.VENECIA).getProvinceCurrentState(Province.CONSTANTINOPLE)
- >= ProvinceStatus.CONQUER
- ):
- if self.checkProvincesStates(Civ.VENECIA, tVenetianControlII):
- self.wonUHV(Civ.VENECIA, 1)
- if iGameTurn == year(1204):
- self.expireUHV(Civ.VENECIA, 1)
-
- # UHV 3: Be the first to build a Colony from the Age of Discovery
- # UHV 3: Vinland is from the Viking Age, all other Colonies are from the Age of Discovery
- # handled in the onProjectBuilt function
-
- def checkBurgundy(self, iGameTurn):
-
- # UHV 1: Produce 12,000 culture points in your cities by 1336
- # The counter should be updated until the deadline for the challenge UHVs, even after UHV completion
- if iGameTurn < year(1336) + 2:
- iCulture = (
- player(Civ.BURGUNDY).getUHVCounter(0) + player(Civ.BURGUNDY).countCultureProduced()
- )
- player(Civ.BURGUNDY).setUHVCounter(0, iCulture)
- if self.isPossibleUHV(Civ.BURGUNDY, 0, True):
- if iCulture >= 12000:
- self.wonUHV(Civ.BURGUNDY, 0)
- if iGameTurn == year(1336):
- self.expireUHV(Civ.BURGUNDY, 0)
-
- # UHV 2: Control Burgundy, Provence, Picardy, Flanders, Champagne and Lorraine in 1376
- elif iGameTurn == year(1376):
- if self.isPossibleUHV(Civ.BURGUNDY, 1, True):
- if self.checkProvincesStates(Civ.BURGUNDY, tBurgundyControl):
- self.wonUHV(Civ.BURGUNDY, 1)
- else:
- self.lostUHV(Civ.BURGUNDY, 1)
-
- # UHV 3: Have a higher score than France, England and Germany in 1473
- elif iGameTurn == year(1473):
- if self.isPossibleUHV(Civ.BURGUNDY, 2, True):
- iBurgundyRank = gc.getGame().getTeamRank(Civ.BURGUNDY)
- bIsOnTop = True
- for iTestPlayer in tBurgundyOutrank:
- if gc.getGame().getTeamRank(iTestPlayer) < iBurgundyRank:
- bIsOnTop = False
- break
- if bIsOnTop:
- self.wonUHV(Civ.BURGUNDY, 2)
- else:
- self.lostUHV(Civ.BURGUNDY, 2)
-
- def checkGermany(self, iGameTurn):
-
- # Old UHVs: Have most Catholic FPs in 1077 (Walk to Canossa)
- # Have 3 vassals
-
- # UHV 1: Control Lorraine, Swabia, Saxony, Bavaria, Franconia, Brandenburg, Holstein, Lombardy, Liguria and Tuscany in 1167
- if iGameTurn == year(1167):
- if self.isPossibleUHV(Civ.GERMANY, 0, True):
- if self.checkProvincesStates(Civ.GERMANY, tGermanyControl):
- self.wonUHV(Civ.GERMANY, 0)
- else:
- self.lostUHV(Civ.GERMANY, 0)
-
- # UHV 2: Start the Reformation (Found Protestantism)
- # Controlled in the onReligionFounded function
-
- # UHV 3: Control Swabia, Saxony, Bavaria, Franconia, Brandenburg, Holstein, Flanders, Pomerania, Silesia, Bohemia, Moravia and Austria in 1648
- elif iGameTurn == year(1648):
- if self.isPossibleUHV(Civ.GERMANY, 2, True):
- if self.checkProvincesStates(Civ.GERMANY, tGermanyControlII):
- self.wonUHV(Civ.GERMANY, 2)
- else:
- self.lostUHV(Civ.GERMANY, 2)
-
- def checkNovgorod(self, iGameTurn):
-
- # UHV 1: Control Novgorod, Karelia, Estonia, Livonia, Rostov, Vologda and Osterland in 1284
- if iGameTurn == year(1284):
- if self.isPossibleUHV(Civ.NOVGOROD, 0, True):
- if self.checkProvincesStates(Civ.NOVGOROD, tNovgorodControl):
- self.wonUHV(Civ.NOVGOROD, 0)
- else:
- self.lostUHV(Civ.NOVGOROD, 0)
-
- # UHV 2: Control eleven sources of fur by 1397
- if self.isPossibleUHV(Civ.NOVGOROD, 1, True):
- if player(Civ.NOVGOROD).countCultBorderBonuses(Bonus.FUR) >= 11:
- self.wonUHV(Civ.NOVGOROD, 1)
- if iGameTurn == year(1397):
- self.expireUHV(Civ.NOVGOROD, 1)
-
- # UHV 3: Control the province of Moscow or have Muscovy as a vassal in 1478
- if iGameTurn == year(1478):
- if self.isPossibleUHV(Civ.NOVGOROD, 2, True):
- if (
- player(Civ.NOVGOROD).getProvinceCurrentState(Province.MOSCOW)
- >= ProvinceStatus.CONQUER
- ):
- self.wonUHV(Civ.NOVGOROD, 2)
- elif civilization(Civ.MOSCOW).is_alive() and civilization(Civ.MOSCOW).is_vassal(
- Civ.NOVGOROD
- ):
- self.wonUHV(Civ.NOVGOROD, 2)
- else:
- self.lostUHV(Civ.NOVGOROD, 2)
-
- def checkKiev(self, iGameTurn):
-
- # UHV 1: Build 2 Orthodox cathedrals and 8 Orthodox monasteries by 1250
- # Controlled in the onBuildingBuilt function
- if iGameTurn == year(1250) + 1:
- self.expireUHV(Civ.KIEV, 0)
-
- # UHV 2: Control 10 provinces out of Kiev, Podolia, Pereyaslavl, Sloboda, Chernigov, Volhynia, Minsk, Polotsk, Smolensk, Moscow, Murom, Rostov, Novgorod and Vologda in 1288
- elif iGameTurn == year(1288):
- if self.isPossibleUHV(Civ.KIEV, 1, True):
- iConq = 0
- for iProv in tKievControl:
- if player(Civ.KIEV).getProvinceCurrentState(iProv) >= ProvinceStatus.CONQUER:
- iConq += 1
- if iConq >= 10:
- self.wonUHV(Civ.KIEV, 1)
- else:
- self.lostUHV(Civ.KIEV, 1)
-
- # UHV 3: Produce 25000 food by 1300
- # The counter should be updated until the deadline for the challenge UHVs, even after UHV completion
- if iGameTurn < year(1300) + 2:
- iFood = player(Civ.KIEV).getUHVCounter(2) + player(Civ.KIEV).calculateTotalYield(
- YieldTypes.YIELD_FOOD
- )
- player(Civ.KIEV).setUHVCounter(2, iFood)
- if self.isPossibleUHV(Civ.KIEV, 2, True):
- if iFood > 25000:
- self.wonUHV(Civ.KIEV, 2)
- if iGameTurn == year(1300):
- self.expireUHV(Civ.KIEV, 2)
-
- def checkHungary(self, iGameTurn):
-
- # UHV 1: Control Austria, Carinthia, Moravia, Silesia, Bohemia, Dalmatia, Bosnia, Banat, Wallachia and Moldova in 1490
- if iGameTurn == year(1490):
- if self.isPossibleUHV(Civ.HUNGARY, 0, True):
- if self.checkProvincesStates(Civ.HUNGARY, tHungaryControl):
- self.wonUHV(Civ.HUNGARY, 0)
- else:
- self.lostUHV(Civ.HUNGARY, 0)
-
- # UHV 2: Allow no Ottoman cities in Europe in 1541
- elif iGameTurn == year(1541):
- if self.isPossibleUHV(Civ.HUNGARY, 1, True):
- bClean = True
- if civilization(Civ.OTTOMAN).is_alive():
- for iProv in tHungaryControlII:
- if player(Civ.OTTOMAN).getProvinceCityCount(iProv) > 0:
- bClean = False
- break
- if bClean:
- self.wonUHV(Civ.HUNGARY, 1)
- else:
- self.lostUHV(Civ.HUNGARY, 1)
-
- # UHV 3: Be the first to adopt Free Religion
- if self.isPossibleUHV(Civ.HUNGARY, 2, True):
- iReligiousCivic = player(Civ.HUNGARY).getCivics(4)
- if iReligiousCivic == Civic.FREE_RELIGION:
- self.wonUHV(Civ.HUNGARY, 2)
- else:
- for iPlayer in civilizations().majors().ids():
- pPlayer = gc.getPlayer(iPlayer)
- if pPlayer.isAlive() and pPlayer.getCivics(4) == Civic.FREE_RELIGION:
- self.lostUHV(Civ.HUNGARY, 2)
-
- def checkSpain(self, iGameTurn):
-
- # UHV 1: Reconquista (make sure Catholicism is the only religion present in every city in the Iberian peninsula in 1492)
- if iGameTurn == year(1492):
- if self.isPossibleUHV(Civ.CASTILE, 0, True):
- bConverted = True
- for iProv in tSpainConvert:
- if not player(Civ.CASTILE).provinceIsConvertReligion(
- iProv, Religion.CATHOLICISM
- ):
- bConverted = False
- break
- if bConverted:
- self.wonUHV(Civ.CASTILE, 0)
- else:
- self.lostUHV(Civ.CASTILE, 0)
-
- # UHV 2: Have more Colonies than any other nation in 1588, while having at least 3
- elif iGameTurn == year(1588):
- if self.isPossibleUHV(Civ.CASTILE, 1, True):
- bMost = True
- iSpainColonies = self.getNumRealColonies(Civ.CASTILE)
- for iPlayer in civilizations().majors().ids():
- if iPlayer != Civ.CASTILE:
- pPlayer = gc.getPlayer(iPlayer)
- if (
- pPlayer.isAlive()
- and self.getNumRealColonies(iPlayer) >= iSpainColonies
- ):
- bMost = False
- if bMost and iSpainColonies >= 3:
- self.wonUHV(Civ.CASTILE, 1)
- else:
- self.lostUHV(Civ.CASTILE, 1)
-
- # UHV 3: Ensure that Catholic nations have more population and more land than any other religion in 1648
- elif iGameTurn == year(1648):
- if self.isPossibleUHV(Civ.CASTILE, 2, True):
- if player(Civ.CASTILE).getStateReligion() != Religion.CATHOLICISM:
- self.lostUHV(Civ.CASTILE, 2)
- else:
- lLand = [0, 0, 0, 0, 0, 0] # Prot, Islam, Cath, Orth, Jew, Pagan
- lPop = [0, 0, 0, 0, 0, 0]
- for iPlayer in civilizations().majors().ids():
- pPlayer = gc.getPlayer(iPlayer)
- iStateReligion = pPlayer.getStateReligion()
- if iStateReligion > -1:
- lLand[iStateReligion] += pPlayer.getTotalLand()
- lPop[iStateReligion] += pPlayer.getTotalPopulation()
- else:
- lLand[5] += pPlayer.getTotalLand()
- lPop[5] += pPlayer.getTotalPopulation()
- # The Barbarian civ counts as Pagan, Independent cities are included separately, based on the religion of the population
- lLand[5] += civilizations().barbarian().unwrap().player.getTotalLand()
- lPop[5] += civilizations().barbarian().unwrap().player.getTotalPopulation()
- for iIndyCiv in [
- Civ.INDEPENDENT,
- Civ.INDEPENDENT_2,
- Civ.INDEPENDENT_3,
- Civ.INDEPENDENT_4,
- ]:
- for pCity in cities().owner(iIndyCiv).entities():
- pIndyCiv = gc.getPlayer(iIndyCiv)
- iAverageCityLand = pIndyCiv.getTotalLand() / pIndyCiv.getNumCities()
- if pCity.getReligionCount() == 0:
- lLand[5] += iAverageCityLand
- lPop[5] += pCity.getPopulation()
- else:
- for iReligion in range(len(Religion)):
- if pCity.isHasReligion(iReligion):
- lLand[iReligion] += (
- iAverageCityLand / pCity.getReligionCount()
- )
- lPop[iReligion] += (
- pCity.getPopulation() / pCity.getReligionCount()
- )
-
- iCathLand = lLand[Religion.CATHOLICISM]
- iCathPop = lPop[Religion.CATHOLICISM]
-
- bWon = True
- for iReligion in range(len(Religion) + 1):
- if iReligion != Religion.CATHOLICISM:
- if lLand[iReligion] >= iCathLand:
- bWon = False
- break
- if lPop[iReligion] >= iCathPop:
- bWon = False
- break
-
- if bWon:
- self.wonUHV(Civ.CASTILE, 2)
- else:
- self.lostUHV(Civ.CASTILE, 2)
-
- def checkScotland(self, iGameTurn):
-
- # UHV 1: Have 10 Forts and 4 Castles by 1296
- if self.isPossibleUHV(Civ.SCOTLAND, 0, True):
- iForts = player(Civ.SCOTLAND).getImprovementCount(Improvement.FORT)
- iCastles = player(Civ.SCOTLAND).countNumBuildings(Building.CASTLE)
- if iForts >= 10 and iCastles >= 4:
- self.wonUHV(Civ.SCOTLAND, 0)
- if iGameTurn == year(1296):
- self.expireUHV(Civ.SCOTLAND, 0)
-
- # UHV 2: Have 1500 Attitude Points with France by 1560 (Attitude Points are added every turn depending on your relations)
- if self.isPossibleUHV(Civ.SCOTLAND, 1, True):
- if civilization(Civ.FRANCE).is_alive():
- # Being at war with France gives a big penalty (and ignores most bonuses!)
- if civilization(Civ.SCOTLAND).at_war(Civ.FRANCE):
- iScore = -10
- else:
- # -1 for Furious 0 for Annoyed 1 for Cautious 2 for Pleased 3 for Friendly
- iScore = player(Civ.FRANCE).AI_getAttitude(Civ.SCOTLAND) - 1
- # Agreements
- if team(Civ.FRANCE).isOpenBorders(Civ.SCOTLAND):
- iScore += 1
- if team(Civ.FRANCE).isDefensivePact(Civ.SCOTLAND):
- iScore += 2
- # Imports/Exports
- iTrades = 0
- iTrades += player(Civ.SCOTLAND).getNumTradeBonusImports(Civ.FRANCE)
- iTrades += player(Civ.FRANCE).getNumTradeBonusImports(Civ.SCOTLAND)
- iScore += iTrades / 2
- # Common Wars
- for iEnemy in civilizations().majors().ids():
- if iEnemy in [Civ.SCOTLAND, Civ.FRANCE]:
- continue
- if team(Civ.FRANCE).isAtWar(iEnemy) and team(Civ.SCOTLAND).isAtWar(iEnemy):
- iScore += 2
- # Different religion from France also gives a penalty, same religion gives a bonus (but only if both have a state religion)
- if (
- civilization(Civ.SCOTLAND).has_a_state_religion()
- and civilization(Civ.FRANCE).has_a_state_religion()
- ):
- if (
- civilization(Civ.SCOTLAND).state_religion()
- != civilization(Civ.FRANCE).state_religion()
- ):
- iScore -= 3
- elif (
- civilization(Civ.SCOTLAND).state_religion()
- == civilization(Civ.FRANCE).state_religion()
- ):
- iScore += 1
- iOldScore = player(Civ.SCOTLAND).getUHVCounter(1)
- iNewScore = iOldScore + iScore
- player(Civ.SCOTLAND).setUHVCounter(1, iNewScore)
- if iNewScore >= 1500:
- self.wonUHV(Civ.SCOTLAND, 1)
- if iGameTurn == year(1560):
- self.expireUHV(Civ.SCOTLAND, 1)
-
- # UHV 3: Control Scotland, The Isles, Ireland, Wales, Brittany and Galicia in 1700
- elif iGameTurn == year(1700):
- if self.isPossibleUHV(Civ.SCOTLAND, 2, True):
- if self.checkProvincesStates(Civ.SCOTLAND, tScotlandControl):
- self.wonUHV(Civ.SCOTLAND, 2)
- else:
- self.lostUHV(Civ.SCOTLAND, 2)
-
- def checkPoland(self, iGameTurn):
-
- # Old UHVs: Don't lose cities until 1772 or conquer Russia until 1772
- # Vassalize Russia, Germany and Austria
-
- # UHV 1: Food production between 1500 and 1520
- if year(1500) <= iGameTurn <= year(1520):
- if self.isPossibleUHV(Civ.POLAND, 0, True):
- iAgriculturePolish = player(Civ.POLAND).calculateTotalYield(YieldTypes.YIELD_FOOD)
- bFood = True
- for iPlayer in civilizations().majors().ids():
- if (
- gc.getPlayer(iPlayer).calculateTotalYield(YieldTypes.YIELD_FOOD)
- > iAgriculturePolish
- ):
- bFood = False
- break
- if bFood:
- self.wonUHV(Civ.POLAND, 0)
- if iGameTurn == year(1520) + 1:
- self.expireUHV(Civ.POLAND, 0)
-
- # UHV 2: Own at least 12 cities in the given provinces in 1569
- elif iGameTurn == year(1569):
- if self.isPossibleUHV(Civ.POLAND, 1, True):
- iNumCities = 0
- for iProv in tPolishControl:
- iNumCities += player(Civ.POLAND).getProvinceCityCount(iProv)
- if iNumCities >= 12:
- self.wonUHV(Civ.POLAND, 1)
- else:
- self.lostUHV(Civ.POLAND, 1)
-
- # UHV 3: Construct 3 Catholic and Orthodox Cathedrals, 2 Protestant Cathedrals, and have at least 2 Jewish Quarters in your cities
- # Controlled in the onBuildingBuilt and onCityAcquired functions
-
- def checkGenoa(self, iGameTurn):
-
- # UHV 1: Control Corsica, Sardinia, Crete, Rhodes, Thrakesion, Cyprus and Crimea in 1400
- if iGameTurn == year(1400):
- if self.isPossibleUHV(Civ.GENOA, 0, True):
- if self.checkProvincesStates(Civ.GENOA, tGenoaControl):
- self.wonUHV(Civ.GENOA, 0)
- else:
- self.lostUHV(Civ.GENOA, 0)
-
- # UHV 2: Have the largest total amount of commerce from foreign Trade Route Exports and Imports in 1566
- # UHV 2: Export is based on your cities' trade routes with foreign cities, import is based on foreign cities' trade routes with your cities
- elif iGameTurn == year(1566):
- if self.isPossibleUHV(Civ.GENOA, 1, True):
- iGenoaTrade = player(Civ.GENOA).calculateTotalImports(
- YieldTypes.YIELD_COMMERCE
- ) + player(Civ.GENOA).calculateTotalExports(YieldTypes.YIELD_COMMERCE)
- bLargest = True
- for iPlayer in civilizations().majors().ids():
- if iPlayer != Civ.GENOA:
- pPlayer = gc.getPlayer(iPlayer)
- if (
- pPlayer.calculateTotalImports(YieldTypes.YIELD_COMMERCE)
- + pPlayer.calculateTotalExports(YieldTypes.YIELD_COMMERCE)
- > iGenoaTrade
- ):
- bLargest = False
- break
- if bLargest:
- self.wonUHV(Civ.GENOA, 1)
- else:
- self.lostUHV(Civ.GENOA, 1)
-
- # UHV 3: Have 8 Banks and own all Bank of St. George cities in 1625
- elif iGameTurn == year(1625):
- if self.isPossibleUHV(Civ.GENOA, 2, True):
- iBanks = 0
- for city in cities().owner(Civ.GENOA).entities():
- if (
- city.getNumRealBuilding(Building.BANK) > 0
- or city.getNumRealBuilding(Building.GENOA_BANK) > 0
- or city.getNumRealBuilding(Building.ENGLISH_ROYAL_EXCHANGE) > 0
- ):
- iBanks += 1
- iCompanyCities = player(Civ.GENOA).countCorporations(Company.ST_GEORGE)
- if iBanks >= 8 and iCompanyCities == companies[Company.ST_GEORGE].limit:
- self.wonUHV(Civ.GENOA, 2)
- else:
- self.lostUHV(Civ.GENOA, 2)
-
- def checkMorocco(self, iGameTurn):
-
- # UHV 1: Control Morocco, Marrakesh, Fez, Tetouan, Oran, Algiers, Ifriqiya, Andalusia, Valencia and the Balearic Islands in 1248
- if iGameTurn == year(1248):
- if self.isPossibleUHV(Civ.MOROCCO, 0, True):
- if self.checkProvincesStates(Civ.MOROCCO, tMoroccoControl):
- self.wonUHV(Civ.MOROCCO, 0)
- else:
- self.lostUHV(Civ.MOROCCO, 0)
-
- # UHV 2: Have 5000 culture in each of three cities in 1465
- elif iGameTurn == year(1465):
- if self.isPossibleUHV(Civ.MOROCCO, 1, True):
- iGoodCities = 0
- for city in cities().owner(Civ.MOROCCO).entities():
- if city.getCulture(Civ.MOROCCO) >= 5000:
- iGoodCities += 1
- if iGoodCities >= 3:
- self.wonUHV(Civ.MOROCCO, 1)
- else:
- self.lostUHV(Civ.MOROCCO, 1)
-
- # UHV 3: Destroy or vassalize Portugal, Spain, and Aragon by 1578
- if year(1164) <= iGameTurn <= year(1578):
- if self.isPossibleUHV(Civ.MOROCCO, 2, True):
- bConq = True
- if (
- (
- civilization(Civ.CASTILE).is_alive()
- and not civilization(Civ.CASTILE).is_vassal(Civ.MOROCCO)
- )
- or (
- civilization(Civ.PORTUGAL).is_alive()
- and not civilization(Civ.PORTUGAL).is_vassal(Civ.MOROCCO)
- )
- or (
- civilization(Civ.ARAGON).is_alive()
- and not civilization(Civ.ARAGON).is_vassal(Civ.MOROCCO)
- )
- ):
- bConq = False
-
- if bConq:
- self.wonUHV(Civ.MOROCCO, 2)
- if iGameTurn == year(1578) + 1:
- self.expireUHV(Civ.MOROCCO, 2)
-
- def checkEngland(self, iGameTurn):
-
- # UHV 1: Control London, Wessex, East Anglia, Mercia, Northumbria, Scotland, Wales, Ireland, Normandy, Picardy, Bretagne, Il-de-France, Aquitania and Orleans in 1452
- if iGameTurn == year(1452):
- if self.isPossibleUHV(Civ.ENGLAND, 0, True):
- if self.checkProvincesStates(Civ.ENGLAND, tEnglandControl):
- self.wonUHV(Civ.ENGLAND, 0)
- else:
- self.lostUHV(Civ.ENGLAND, 0)
-
- # UHV 2: Build 7 Colonies
- # Controlled in the onProjectBuilt function
-
- # UHV 3: Be the first to enter the Industrial age
- # Controlled in the onTechAcquired function
-
- def checkPortugal(self, iGameTurn):
-
- # UHV 1: Settle 3 cities on the Azores, Canaries and Madeira and 2 in Morocco, Tetouan and Oran
- # Controlled in the onCityBuilt function
-
- # UHV 2: Do not lose a city before 1640
- # Controlled in the onCityAcquired function
- if iGameTurn == year(1640):
- if self.isPossibleUHV(Civ.PORTUGAL, 1, True):
- self.wonUHV(Civ.PORTUGAL, 1)
-
- # UHV 3: Build 5 Colonies
- # Controlled in the onProjectBuilt function
-
- def checkAragon(self, iGameTurn):
-
- # UHV 1: Control Catalonia, Valencia, Balears and Sicily in 1282
- if iGameTurn == year(1282):
- if self.isPossibleUHV(Civ.ARAGON, 0, True):
- if self.checkProvincesStates(Civ.ARAGON, tAragonControlI):
- self.wonUHV(Civ.ARAGON, 0)
- else:
- self.lostUHV(Civ.ARAGON, 0)
-
- # UHV 2: Have 12 Consulates of the Sea and 30 Trade Ships in 1444
- # UHV 2: Ships with at least one cargo space count as Trade Ships
- elif iGameTurn == year(1444):
- if self.isPossibleUHV(Civ.ARAGON, 1, True):
- iPorts = player(Civ.ARAGON).countNumBuildings(Building.ARAGON_SEAPORT)
- iCargoShips = getNumberCargoShips(Civ.ARAGON)
- if iPorts >= 12 and iCargoShips >= 30:
- self.wonUHV(Civ.ARAGON, 1)
- else:
- self.lostUHV(Civ.ARAGON, 1)
-
- # UHV 3: Control Catalonia, Valencia, Aragon, Balears, Corsica, Sardinia, Sicily, Calabria, Apulia, Provence and Thessaly in 1474
- elif iGameTurn == year(1474):
- if self.isPossibleUHV(Civ.ARAGON, 2, True):
- if self.checkProvincesStates(Civ.ARAGON, tAragonControlII):
- self.wonUHV(Civ.ARAGON, 2)
- else:
- self.lostUHV(Civ.ARAGON, 2)
-
- def checkPrussia(self, iGameTurn):
-
- # UHV 1: Control Prussia, Suvalkija, Lithuania, Livonia, Estonia, and Pomerania in 1410
- if iGameTurn == year(1410):
- if self.isPossibleUHV(Civ.PRUSSIA, 0, True):
- if self.checkProvincesStates(Civ.PRUSSIA, tPrussiaControlI):
- self.wonUHV(Civ.PRUSSIA, 0)
- else:
- self.lostUHV(Civ.PRUSSIA, 0)
-
- # UHV 2: Conquer two cities from each of Austria, Muscovy, Germany, Sweden, France and Spain between 1650 and 1763, if they are still alive
- # Controlled in the onCityAcquired function
- if iGameTurn == year(1763) + 1:
- self.expireUHV(Civ.PRUSSIA, 1)
-
- # UHV 3: Settle a total of 15 Great People in your capital
- # UHV 3: Great People can be settled in any combination, Great Generals included
- if self.isPossibleUHV(Civ.PRUSSIA, 2, True):
- pCapital = player(Civ.PRUSSIA).getCapitalCity()
- iGPStart = gc.getInfoTypeForString("SPECIALIST_GREAT_PRIEST")
- iGPEnd = gc.getInfoTypeForString("SPECIALIST_GREAT_SPY")
- iGPeople = 0
- for iType in range(iGPStart, iGPEnd + 1):
- iGPeople += pCapital.getFreeSpecialistCount(iType)
- if iGPeople >= 15:
- self.wonUHV(Civ.PRUSSIA, 2)
-
- def checkLithuania(self, iGameTurn):
-
- # UHV 1: Accumulate 2500 Culture points without declaring a state religion before 1386
- # The counter should be updated until the deadline for the challenge UHVs, even after UHV completion
- if iGameTurn < year(1386) + 2:
- iCulture = (
- player(Civ.LITHUANIA).getUHVCounter(0)
- + player(Civ.LITHUANIA).countCultureProduced()
- )
- player(Civ.LITHUANIA).setUHVCounter(0, iCulture)
- if self.isPossibleUHV(Civ.LITHUANIA, 0, True):
- if civilization(Civ.LITHUANIA).has_a_state_religion():
- self.lostUHV(Civ.LITHUANIA, 0)
- else:
- if iCulture >= 2500:
- self.wonUHV(Civ.LITHUANIA, 0)
- if iGameTurn == year(1386):
- self.expireUHV(Civ.LITHUANIA, 0)
-
- # UHV 2: Control the most territory in Europe in 1430
- elif iGameTurn == year(1430):
- if self.isPossibleUHV(Civ.LITHUANIA, 1, True):
- bMost = True
- iCount = self.getTerritoryPercentEurope(Civ.LITHUANIA)
- for iOtherPlayer in civilizations().majors().ids():
- if not gc.getPlayer(iOtherPlayer).isAlive() or iOtherPlayer == Civ.LITHUANIA:
- continue
- iOtherCount = self.getTerritoryPercentEurope(iOtherPlayer)
- if iOtherCount >= iCount:
- bMost = False
- break
- if bMost:
- self.wonUHV(Civ.LITHUANIA, 1)
- else:
- self.lostUHV(Civ.LITHUANIA, 1)
-
- # UHV 3: Destroy or Vassalize Muscovy, Novgorod and Prussia by 1795
- if year(1380) <= iGameTurn <= year(1795):
- if self.isPossibleUHV(Civ.LITHUANIA, 2, True):
- bConq = True
- if (
- (
- civilization(Civ.MOSCOW).is_alive()
- and not civilization(Civ.MOSCOW).is_vassal(Civ.LITHUANIA)
- )
- or (
- civilization(Civ.NOVGOROD).is_alive()
- and not civilization(Civ.NOVGOROD).is_vassal(Civ.LITHUANIA)
- )
- or (
- civilization(Civ.PRUSSIA).is_alive()
- and not civilization(Civ.PRUSSIA).is_vassal(Civ.LITHUANIA)
- )
- ):
- bConq = False
-
- if bConq:
- self.wonUHV(Civ.LITHUANIA, 2)
- if iGameTurn == year(1795) + 1:
- self.expireUHV(Civ.LITHUANIA, 2)
-
- def checkAustria(self, iGameTurn):
-
- # UHV 1: Control all of medieval Austria, Hungary and Bohemia in 1617
- if iGameTurn == year(1617):
- if self.isPossibleUHV(Civ.AUSTRIA, 0, True):
- if self.checkProvincesStates(Civ.AUSTRIA, tAustriaControl):
- self.wonUHV(Civ.AUSTRIA, 0)
- else:
- self.lostUHV(Civ.AUSTRIA, 0)
-
- # UHV 2: Have 3 vassals in 1700
- elif iGameTurn == year(1700):
- if self.isPossibleUHV(Civ.AUSTRIA, 1, True):
- iCount = 0
- for iPlayer in civilizations().majors().ids():
- if iPlayer == Civ.AUSTRIA:
- continue
- pPlayer = gc.getPlayer(iPlayer)
- if pPlayer.isAlive():
- if gc.getTeam(pPlayer.getTeam()).isVassal(team(Civ.AUSTRIA).getID()):
- iCount += 1
- if iCount >= 3:
- self.wonUHV(Civ.AUSTRIA, 1)
- else:
- self.lostUHV(Civ.AUSTRIA, 1)
-
- # UHV 3: Have the highest score in 1780
- elif iGameTurn == year(1780):
- if self.isPossibleUHV(Civ.AUSTRIA, 2, True):
- if gc.getGame().getTeamRank(Civ.AUSTRIA) == 0:
- self.wonUHV(Civ.AUSTRIA, 2)
- else:
- self.lostUHV(Civ.AUSTRIA, 2)
-
- def checkTurkey(self, iGameTurn):
-
- # UHV 1: Control Constantinople, the Balkans, Anatolia, the Levant and Egypt in 1517
- if iGameTurn == year(1517):
- if self.isPossibleUHV(Civ.OTTOMAN, 0, True):
- if self.checkProvincesStates(Civ.OTTOMAN, tOttomanControlI):
- self.wonUHV(Civ.OTTOMAN, 0)
- else:
- self.lostUHV(Civ.OTTOMAN, 0)
-
- # UHV 2: Construct the Topkapi Palace, the Blue Mosque, the Selimiye Mosque and the Tomb of Al-Walid by 1616
- # Controlled in the onBuildingBuilt function
- elif iGameTurn == year(1616):
- self.expireUHV(Civ.OTTOMAN, 1)
-
- # UHV 3: Conquer Austria, Pannonia and Lesser Poland by 1683
- if self.isPossibleUHV(Civ.OTTOMAN, 2, True):
- if self.checkProvincesStates(Civ.OTTOMAN, tOttomanControlII):
- self.wonUHV(Civ.OTTOMAN, 2)
- if iGameTurn == year(1683):
- self.expireUHV(Civ.OTTOMAN, 2)
-
- def checkMoscow(self, iGameTurn):
-
- # UHV 1: Free Eastern Europe from the Mongols (Make sure there are no Mongol (or any other Barbarian) cities in Russia and Ukraine in 1482)
- if iGameTurn == year(1482):
- if self.isPossibleUHV(Civ.MOSCOW, 0, True):
- bClean = True
- for iProv in tMoscowControl:
- if civilizations().barbarian().unwrap().player.getProvinceCityCount(iProv) > 0:
- bClean = False
- break
- if bClean:
- self.wonUHV(Civ.MOSCOW, 0)
- else:
- self.lostUHV(Civ.MOSCOW, 0)
-
- # UHV 2: Control at least 25% of Europe
- if self.isPossibleUHV(Civ.MOSCOW, 1, True):
- totalLand = gc.getMap().getLandPlots()
- RussianLand = player(Civ.MOSCOW).getTotalLand()
- if totalLand > 0:
- landPercent = (RussianLand * 100.0) / totalLand
- else:
- landPercent = 0.0
- if landPercent >= 25:
- self.wonUHV(Civ.MOSCOW, 1)
-
- # UHV 3: Get into warm waters (Conquer Constantinople or control an Atlantic Access resource)
- if self.isPossibleUHV(Civ.MOSCOW, 2, True):
- if player(Civ.MOSCOW).countCultBorderBonuses(Bonus.ACCESS) > 0:
- self.wonUHV(Civ.MOSCOW, 2)
- elif (
- gc.getMap().plot(*CIV_CAPITAL_LOCATIONS[Civ.BYZANTIUM]).getPlotCity().getOwner()
- == Civ.MOSCOW
- ):
- self.wonUHV(Civ.MOSCOW, 2)
-
- def checkSweden(self, iGameTurn):
-
- # Old UHVs: Conquer Gotaland, Svealand, Norrland, Skaneland, Gotland and Osterland in 1600
- # Don't lose any cities to Poland, Lithuania or Russia before 1700
- # Have 15 cities in Saxony, Brandenburg, Holstein, Pomerania, Prussia, Greater Poland, Masovia, Suvalkija, Lithuania, Livonia, Estonia, Smolensk, Polotsk, Minsk, Murom, Chernigov, Moscow, Novgorod and Rostov in 1750
-
- # UHV 1: Have six cities in Norrland, Osterland and Karelia in 1323
- if iGameTurn == year(1323):
- if self.isPossibleUHV(Civ.SWEDEN, 0, True):
- iNumCities = 0
- for iProv in tSwedenControl:
- iNumCities += player(Civ.SWEDEN).getProvinceCityCount(iProv)
- if iNumCities >= 6:
- self.wonUHV(Civ.SWEDEN, 0)
- else:
- self.lostUHV(Civ.SWEDEN, 0)
-
- # UHV 2: Raze 5 Catholic cities while being Protestant by 1660
- # Controlled in the onCityRazed function
- elif iGameTurn == year(1660):
- self.expireUHV(Civ.SWEDEN, 1)
-
- # UHV 3: Control every coastal city on the Baltic Sea in 1750
- elif iGameTurn == year(1750):
- if self.isPossibleUHV(Civ.SWEDEN, 2, True):
- if up.getNumForeignCitiesOnBaltic(Civ.SWEDEN, True) > 0:
- self.lostUHV(Civ.SWEDEN, 2)
- else:
- self.wonUHV(Civ.SWEDEN, 2)
-
- def checkDutch(self, iGameTurn):
-
- # UHV 1: Settle 5 Great Merchants in Amsterdam by 1750
- if self.isPossibleUHV(Civ.DUTCH, 0, True):
- pPlot = gc.getMap().plot(*CIV_CAPITAL_LOCATIONS[Civ.DUTCH])
- if pPlot.isCity():
- city = pPlot.getPlotCity()
- if (
- city.getFreeSpecialistCount(Specialist.GREAT_MERCHANT) >= 5
- and city.getOwner() == Civ.DUTCH
- ):
- self.wonUHV(Civ.DUTCH, 0)
- if iGameTurn == year(1750):
- self.expireUHV(Civ.DUTCH, 0)
-
- # UHV 2: Build 3 Colonies and complete both Trading Companies
- # Controlled in the onProjectBuilt function
-
- # UHV 3: Become the richest country in Europe
- if self.isPossibleUHV(Civ.DUTCH, 2, True):
- iGold = player(Civ.DUTCH).getGold()
- bMost = True
- for iCiv in civilizations().majors().ids():
- if iCiv == Civ.DUTCH:
- continue
- pPlayer = gc.getPlayer(iCiv)
- if pPlayer.isAlive():
- if pPlayer.getGold() > iGold:
- bMost = False
- break
- if bMost:
- self.wonUHV(Civ.DUTCH, 2)
-
- def checkProvincesStates(self, iPlayer, tProvinces):
- pPlayer = gc.getPlayer(iPlayer)
- for iProv in tProvinces:
- if pPlayer.getProvinceCurrentState(iProv) < ProvinceStatus.CONQUER:
- return False
- return True
-
- def wonUHV(self, iCiv, iUHV):
- pCiv = gc.getPlayer(iCiv)
- pCiv.setUHV(iUHV, 1)
- pCiv.changeStabilityBase(StabilityCategory.EXPANSION, 3)
- if human() == iCiv:
- if iUHV == 0:
- sText = "first"
- elif iUHV == 1:
- sText = "second"
- elif iUHV == 2:
- sText = "third"
- show(text("TXT_KEY_VICTORY_UHV_GOAL_WON", sText))
-
- def lostUHV(self, iCiv, iUHV):
- pCiv = gc.getPlayer(iCiv)
- pCiv.setUHV(iUHV, 0)
- if human() == iCiv:
- if iUHV == 0:
- sText = "first"
- elif iUHV == 1:
- sText = "second"
- elif iUHV == 2:
- sText = "third"
- show(text("TXT_KEY_VICTORY_UHV_GOAL_LOST", sText))
-
- def setAllUHVFailed(self, iCiv):
- pPlayer = gc.getPlayer(iCiv)
- for i in range(3):
- pPlayer.setUHV(i, 0)
-
- def switchUHV(self, iNewCiv, iOldCiv):
- pPlayer = gc.getPlayer(iNewCiv)
- for i in range(3):
- pPlayer.setUHV(i, -1)
- if self.isIgnoreAI():
- self.setAllUHVFailed(iOldCiv)
-
- def isPossibleUHV(self, iCiv, iUHV, bAlreadyAIChecked):
- pCiv = gc.getPlayer(iCiv)
- if pCiv.getUHV(iUHV) != -1:
- return False
- if not pCiv.isAlive():
- return False
-
- if not bAlreadyAIChecked:
- if (
- iCiv != human() and self.isIgnoreAI()
- ): # Skip calculations if no AI UHV option is enabled
- return False
-
- return True
-
- def expireUHV(self, iCiv, iUHV):
- # UHVs have to expire on the given deadline, even if the civ is not alive currently (would be an issue on respawns otherwise)
- # if self.isPossibleUHV(iCiv, iUHV, True):
- pCiv = gc.getPlayer(iCiv)
- if pCiv.getUHV(iUHV) == -1:
- self.lostUHV(iCiv, iUHV)
-
- def set1200UHVDone(self, iCiv):
- if iCiv == Civ.BYZANTIUM:
- player(Civ.BYZANTIUM).setUHV(0, 1)
- elif iCiv == Civ.FRANCE:
- player(Civ.FRANCE).setUHV(0, 1)
- elif iCiv == Civ.ARABIA:
- player(Civ.ARABIA).setUHV(0, 1)
- elif iCiv == Civ.BULGARIA:
- player(Civ.BULGARIA).setUHV(0, 1)
- elif iCiv == Civ.VENECIA: # Venice gets conquerors near Constantinople for 2nd UHV
- player(Civ.VENECIA).setUHV(0, 1)
- elif iCiv == Civ.GERMANY:
- player(Civ.GERMANY).setUHV(0, 1)
- elif iCiv == Civ.NORWAY:
- player(Civ.NORWAY).setUHV(0, 1)
- elif iCiv == Civ.DENMARK:
- player(Civ.DENMARK).setUHV(0, 1)
- elif iCiv == Civ.SCOTLAND:
- player(Civ.SCOTLAND).setUHVCounter(1, 100)
diff --git a/Assets/Python/components/Wonders.py b/Assets/Python/components/Wonders.py
deleted file mode 100644
index 4677971c9..000000000
--- a/Assets/Python/components/Wonders.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from Core import city
-from CoreTypes import Specialist
-from PyUtils import rand
-
-
-def leaning_tower_effect():
- iGP = rand(7)
- pFlorentia = city(54, 32)
- iSpecialist = Specialist.GREAT_PROPHET + iGP
- pFlorentia.setFreeSpecialistCount(iSpecialist, 1)
diff --git a/Assets/Python/data/Consts.py b/Assets/Python/data/Consts.py
index 5182f8cab..6a36dcb72 100644
--- a/Assets/Python/data/Consts.py
+++ b/Assets/Python/data/Consts.py
@@ -8,6 +8,9 @@
INDEPENDENT_CIVS = [Civ.INDEPENDENT, Civ.INDEPENDENT_2, Civ.INDEPENDENT_3, Civ.INDEPENDENT_4]
MINOR_CIVS = INDEPENDENT_CIVS + [Civ.BARBARIAN]
+# Absinthe: Turn Randomization constants
+iLighthouseEarthQuake = 0
+iByzantiumVikingAttack = 1
# Used for messages
class MessageData(object):
diff --git a/Assets/Python/screens/BugFinanceAdvisor.py b/Assets/Python/screens/BugFinanceAdvisor.py
index a54d3e51d..98d0ba89a 100644
--- a/Assets/Python/screens/BugFinanceAdvisor.py
+++ b/Assets/Python/screens/BugFinanceAdvisor.py
@@ -10,7 +10,7 @@
import BugDll
import BugUtil
import PlayerUtil
-from Stability import Stability
+import Stability
import TradeUtil
# globals
@@ -18,8 +18,6 @@
ArtFileMgr = CyArtFileMgr()
localText = CyTranslator()
-stab = Stability()
-
class BugFinanceAdvisor:
def __init__(self):
@@ -170,7 +168,7 @@ def interfaceScreen(self):
)
# Absinthe: update all stability values for the active player
- stab.refreshBaseStability(self.iActiveLeader)
+ Stability.refreshBaseStability(self.iActiveLeader)
# draw the contents
self.drawContents()
diff --git a/Assets/Python/screens/CvCivicsScreen.py b/Assets/Python/screens/CvCivicsScreen.py
index b31ebee2a..571914e51 100644
--- a/Assets/Python/screens/CvCivicsScreen.py
+++ b/Assets/Python/screens/CvCivicsScreen.py
@@ -5,8 +5,6 @@
import CvScreensInterface
import Stability
-sta = Stability.Stability()
-
# Globals
gc = CyGlobalContext()
localText = CyTranslator()
@@ -532,7 +530,7 @@ def colorCivicTexts(self, iHoverCivic, bHoverOn):
sName = "CivicName" + str(iCivic)
sText = gc.getCivicInfo(iCivic).getDescription()
- iCombovalue = sta.getCivicCombinationStability(iHoverCivic, iCivic)
+ iCombovalue = Stability.getCivicCombinationStability(iHoverCivic, iCivic)
bGood = iCombovalue > 0
bBad = iCombovalue < 0
diff --git a/Assets/Python/screens/CvFinanceAdvisor.py b/Assets/Python/screens/CvFinanceAdvisor.py
index 1f662eb60..775a57215 100644
--- a/Assets/Python/screens/CvFinanceAdvisor.py
+++ b/Assets/Python/screens/CvFinanceAdvisor.py
@@ -5,16 +5,8 @@
from CoreTypes import SpecialParameter, StabilityCategory
import CvUtil
import CvScreenEnums
-
-
from RFCUtils import * # getArrow comes from RFC classic
-import Stability # Absinthe
-
-# Mercenary Upkeep
-# import MercenaryUtils
-# objMercenaryUtils = MercenaryUtils.MercenaryUtils()
-
-stab = Stability.Stability() # Absinthe
+import Stability
# globals
gc = CyGlobalContext()
@@ -172,7 +164,7 @@ def interfaceScreen(self):
# Absinthe: update all stability values for the active player
# iGameTurn = turn()
- stab.refreshBaseStability(self.iActiveLeader)
+ Stability.refreshBaseStability(self.iActiveLeader)
# draw the contents
self.drawContents()
diff --git a/Assets/Python/screens/CvMercenaryManager.py b/Assets/Python/screens/CvMercenaryManager.py
index fb231f1e8..e86c5ba7e 100644
--- a/Assets/Python/screens/CvMercenaryManager.py
+++ b/Assets/Python/screens/CvMercenaryManager.py
@@ -31,7 +31,6 @@
# objMercenaryUtils = MercenaryUtils.MercenaryUtils()
# 3Miro: this class will provide the needed interface for the RFCE Merc mechanics
-GMU = Mercenaries.GlobalMercenaryUtils()
lMercList = Mercenaries.lMercList
# Change this to True if hiring mercenaries should only be allowed if one or more of
@@ -130,7 +129,7 @@ def interfaceScreen(self):
def populateAvailableMercenariesPanel(self, screen):
## 3Miro: draw the available merc info
# read in the available mercs
- lAvailableMercs = GMU.getMercGlobalPool()
+ lAvailableMercs = Mercenaries.getMercGlobalPool()
# Get the ID for the current active player
iPlayer = gc.getGame().getActivePlayer()
@@ -140,7 +139,7 @@ def populateAvailableMercenariesPanel(self, screen):
iGold = pPlayer.getGold()
# get a list of the provinces controlled by the player
- lProvList = GMU.getOwnedProvinces(iPlayer)
+ lProvList = Mercenaries.getOwnedProvinces(iPlayer)
# lProvList = Set( lProvList ) # set as in set-theory
mercenaryCount = 0
@@ -200,8 +199,8 @@ def populateAvailableMercenariesPanel(self, screen):
PanelStyles.PANEL_STYLE_EMPTY,
)
- iHireCost = GMU.getModifiedCostPerPlayer(lMerc[2], iPlayer)
- iUpkeepCost = GMU.getModifiedCostPerPlayer(lMerc[3], iPlayer)
+ iHireCost = Mercenaries.getModifiedCostPerPlayer(lMerc[2], iPlayer)
+ iUpkeepCost = Mercenaries.getModifiedCostPerPlayer(lMerc[3], iPlayer)
strHCost = u"%d%c" % (
iHireCost,
@@ -296,7 +295,7 @@ def populateAvailableMercenariesPanel(self, screen):
def clearAvailableMercs(self, screen):
- lGlobalMercPool = GMU.getMercGlobalPool()
+ lGlobalMercPool = Mercenaries.getMercGlobalPool()
for iI in range(len(lGlobalMercPool)):
screen.deleteWidget(
@@ -1089,13 +1088,13 @@ def hireMercenary(self, screen, iMerc):
szUniqueInternalName = "HiredMercID" + self.numToStr(iMerc)
# screen.deleteWidget(szUniqueInternalName)
- lGlobalMercPool = GMU.getMercGlobalPool()
+ lGlobalMercPool = Mercenaries.getMercGlobalPool()
for iI in range(len(lGlobalMercPool)):
if lGlobalMercPool[iI][0] == iMerc:
lMerc = lGlobalMercPool[iI]
- GMU.hireMerc(lMerc, iPlayer)
+ Mercenaries.hireMerc(lMerc, iPlayer)
# Draw the gold information for the screen
self.drawGoldInformation(screen)
@@ -1118,7 +1117,7 @@ def fireMercenary(self, screen, iMerc):
for pUnit in unitList:
if pUnit.getMercID() == iMerc:
- GMU.fireMerc(pUnit)
+ Mercenaries.fireMerc(pUnit)
screen.deleteWidget(
"HiredMercID" + self.numToStr(iMerc)
) # it is OK to delete non-existent widgets
@@ -1247,7 +1246,7 @@ def handleInput(self, inputClass):
iMerc = self.strToNum(iMerc)
iPlayer = gc.getGame().getActivePlayer()
- lGlobalMercPool = GMU.getMercGlobalPool()
+ lGlobalMercPool = Mercenaries.getMercGlobalPool()
for iI in range(len(lGlobalMercPool)):
if lGlobalMercPool[iI][0] == iMerc:
@@ -1259,8 +1258,8 @@ def handleInput(self, inputClass):
self.calculateScreenWidgetData(screen)
# Absinthe: we need to make sure this is applied only once
- iModifiedCost = GMU.getModifiedCostPerPlayer(lMerc[2], iPlayer)
- iModifiedUpkeep = GMU.getModifiedCostPerPlayer(lMerc[3], iPlayer)
+ iModifiedCost = Mercenaries.getModifiedCostPerPlayer(lMerc[2], iPlayer)
+ iModifiedUpkeep = Mercenaries.getModifiedCostPerPlayer(lMerc[3], iPlayer)
lModifiedMerc = [lMerc[0], lMerc[1], iModifiedCost, iModifiedUpkeep, lMerc[4]]
diff --git a/Assets/Python/screens/CvVictoryScreen.py b/Assets/Python/screens/CvVictoryScreen.py
index c75623643..c64175865 100644
--- a/Assets/Python/screens/CvVictoryScreen.py
+++ b/Assets/Python/screens/CvVictoryScreen.py
@@ -30,12 +30,11 @@
from LocationsData import CITIES, COLONY_LOCATIONS
import PyHelpers
from RFCUtils import getNumberCargoShips, getMostAdvancedCiv
-import Victory as vic
+import Victory
import UniquePowers
PyPlayer = PyHelpers.PyPlayer
-up = UniquePowers.UniquePowers()
gc = CyGlobalContext()
ArtFileMgr = CyArtFileMgr()
@@ -2440,7 +2439,7 @@ def getByzantiumText(self):
pPlayer = gc.getPlayer(iPlayer)
sText1, sText2, sText3 = self.getEmptyTexts()
# UHV1
- tProvsToCheck = vic.tByzantiumControl
+ tProvsToCheck = Victory.tByzantiumControl
iNumCities = 0
for iProv in tProvsToCheck:
iNumCities += pPlayer.getProvinceCityCount(iProv)
@@ -2450,7 +2449,7 @@ def getByzantiumText(self):
+ self.determineColor(iNumCities >= 6, str(iNumCities))
)
# UHV2
- sText2 += self.getProvinceString(vic.tByzantiumControlII)
+ sText2 += self.getProvinceString(Victory.tByzantiumControlII)
# UHV3
tConstantinople = civilization(iPlayer).location.capital
pConstantinople = gc.getMap().plot(tConstantinople[0], tConstantinople[1]).getPlotCity()
@@ -2512,7 +2511,7 @@ def getFrankiaText(self):
pPlayer = gc.getPlayer(iPlayer)
sText1, sText2, sText3 = self.getEmptyTexts()
# UHV1
- sText1 += self.getProvinceString(vic.tFrankControl)
+ sText1 += self.getProvinceString(Victory.tFrankControl)
# UHV2
tPlot = CITIES[City.JERUSALEM]
sText2 += self.checkCity(tPlot, iPlayer, text("TXT_KEY_UHV_JERUSALEM"), True)
@@ -2526,7 +2525,7 @@ def getArabiaText(self):
pPlayer = gc.getPlayer(iPlayer)
sText1, sText2, sText3 = self.getEmptyTexts()
# UHV1
- sText1 += self.getProvinceString(vic.tArabiaControlI)
+ sText1 += self.getProvinceString(Victory.tArabiaControlI)
# sText1 += self.getMultiProvinceString([(vic.tArabiaControlI, year(955)), (vic.tArabiaControlII, year(1291))])
# UHV2
iMostAdvancedCiv = getMostAdvancedCiv()
@@ -2544,7 +2543,7 @@ def getArabiaText(self):
+ ": "
+ u"%s" % (text("TXT_KEY_UHV_NO_MOST_ADVANCED_CIV"))
)
- sText2 += "\n" + self.getProvinceString(vic.tArabiaControlII)
+ sText2 += "\n" + self.getProvinceString(Victory.tArabiaControlII)
# UHV3
iPerc = gc.getGame().calculateReligionPercent(Religion.ISLAM)
sPerc = str(iPerc) + "%"
@@ -2557,7 +2556,7 @@ def getBulgariaText(self):
pPlayer = gc.getPlayer(iPlayer)
sText1, sText2, sText3 = self.getEmptyTexts()
# UHV1
- sText1 += self.getProvinceString(vic.tBulgariaControl)
+ sText1 += self.getProvinceString(Victory.tBulgariaControl)
# UHV2
iFaith = pPlayer.getFaith()
sText2 += (
@@ -2611,9 +2610,9 @@ def getCordobaText(self):
else:
sText1 += self.checkCity(tCordoba, iPlayer, sCordobaName)
# UHV2
- sText2 += self.getWonderString(vic.tCordobaWonders)
+ sText2 += self.getWonderString(Victory.tCordobaWonders)
# UHV3
- sText3 += self.getReligionProvinceString(vic.tCordobaIslamize, Religion.ISLAM, 1)
+ sText3 += self.getReligionProvinceString(Victory.tCordobaIslamize, Religion.ISLAM, 1)
lHelpTexts = [sText1, sText2, sText3]
return lHelpTexts
@@ -2622,13 +2621,13 @@ def getVeneciaText(self):
pPlayer = gc.getPlayer(iPlayer)
sText1, sText2, sText3 = self.getEmptyTexts()
# UHV1
- sText1 += self.getProvinceString(vic.tVenetianControl)
+ sText1 += self.getProvinceString(Victory.tVenetianControl)
# UHV2
tConstantinople = civilization(Civ.BYZANTIUM).location.capital
sText2 += self.checkCity(
tConstantinople, iPlayer, text("TXT_KEY_CITY_NAME_CONSTANTINOPLE"), True
)
- sText2 += "\n" + self.getProvinceString(vic.tVenetianControlII)
+ sText2 += "\n" + self.getProvinceString(Victory.tVenetianControlII)
# UHV3
sText3 = (
"\n"
@@ -2654,9 +2653,9 @@ def getBurgundyText(self):
+ self.determineColor(iCulture >= 12000, str(iCulture))
)
# UHV2
- sText2 += self.getProvinceString(vic.tBurgundyControl)
+ sText2 += self.getProvinceString(Victory.tBurgundyControl)
# UHV3
- sText3 += self.checkScores(vic.tBurgundyOutrank)
+ sText3 += self.checkScores(Victory.tBurgundyOutrank)
lHelpTexts = [sText1, sText2, sText3]
return lHelpTexts
@@ -2665,7 +2664,7 @@ def getGermanyText(self):
pPlayer = gc.getPlayer(iPlayer)
sText1, sText2, sText3 = self.getEmptyTexts()
# UHV1
- sText1 += self.getProvinceString(vic.tGermanyControl)
+ sText1 += self.getProvinceString(Victory.tGermanyControl)
# UHV2
iGoal = pPlayer.getUHV(1)
sTextGood = text("TXT_KEY_UHV_NOT_FOUND_YET")
@@ -2674,7 +2673,7 @@ def getGermanyText(self):
gc.getReligionInfo(Religion.PROTESTANTISM).getDescription() + " " + sTextGood,
)
# UHV3
- sText3 += self.getProvinceString(vic.tGermanyControlII)
+ sText3 += self.getProvinceString(Victory.tGermanyControlII)
lHelpTexts = [sText1, sText2, sText3]
return lHelpTexts
@@ -2683,7 +2682,7 @@ def getNovgorodText(self):
pPlayer = gc.getPlayer(iPlayer)
sText1, sText2, sText3 = self.getEmptyTexts()
# UHV1
- sText1 += self.getProvinceString(vic.tNovgorodControl)
+ sText1 += self.getProvinceString(Victory.tNovgorodControl)
# UHV2
sText2 = (
"\n"
@@ -2724,9 +2723,9 @@ def getNorwayText(self):
)
)
# UHV2
- sText2 += self.getProvinceString(vic.tNorwayControl)
+ sText2 += self.getProvinceString(Victory.tNorwayControl)
# UHV3
- sText3 += self.checkScores(vic.tNorwayOutrank)
+ sText3 += self.checkScores(Victory.tNorwayOutrank)
lHelpTexts = [sText1, sText2, sText3]
return lHelpTexts
@@ -2742,7 +2741,7 @@ def getKievText(self):
sText1 += sKievCath + self.determineColor(iKievCath >= 2, str(iKievCath))
sText1 += "\n" + sKievMona + self.determineColor(iKievMona >= 8, str(iKievMona))
# UHV2
- sText2 += self.getProvinceString(vic.tKievControl, (True, 10))
+ sText2 += self.getProvinceString(Victory.tKievControl, (True, 10))
# UHV3
iFood = pPlayer.getUHVCounter(2)
sText3 += self.getCounterString(iFood, 25000)
@@ -2754,10 +2753,12 @@ def getHungaryText(self):
pPlayer = gc.getPlayer(iPlayer)
sText1, sText2, sText3 = self.getEmptyTexts()
# UHV1
- sText1 += self.getProvinceString(vic.tHungaryControl)
+ sText1 += self.getProvinceString(Victory.tHungaryControl)
# UHV2
sEnemyString = "The Ottomans"
- sText2 += self.getNotCivProvinceString(Civ.OTTOMAN, sEnemyString, vic.tHungaryControlII)
+ sText2 += self.getNotCivProvinceString(
+ Civ.OTTOMAN, sEnemyString, Victory.tHungaryControlII
+ )
# UHV3
iGoal = pPlayer.getUHV(2)
sText3 += self.determineColor(iGoal != 0, text("TXT_KEY_UHV_NO_ADOPTION_YET"))
@@ -2769,16 +2770,16 @@ def getSpainText(self):
pPlayer = gc.getPlayer(iPlayer)
sText1, sText2, sText3 = self.getEmptyTexts()
# UHV1
- sText1 += self.getReligionProvinceString(vic.tSpainConvert, Religion.CATHOLICISM, 2)
+ sText1 += self.getReligionProvinceString(Victory.tSpainConvert, Religion.CATHOLICISM, 2)
# UHV2
- iSpainColonies = vic.Victory().getNumRealColonies(iPlayer)
+ iSpainColonies = Victory.getNumRealColonies(iPlayer)
iOtherColonies = 0
iColonyPlayer = -1
for iCiv in civilizations().majors().ids():
if iCiv == iPlayer:
continue
if gc.getPlayer(iCiv).isAlive():
- iTempNumColonies = vic.Victory().getNumRealColonies(iCiv)
+ iTempNumColonies = Victory.getNumRealColonies(iCiv)
if iTempNumColonies > iOtherColonies:
iOtherColonies = iTempNumColonies
iColonyPlayer = iCiv
@@ -2816,7 +2817,7 @@ def getSpainText(self):
Civ.INDEPENDENT_3,
Civ.INDEPENDENT_4,
]:
- for pCity in cities().owner(iIndyCiv).entities():
+ for pCity in cities.owner(iIndyCiv).entities():
pIndyCiv = gc.getPlayer(iIndyCiv)
iAverageCityLand = pIndyCiv.getTotalLand() / pIndyCiv.getNumCities()
if pCity.getReligionCount() == 0:
@@ -2863,9 +2864,9 @@ def getDenmarkText(self):
pPlayer = gc.getPlayer(iPlayer)
sText1, sText2, sText3 = self.getEmptyTexts()
# UHV1
- sText1 += self.getProvinceString(vic.tDenmarkControlI)
+ sText1 += self.getProvinceString(Victory.tDenmarkControlI)
# UHV2
- sText2 += self.getProvinceString(vic.tDenmarkControlIII)
+ sText2 += self.getProvinceString(Victory.tDenmarkControlIII)
# UHV3
sText3 += self.getNumColoniesString(3, True)
lHelpTexts = [sText1, sText2, sText3]
@@ -2897,7 +2898,7 @@ def getScotlandText(self):
iScore = pPlayer.getUHVCounter(1)
sText2 += self.getCounterString(iScore, 1500)
# UHV3
- sText3 += self.getProvinceString(vic.tScotlandControl)
+ sText3 += self.getProvinceString(Victory.tScotlandControl)
lHelpTexts = [sText1, sText2, sText3]
return lHelpTexts
@@ -2924,7 +2925,7 @@ def getPolandText(self):
sUnit = "%s" % (u"%c" % (gc.getYieldInfo(YieldTypes.YIELD_FOOD).getChar()))
sText1 += self.getCompetition(iPolandFood, iOtherFood, iFoodPlayer, sText, sUnit)
# UHV2
- tProvsToCheck = vic.tPolishControl
+ tProvsToCheck = Victory.tPolishControl
iNumCities = 0
for iProv in tProvsToCheck:
iNumCities += pPlayer.getProvinceCityCount(iProv)
@@ -2960,7 +2961,7 @@ def getGenoaText(self):
pPlayer = gc.getPlayer(iPlayer)
sText1, sText2, sText3 = self.getEmptyTexts()
# UHV1
- sText1 += self.getProvinceString(vic.tGenoaControl)
+ sText1 += self.getProvinceString(Victory.tGenoaControl)
# UHV2
sText2 = (
"\n"
@@ -2993,7 +2994,7 @@ def getGenoaText(self):
sText2 += self.getCompetition(iGenoaTrade, iOtherTrade, iBiggestTrader, sTextTmp, sUnit)
# UHV3
iBankCount = 0
- for city in cities().owner(iPlayer).entities():
+ for city in cities.owner(iPlayer).entities():
if (
city.getNumRealBuilding(Building.BANK) > 0
or city.getNumRealBuilding(Building.GENOA_BANK) > 0
@@ -3022,7 +3023,7 @@ def getMoroccoText(self):
pPlayer = gc.getPlayer(iPlayer)
sText1, sText2, sText3 = self.getEmptyTexts()
# UHV1
- sText1 += self.getProvinceString(vic.tMoroccoControl)
+ sText1 += self.getProvinceString(Victory.tMoroccoControl)
# UHV2
victory = gc.getVictoryInfo(4) # Cultural victory
ourBestCities = self.getListCultureCities(self.iActivePlayer)[
@@ -3047,7 +3048,7 @@ def getEnglandText(self):
pPlayer = gc.getPlayer(iPlayer)
sText1, sText2, sText3 = self.getEmptyTexts()
# UHV1
- sText1 += self.getProvinceString(vic.tEnglandControl)
+ sText1 += self.getProvinceString(Victory.tEnglandControl)
# UHV2
sText2 += self.getNumColoniesString(7)
# UHV3
@@ -3095,7 +3096,7 @@ def getAragonText(self):
pPlayer = gc.getPlayer(iPlayer)
sText1, sText2, sText3 = self.getEmptyTexts()
# UHV1
- sText1 += self.getProvinceString(vic.tAragonControlI)
+ sText1 += self.getProvinceString(Victory.tAragonControlI)
# UHV2
sText2 = (
"\n"
@@ -3120,7 +3121,7 @@ def getAragonText(self):
+ text("TXT_KEY_UHV_TRADE_SHIPS")
)
# UHV3
- sText3 += self.getProvinceString(vic.tAragonControlII)
+ sText3 += self.getProvinceString(Victory.tAragonControlII)
lHelpTexts = [sText1, sText2, sText3]
return lHelpTexts
@@ -3130,14 +3131,14 @@ def getSwedenText(self):
sText1, sText2, sText3 = self.getEmptyTexts()
# UHV1
iCounter = 0
- for iProv in vic.tSwedenControl:
+ for iProv in Victory.tSwedenControl:
iCounter += pPlayer.getProvinceCityCount(iProv)
sText1 += self.getCounterString(iCounter, 6)
# UHV2
iCounter = pPlayer.getUHVCounter(1)
sText2 += self.getCounterString(iCounter, 5)
# UHV3
- iCounter = up.getNumForeignCitiesOnBaltic(iPlayer, True)
+ iCounter = UniquePowers.getNumForeignCitiesOnBaltic(iPlayer, True)
sText3 += self.getCounterString(iCounter, 0, True)
sText3 += " " + text("TXT_KEY_UHV_BALTIC_CITIES")
lHelpTexts = [sText1, sText2, sText3]
@@ -3148,13 +3149,13 @@ def getPrussiaText(self):
pPlayer = gc.getPlayer(iPlayer)
sText1, sText2, sText3 = self.getEmptyTexts()
# UHV1
- sText1 += self.getProvinceString(vic.tPrussiaControlI)
+ sText1 += self.getProvinceString(Victory.tPrussiaControlI)
# UHV2
if turn() >= year(1650):
iConqRaw = gc.getPlayer(Civ.PRUSSIA).getUHVCounter(1)
- for iI in range(len(vic.tPrussiaDefeat)):
+ for iI in range(len(Victory.tPrussiaDefeat)):
iNumConq = (iConqRaw / pow(10, iI)) % 10
- pVictim = gc.getPlayer(vic.tPrussiaDefeat[iI])
+ pVictim = gc.getPlayer(Victory.tPrussiaDefeat[iI])
if iNumConq < 9:
szNumConq = " %d" % iNumConq
else:
@@ -3197,7 +3198,7 @@ def getLithuaniaText(self):
iCulture = pPlayer.getUHVCounter(0)
sText1 += self.getCounterString(iCulture, 2500)
# UHV2
- iCount, iTotal = vic.Victory().getTerritoryPercentEurope(iPlayer, True)
+ iCount, iTotal = Victory.getTerritoryPercentEurope(iPlayer, True)
iOtherCount = 0
iMostPlayer = -1
for iLoopPlayer in civilizations().majors().ids():
@@ -3205,7 +3206,7 @@ def getLithuaniaText(self):
continue
pLoopPlayer = gc.getPlayer(iLoopPlayer)
if pLoopPlayer.isAlive():
- iTempCount = vic.Victory().getTerritoryPercentEurope(iLoopPlayer)
+ iTempCount = Victory.getTerritoryPercentEurope(iLoopPlayer)
if iTempCount > iOtherCount:
iOtherCount = iTempCount
iMostPlayer = iLoopPlayer
@@ -3229,7 +3230,7 @@ def getAustriaText(self):
pPlayer = gc.getPlayer(iPlayer)
sText1, sText2, sText3 = self.getEmptyTexts()
# UHV1
- sText1 += self.getProvinceString(vic.tAustriaControl)
+ sText1 += self.getProvinceString(Victory.tAustriaControl)
# UHV2
iCount = 0
for iLoopPlayer in civilizations().majors().ids():
@@ -3255,11 +3256,11 @@ def getTurkeyText(self):
pPlayer = gc.getPlayer(iPlayer)
sText1, sText2, sText3 = self.getEmptyTexts()
# UHV1
- sText1 += self.getProvinceString(vic.tOttomanControlI)
+ sText1 += self.getProvinceString(Victory.tOttomanControlI)
# UHV2
- sText2 += self.getWonderString(vic.tOttomanWonders)
+ sText2 += self.getWonderString(Victory.tOttomanWonders)
# UHV3
- sText3 += self.getProvinceString(vic.tOttomanControlII)
+ sText3 += self.getProvinceString(Victory.tOttomanControlII)
lHelpTexts = [sText1, sText2, sText3]
return lHelpTexts
@@ -3269,7 +3270,7 @@ def getMoscowText(self):
sText1, sText2, sText3 = self.getEmptyTexts()
# UHV1
sEnemyString = "Barbarians"
- sText1 += self.getNotCivProvinceString(Civ.BARBARIAN, sEnemyString, vic.tMoscowControl)
+ sText1 += self.getNotCivProvinceString(Civ.BARBARIAN, sEnemyString, Victory.tMoscowControl)
# UHV2
totalLand = gc.getMap().getLandPlots()
RussianLand = pPlayer.getTotalLand()
@@ -3604,7 +3605,7 @@ def getCounterString(
return sString
def getNumColoniesString(self, iRequired, bTradingCompanies=False):
- iCount = vic.Victory().getNumRealColonies(self.iActivePlayer)
+ iCount = Victory.getNumRealColonies(self.iActivePlayer)
sString = (
text("TXT_KEY_UHV_COLONIES") + ": " + self.determineColor(iCount >= iRequired, iCount)
)
diff --git a/Assets/Python/screens/PlatyBuilder/CvPlatyBuilderScreen.py b/Assets/Python/screens/PlatyBuilder/CvPlatyBuilderScreen.py
index 3173296ba..d74407cf3 100644
--- a/Assets/Python/screens/PlatyBuilder/CvPlatyBuilderScreen.py
+++ b/Assets/Python/screens/PlatyBuilder/CvPlatyBuilderScreen.py
@@ -1,4 +1,5 @@
from CvPythonExtensions import *
+from CvPlatyBuilderSettings import *
from CityMapData import CITIES_MAP
from Core import (
get_data_from_upside_down_map,
@@ -33,20 +34,6 @@
import Popup
gc = CyGlobalContext()
-iChange = 1
-bPython = True
-bHideInactive = True
-Activities = [
- "AWAKE",
- "HOLD",
- "SLEEP",
- "HEAL",
- "SENTRY",
- "INTERCEPT",
- "MISSION",
- "PATROL",
- "PLUNDER",
-]
class CvWorldBuilderScreen:
diff --git a/Assets/Python/screens/PlatyBuilder/CvPlatyBuilderSettings.py b/Assets/Python/screens/PlatyBuilder/CvPlatyBuilderSettings.py
new file mode 100644
index 000000000..21530cb43
--- /dev/null
+++ b/Assets/Python/screens/PlatyBuilder/CvPlatyBuilderSettings.py
@@ -0,0 +1,14 @@
+iChange = 1
+bPython = True
+bHideInactive = True
+Activities = [
+ "AWAKE",
+ "HOLD",
+ "SLEEP",
+ "HEAL",
+ "SENTRY",
+ "INTERCEPT",
+ "MISSION",
+ "PATROL",
+ "PLUNDER",
+]
diff --git a/Assets/Python/screens/ScreenHandler.py b/Assets/Python/screens/ScreenHandler.py
new file mode 100644
index 000000000..200d3df0e
--- /dev/null
+++ b/Assets/Python/screens/ScreenHandler.py
@@ -0,0 +1,1120 @@
+from CvPythonExtensions import *
+import CvPlatyBuilderSettings
+import CvAdvisorUtils
+import CvTopCivs
+import CvEspionageAdvisor
+import CvScreensInterface
+import CvDebugTools
+import CvWBPopups
+import CvCameraControls
+import CvUtil
+import PyHelpers
+import Popup as PyPopup
+from Core import get_data_from_upside_down_map, human, player, text
+from MiscData import MODNET_EVENTS
+from CityMapData import CITIES_MAP
+from Events import events, handler
+
+## Ultrapack ##
+import WBCityEditScreen
+import WBUnitScreen
+import WBPlayerScreen
+import WBGameDataScreen
+import WBPlotScreen
+import CvPlatyBuilderScreen
+
+gc = CyGlobalContext()
+PyPlayer = PyHelpers.PyPlayer
+PyInfo = PyHelpers.PyInfo
+
+
+@handler("kbdEvent")
+def onKbdEvent(eventType, key, mx, my, px, py):
+ if events.bAllowCheats:
+ # notify debug tools of input to allow it to override the control
+ argsList = (
+ eventType,
+ key,
+ events.bCtrl,
+ events.bShift,
+ events.bAlt,
+ mx,
+ my,
+ px,
+ py,
+ gc.getGame().isNetworkMultiPlayer(),
+ )
+ if CvDebugTools.g_CvDebugTools.notifyInput(argsList):
+ return 0
+
+ if eventType == events.EventKeyDown:
+ key = int(key)
+
+ CvCameraControls.g_CameraControls.handleInput(key)
+
+ if events.bAllowCheats:
+ # Shift - T (Debug - No MP)
+ if key == int(InputTypes.KB_T):
+ if events.bShift:
+ events.beginEvent(CvUtil.EventAwardTechsAndGold)
+ # events.beginEvent(CvUtil.EventCameraControlPopup)
+ return 1
+
+ elif key == int(InputTypes.KB_W):
+ if events.bShift and events.bCtrl:
+ events.beginEvent(CvUtil.EventShowWonder)
+ return 1
+
+ # Shift - ] (Debug - currently mouse-overd unit, health += 10
+ elif key == int(InputTypes.KB_LBRACKET) and events.bShift:
+ unit = CyMap().plot(px, py).getUnit(0)
+ if not unit.isNone():
+ d = min(unit.maxHitPoints() - 1, unit.getDamage() + 10)
+ unit.setDamage(d, PlayerTypes.NO_PLAYER)
+
+ # Shift - [ (Debug - currently mouse-overd unit, health -= 10
+ elif key == int(InputTypes.KB_RBRACKET) and events.bShift:
+ unit = CyMap().plot(px, py).getUnit(0)
+ if not unit.isNone():
+ d = max(0, unit.getDamage() - 10)
+ unit.setDamage(d, PlayerTypes.NO_PLAYER)
+
+ elif key == int(InputTypes.KB_F1):
+ if events.bShift:
+ CvScreensInterface.replayScreen.showScreen(False)
+ return 1
+ # don't return 1 unless you want the input consumed
+
+ elif key == int(InputTypes.KB_F2):
+ if events.bShift:
+ CvScreensInterface.showDebugInfoScreen()
+ return 1
+
+ elif key == int(InputTypes.KB_F3):
+ if events.bShift:
+ CvScreensInterface.showDanQuayleScreen(())
+ return 1
+
+ elif key == int(InputTypes.KB_F4):
+ if events.bShift:
+ CvScreensInterface.showUnVictoryScreen(())
+ return 1
+
+
+@handler("mouseEvent")
+def onMouseEvent(eventType, mx, my, px, py, interfaceConsumed, screens):
+ if px != -1 and py != -1:
+ if eventType == events.EventLButtonDown:
+ if (
+ events.bAllowCheats
+ and events.bCtrl
+ and events.bAlt
+ and CyMap().plot(px, py).isCity()
+ and not interfaceConsumed
+ ):
+ # Launch Edit City Event
+ events.beginEvent(CvUtil.EventEditCity, (px, py))
+ return 1
+
+ elif events.bAllowCheats and events.bCtrl and events.bShift and not interfaceConsumed:
+ # Launch Place Object Event
+ events.beginEvent(CvUtil.EventPlaceObject, (px, py))
+ return 1
+
+ if eventType == events.EventBack:
+ return CvScreensInterface.handleBack(screens)
+ elif eventType == events.EventForward:
+ return CvScreensInterface.handleForward(screens)
+
+
+@handler("ModNetMessage")
+def onModNetMessage(iData1, iData2, iData3, iData4, iData5):
+ if iData1 == MODNET_EVENTS["CHANGE_COMMERCE_PERCENT"]:
+ CommerceType = [
+ CommerceTypes.COMMERCE_GOLD,
+ CommerceTypes.COMMERCE_RESEARCH,
+ CommerceTypes.COMMERCE_CULTURE,
+ CommerceTypes.COMMERCE_ESPIONAGE,
+ ]
+ gc.getPlayer(iData2).changeCommercePercent(CommerceType[iData3], iData4)
+ if iData2 == CyGame().getActivePlayer():
+ screen = CvEspionageAdvisor.CvEspionageAdvisor().getScreen()
+ if screen.isActive():
+ CvEspionageAdvisor.CvEspionageAdvisor().updateEspionageWeights()
+
+
+@handler("Update")
+def onUpdate(delta_time):
+ # allow camera to be updated
+ CvCameraControls.g_CameraControls.onUpdate(delta_time)
+
+
+@handler("OnLoad")
+def onLoadGame():
+ CvAdvisorUtils.resetNoLiberateCities()
+ return 0
+
+
+@handler("GameStart")
+def onGameStart():
+ # Rhye - Dawn of Man must appear in late starts too
+ # Duplicate with Assets/Python/Contrib/CvAllErasDawnOfManScreenEventManager.py
+ if (
+ gc.getGame().getStartEra() == gc.getDefineINT("STANDARD_ERA")
+ or gc.getGame().isOption(GameOptionTypes.GAMEOPTION_ADVANCED_START)
+ ) and player().isAlive():
+ popupInfo = CyPopupInfo()
+ popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_PYTHON_SCREEN)
+ popupInfo.setText(u"showDawnOfMan")
+ popupInfo.addPopup(human())
+ else:
+ CyInterface().setSoundSelectionReady(True)
+
+ if gc.getGame().isPbem() and player().isAlive():
+ popupInfo = CyPopupInfo()
+ popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_DETAILS)
+ popupInfo.setOption1(True)
+ popupInfo.addPopup(human())
+
+ CvAdvisorUtils.resetNoLiberateCities()
+
+
+@handler("BeginGameTurn")
+def onBeginTurn(iGameTurn):
+ CvTopCivs.CvTopCivs().turnChecker(iGameTurn)
+
+
+@handler("EndPlayerTurn")
+def onEndPlayerTurn(iGameTurn, iPlayer):
+ if gc.getGame().getElapsedGameTurns() == 1:
+ if gc.getPlayer(iPlayer).isHuman():
+ if gc.getPlayer(iPlayer).canRevolution(0):
+ popupInfo = CyPopupInfo()
+ popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_CHANGECIVIC)
+ popupInfo.addPopup(iPlayer)
+
+ CvAdvisorUtils.resetAdvisorNags()
+ CvAdvisorUtils.endTurnFeats(iPlayer)
+
+
+@handler("firstContact")
+def onFirstContact(iTeamX, iHasMetTeamY):
+ ## Platy Builder ##
+ if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderSettings.bPython:
+ return
+ ## Platy Builder ##
+ if not events._LOG_CONTACT:
+ return
+ CvUtil.pyPrint("Team %d has met Team %d" % (iTeamX, iHasMetTeamY))
+
+
+@handler("combatResult")
+def onCombatResult(pWinner, pLoser):
+ playerX = PyPlayer(pWinner.getOwner())
+ unitX = PyInfo.UnitInfo(pWinner.getUnitType())
+ playerY = PyPlayer(pLoser.getOwner())
+ unitY = PyInfo.UnitInfo(pLoser.getUnitType())
+ if not events._LOG_COMBAT:
+ return
+ if playerX and playerX and unitX and playerY:
+ CvUtil.pyPrint(
+ "Player %d Civilization %s Unit %s has defeated Player %d Civilization %s Unit %s"
+ % (
+ playerX.getID(),
+ playerX.getCivilizationName(),
+ unitX.getDescription(),
+ playerY.getID(),
+ playerY.getCivilizationName(),
+ unitY.getDescription(),
+ )
+ )
+
+
+@handler("combatLogCalc")
+def onCombatLogCalc(argsList):
+ "Combat Result"
+ genericArgs = argsList[0]
+ cdAttacker = genericArgs[0]
+ cdDefender = genericArgs[1]
+ iCombatOdds = genericArgs[2]
+ CvUtil.combatMessageBuilder(cdAttacker, cdDefender, iCombatOdds)
+
+
+@handler("combatLogHit")
+def onCombatLogHit(argsList):
+ "Combat Message"
+ global gCombatMessages, gCombatLog
+ genericArgs = argsList[0]
+ cdAttacker = genericArgs[0]
+ cdDefender = genericArgs[1]
+ iIsAttacker = genericArgs[2]
+ iDamage = genericArgs[3]
+ if cdDefender.eOwner == cdDefender.eVisualOwner:
+ szDefenderName = gc.getPlayer(cdDefender.eOwner).getNameKey()
+ else:
+ szDefenderName = text("TXT_KEY_TRAIT_PLAYER_UNKNOWN")
+ if cdAttacker.eOwner == cdAttacker.eVisualOwner:
+ szAttackerName = gc.getPlayer(cdAttacker.eOwner).getNameKey()
+ else:
+ szAttackerName = text("TXT_KEY_TRAIT_PLAYER_UNKNOWN")
+
+ if iIsAttacker == 0:
+ combatMessage = text(
+ "TXT_KEY_COMBAT_MESSAGE_HIT",
+ szDefenderName,
+ cdDefender.sUnitName,
+ iDamage,
+ cdDefender.iCurrHitPoints,
+ cdDefender.iMaxHitPoints,
+ )
+ CyInterface().addCombatMessage(cdAttacker.eOwner, combatMessage)
+ CyInterface().addCombatMessage(cdDefender.eOwner, combatMessage)
+ if cdDefender.iCurrHitPoints <= 0:
+ combatMessage = text(
+ "TXT_KEY_COMBAT_MESSAGE_DEFEATED",
+ szAttackerName,
+ cdAttacker.sUnitName,
+ szDefenderName,
+ cdDefender.sUnitName,
+ )
+ CyInterface().addCombatMessage(cdAttacker.eOwner, combatMessage)
+ CyInterface().addCombatMessage(cdDefender.eOwner, combatMessage)
+ elif iIsAttacker == 1:
+ combatMessage = text(
+ "TXT_KEY_COMBAT_MESSAGE_HIT",
+ szAttackerName,
+ cdAttacker.sUnitName,
+ iDamage,
+ cdAttacker.iCurrHitPoints,
+ cdAttacker.iMaxHitPoints,
+ )
+ CyInterface().addCombatMessage(cdAttacker.eOwner, combatMessage)
+ CyInterface().addCombatMessage(cdDefender.eOwner, combatMessage)
+ if cdAttacker.iCurrHitPoints <= 0:
+ combatMessage = text(
+ "TXT_KEY_COMBAT_MESSAGE_DEFEATED",
+ szDefenderName,
+ cdDefender.sUnitName,
+ szAttackerName,
+ cdAttacker.sUnitName,
+ )
+ CyInterface().addCombatMessage(cdAttacker.eOwner, combatMessage)
+ CyInterface().addCombatMessage(cdDefender.eOwner, combatMessage)
+
+
+@handler("improvementBuilt")
+def onImprovementBuilt(iImprovement, iX, iY):
+ ## Platy Builder ##
+ if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderSettings.bPython:
+ return
+ ## Platy Builder ##
+ "Improvement Built"
+ if not events._LOG_IMPROVEMENT:
+ return
+ CvUtil.pyPrint(
+ "Improvement %s was built at %d, %d"
+ % (PyInfo.ImprovementInfo(iImprovement).getDescription(), iX, iY)
+ )
+
+
+@handler("improvementDestroyed")
+def onImprovementDestroyed(iImprovement, iOwner, iX, iY):
+ if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderSettings.bPython:
+ return
+ "Improvement Destroyed"
+ if not events._LOG_IMPROVEMENT:
+ return
+ CvUtil.pyPrint(
+ "Improvement %s was Destroyed at %d, %d"
+ % (PyInfo.ImprovementInfo(iImprovement).getDescription(), iX, iY)
+ )
+
+
+@handler("routeBuilt")
+def onRouteBuilt(iRoute, iX, iY):
+ if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderSettings.bPython:
+ return
+ "Route Built"
+ if not events._LOG_IMPROVEMENT:
+ return
+ CvUtil.pyPrint(
+ "Route %s was built at %d, %d" % (gc.getRouteInfo(iRoute).getDescription(), iX, iY)
+ )
+
+
+@handler("buildingBuilt")
+def onBuildingBuilt(pCity, iBuildingType):
+ game = gc.getGame()
+ iPlayer = pCity.getOwner()
+ if (
+ (not game.isNetworkMultiPlayer())
+ and (iPlayer == game.getActivePlayer())
+ and isWorldWonderClass(gc.getBuildingInfo(iBuildingType).getBuildingClassType())
+ ):
+ if not CyGame().GetWorldBuilderMode():
+ popupInfo = CyPopupInfo()
+ popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_PYTHON_SCREEN)
+ popupInfo.setData1(iBuildingType)
+ popupInfo.setData2(pCity.getID())
+ popupInfo.setData3(0)
+ popupInfo.setText(u"showWonderMovie")
+ popupInfo.addPopup(iPlayer)
+
+ CvAdvisorUtils.buildingBuiltFeats(pCity, iBuildingType)
+
+ if not events._LOG_BUILDING:
+ return
+ CvUtil.pyPrint(
+ "%s was finished by Player %d Civilization %s"
+ % (
+ PyInfo.BuildingInfo(iBuildingType).getDescription(),
+ iPlayer,
+ player(iPlayer).getCivilizationDescription(0),
+ )
+ )
+
+
+@handler("projectBuilt")
+def onProjectBuilt(pCity, iProjectType):
+ iPlayer = pCity.getOwner()
+ game = gc.getGame()
+ if (not game.isNetworkMultiPlayer()) and (iPlayer == game.getActivePlayer()):
+ if not CyGame().GetWorldBuilderMode():
+ popupInfo = CyPopupInfo()
+ popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_PYTHON_SCREEN)
+ popupInfo.setData1(iProjectType)
+ popupInfo.setData2(pCity.getID())
+ popupInfo.setData3(2)
+ popupInfo.setText(u"showWonderMovie")
+ popupInfo.addPopup(iPlayer)
+
+
+@handler("selectionGroupPushMission")
+def onSelectionGroupPushMission(eOwner, eMission):
+ if not events._LOG_PUSH_MISSION:
+ return
+ if pHeadUnit: # type: ignore
+ CvUtil.pyPrint("Selection Group pushed mission %d" % (eMission))
+
+
+@handler("unitMove")
+def onUnitMove(pPlot, pUnit, pOldPlot):
+ player = PyPlayer(pUnit.getOwner())
+ unitInfo = PyInfo.UnitInfo(pUnit.getUnitType())
+ if not events._LOG_MOVEMENT:
+ return
+ if player and unitInfo:
+ CvUtil.pyPrint(
+ "Player %d Civilization %s unit %s is moving to %d, %d"
+ % (
+ player.getID(),
+ player.getCivilizationName(),
+ unitInfo.getDescription(),
+ pUnit.getX(),
+ pUnit.getY(),
+ )
+ )
+
+
+@handler("unitCreated")
+def on_unit_created(unit):
+ if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderSettings.bPython:
+ return
+ player = PyPlayer(unit.getOwner())
+ if not events._LOG_UNITBUILD:
+ return
+
+
+@handler("unitBuilt")
+def on_unit_built(city, unit):
+ player = PyPlayer(city.getOwner())
+ CvAdvisorUtils.unitBuiltFeats(city, unit)
+
+ if not events._LOG_UNITBUILD:
+ return
+ CvUtil.pyPrint(
+ "%s was finished by Player %d Civilization %s"
+ % (
+ PyInfo.UnitInfo(unit.getUnitType()).getDescription(),
+ player.getID(),
+ player.getCivilizationName(),
+ )
+ )
+
+
+@handler("unitKilled")
+def onUnitKilled(unit, iAttacker):
+ player = PyPlayer(unit.getOwner())
+ attacker = PyPlayer(iAttacker)
+ if not events._LOG_UNITKILLED:
+ return
+ CvUtil.pyPrint(
+ "Player %d Civilization %s Unit %s was killed by Player %d"
+ % (
+ player.getID(),
+ player.getCivilizationName(),
+ PyInfo.UnitInfo(unit.getUnitType()).getDescription(),
+ attacker.getID(),
+ )
+ )
+
+
+@handler("unitLost")
+def onUnitLost(unit):
+ if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderSettings.bPython:
+ return
+
+ player = PyPlayer(unit.getOwner())
+ if not events._LOG_UNITLOST:
+ return
+ CvUtil.pyPrint(
+ "%s was lost by Player %d Civilization %s"
+ % (
+ PyInfo.UnitInfo(unit.getUnitType()).getDescription(),
+ player.getID(),
+ player.getCivilizationName(),
+ )
+ )
+
+
+@handler("unitPromoted")
+def onUnitPromoted(unit, promotion):
+ player = PyPlayer(unit.getOwner())
+ if not events._LOG_UNITPROMOTED:
+ return
+ CvUtil.pyPrint(
+ "Unit Promotion Event: %s - %s" % (player.getCivilizationName(), unit.getName())
+ )
+
+
+@handler("unitSelected")
+def onUnitSelected(unit):
+ player = PyPlayer(unit.getOwner())
+ if not events._LOG_UNITSELECTED:
+ return
+ CvUtil.pyPrint(
+ "%s was selected by Player %d Civilization %s"
+ % (
+ PyInfo.UnitInfo(unit.getUnitType()).getDescription(),
+ player.getID(),
+ player.getCivilizationName(),
+ )
+ )
+
+
+@handler("UnitRename")
+def onUnitRename(pUnit):
+ if pUnit.getOwner() == gc.getGame().getActivePlayer():
+ __eventEditUnitNameBegin(pUnit)
+
+
+@handler("unitPillage")
+def onUnitPillage(pUnit, iImprovement, iRoute, iOwner):
+ iPlotX = pUnit.getX()
+ iPlotY = pUnit.getY()
+
+ if not events._LOG_UNITPILLAGE:
+ return
+ CvUtil.pyPrint(
+ "Player %d's %s pillaged improvement %d and route %d at plot at (%d, %d)"
+ % (
+ iOwner,
+ PyInfo.UnitInfo(pUnit.getUnitType()).getDescription(),
+ iImprovement,
+ iRoute,
+ iPlotX,
+ iPlotY,
+ )
+ )
+
+
+@handler("goodyReceived")
+def onGoodyReceived(iPlayer):
+ if not events._LOG_GOODYRECEIVED:
+ return
+ CvUtil.pyPrint(
+ "%s received a goody" % (gc.getPlayer(iPlayer).getCivilizationDescription(0)),
+ )
+
+
+@handler("greatPersonBorn")
+def onGreatPersonBorn(pUnit, iPlayer, pCity):
+ if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderSettings.bPython:
+ return
+ if pUnit.isNone() or pCity.isNone():
+ return
+ if not events._LOG_GREATPERSON:
+ return
+ CvUtil.pyPrint(
+ "A %s was born for %s in %s"
+ % (pUnit.getName(), player.getCivilizationName(), pCity.getName())
+ )
+
+
+@handler("techAcquired")
+def onTechAcquired(iTechType, iTeam, iPlayer, bAnnounce):
+ if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderSettings.bPython:
+ return
+ # Note that iPlayer may be NULL (-1) and not a refer to a player object
+ # Show tech splash when applicable
+ if iPlayer > -1 and bAnnounce and not CyInterface().noTechSplash():
+ if gc.getGame().isFinalInitialized() and not gc.getGame().GetWorldBuilderMode():
+ if (not gc.getGame().isNetworkMultiPlayer()) and (
+ iPlayer == gc.getGame().getActivePlayer()
+ ):
+ popupInfo = CyPopupInfo()
+ popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_PYTHON_SCREEN)
+ popupInfo.setData1(iTechType)
+ popupInfo.setText(u"showTechSplash")
+ popupInfo.addPopup(iPlayer)
+
+ if not events._LOG_TECH:
+ return
+ CvUtil.pyPrint(
+ "%s was finished by Team %d" % (PyInfo.TechnologyInfo(iTechType).getDescription(), iTeam)
+ )
+
+
+@handler("techSelected")
+def onTechSelected(iTechType, iPlayer):
+ if not events._LOG_TECH:
+ return
+ CvUtil.pyPrint(
+ "%s was selected by Player %d"
+ % (PyInfo.TechnologyInfo(iTechType).getDescription(), iPlayer)
+ )
+
+
+@handler("religionFounded")
+def onReligionFounded(iReligion, iFounder):
+ if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderSettings.bPython:
+ return
+ player = PyPlayer(iFounder)
+
+ iCityId = gc.getGame().getHolyCity(iReligion).getID()
+ if gc.getGame().isFinalInitialized() and not gc.getGame().GetWorldBuilderMode():
+ if (not gc.getGame().isNetworkMultiPlayer()) and (
+ iFounder == gc.getGame().getActivePlayer()
+ ):
+ popupInfo = CyPopupInfo()
+ popupInfo.setButtonPopupType(ButtonPopupTypes.BUTTONPOPUP_PYTHON_SCREEN)
+ popupInfo.setData1(iReligion)
+ popupInfo.setData2(iCityId)
+ popupInfo.setData3(1)
+ popupInfo.setText(u"showWonderMovie")
+ popupInfo.addPopup(iFounder)
+
+ if not events._LOG_RELIGION:
+ return
+ CvUtil.pyPrint(
+ "Player %d Civilization %s has founded %s"
+ % (
+ iFounder,
+ player.getCivilizationName(),
+ gc.getReligionInfo(iReligion).getDescription(),
+ )
+ )
+
+
+@handler("religionSpread")
+def onReligionSpread(iReligion, iOwner, pSpreadCity):
+ if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderSettings.bPython:
+ return
+ player = PyPlayer(iOwner)
+ if not events._LOG_RELIGIONSPREAD:
+ return
+ CvUtil.pyPrint(
+ "%s has spread to Player %d Civilization %s city of %s"
+ % (
+ gc.getReligionInfo(iReligion).getDescription(),
+ iOwner,
+ player.getCivilizationName(),
+ pSpreadCity.getName(),
+ )
+ )
+
+
+@handler("religionRemove")
+def onReligionRemove(iReligion, iOwner, pRemoveCity):
+ if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderSettings.bPython:
+ return
+ player = PyPlayer(iOwner)
+ if not events._LOG_RELIGIONSPREAD:
+ return
+ CvUtil.pyPrint(
+ "%s has been removed from Player %d Civilization %s city of %s"
+ % (
+ gc.getReligionInfo(iReligion).getDescription(),
+ iOwner,
+ player.getCivilizationName(),
+ pRemoveCity.getName(),
+ )
+ )
+
+
+@handler("corporationFounded")
+def onCorporationFounded(iCorporation, iFounder):
+ if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderSettings.bPython:
+ return
+ player = PyPlayer(iFounder)
+ if not events._LOG_RELIGION:
+ return
+ CvUtil.pyPrint(
+ "Player %d Civilization %s has founded %s"
+ % (
+ iFounder,
+ player.getCivilizationName(),
+ gc.getCorporationInfo(iCorporation).getDescription(),
+ )
+ )
+
+
+@handler("corporationSpread")
+def onCorporationSpread(iCorporation, iOwner, pSpreadCity):
+ if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderSettings.bPython:
+ return
+ player = PyPlayer(iOwner)
+ if not events._LOG_RELIGIONSPREAD:
+ return
+ CvUtil.pyPrint(
+ "%s has spread to Player %d Civilization %s city of %s"
+ % (
+ gc.getCorporationInfo(iCorporation).getDescription(),
+ iOwner,
+ player.getCivilizationName(),
+ pSpreadCity.getName(),
+ )
+ )
+
+
+@handler("corporationRemove")
+def onCorporationRemove(iCorporation, iOwner, pRemoveCity):
+ if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderSettings.bPython:
+ return
+ player = PyPlayer(iOwner)
+ if not events._LOG_RELIGIONSPREAD:
+ return
+ CvUtil.pyPrint(
+ "%s has been removed from Player %d Civilization %s city of %s"
+ % (
+ gc.getReligionInfo(iReligion).getDescription(), # type: ignore
+ iOwner,
+ player.getCivilizationName(),
+ pRemoveCity.getName(),
+ )
+ )
+
+
+@handler("goldenAge")
+def onGoldenAge(iPlayer):
+ if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderSettings.bPython:
+ return
+ player = PyPlayer(iPlayer)
+ if not events._LOG_GOLDENAGE:
+ return
+ CvUtil.pyPrint(
+ "Player %d Civilization %s has begun a golden age"
+ % (iPlayer, player.getCivilizationName())
+ )
+
+
+@handler("endGoldenAge")
+def onEndGoldenAge(iPlayer):
+ if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderSettings.bPython:
+ return
+ player = PyPlayer(iPlayer)
+ if not events._LOG_ENDGOLDENAGE:
+ return
+ CvUtil.pyPrint(
+ "Player %d Civilization %s golden age has ended" % (iPlayer, player.getCivilizationName())
+ )
+
+
+@handler("changeWar")
+def onChangeWar(bIsWar, iTeam, iRivalTeam):
+ if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderSettings.bPython:
+ return
+ if not events._LOG_WARPEACE:
+ return
+ if bIsWar:
+ strStatus = "declared war"
+ else:
+ strStatus = "declared peace"
+ CvUtil.pyPrint("Team %d has %s on Team %d" % (iTeam, strStatus, iRivalTeam))
+
+
+@handler("cityBuilt")
+def onCityBuilt(city):
+ # Absinthe: city naming popup on city foundation - settable in GlobalDefines_Alt.xml
+ iPlayer = city.getOwner()
+ bCityNamePopup = gc.getDefineINT("CITY_NAME_POPUP") == 1
+ if bCityNamePopup:
+ if iPlayer == gc.getGame().getActivePlayer():
+ __eventEditCityNameBegin(city, False)
+ CvUtil.pyPrint("City Built Event: %s" % (city.getName()))
+
+
+@handler("cityRazed")
+def onCityRazed(city, iPlayer):
+ # Rhye - start bugfix
+ owner = PyPlayer(city.getOwner())
+ if city.getOwner() == iPlayer:
+ if city.getPreviousOwner() != -1:
+ owner = PyPlayer(city.getPreviousOwner())
+ # Rhye - end bugfix
+
+ CvUtil.pyPrint("City Razed Event: %s" % (city.getName(),))
+ razor = PyPlayer(iPlayer)
+ CvUtil.pyPrint(
+ "Player %d Civilization %s City %s was razed by Player %d Civilization %s"
+ % (
+ owner.getID(),
+ owner.getCivilizationName(),
+ city.getName(),
+ razor.getID(),
+ razor.getCivilizationName(),
+ )
+ )
+
+ # TODO see RFC DOC partisans
+
+ # Absinthe: Partisans! - not used currently
+ # if city.getPopulation > 1 and iOwner != -1 and iPlayer != -1:
+ # owner = gc.getPlayer(iOwner)
+ # if not owner.isBarbarian() and owner.getNumCities() > 0:
+ # if gc.getTeam(owner.getTeam()).isAtWar(gc.getPlayer(iPlayer).getTeam()):
+ # if gc.getNumEventTriggerInfos() > 0: # prevents mods that don't have events from getting an error
+ # iEvent = CvUtil.findInfoTypeNum(gc.getEventTriggerInfo, gc.getNumEventTriggerInfos(),'EVENTTRIGGER_PARTISANS')
+ # if iEvent != -1 and gc.getGame().isEventActive(iEvent) and owner.getEventTriggerWeight(iEvent) < 0:
+ # triggerData = owner.initTriggeredData(iEvent, True, -1, city.getX(), city.getY(), iPlayer, city.getID(), -1, -1, -1, -1)
+ # Absinthe: end
+
+
+@handler("cityAcquired")
+def onCityAcquired(iPreviousOwner, iNewOwner, pCity, bConquest, bTrade):
+ if CyGame().GetWorldBuilderMode() and not CvPlatyBuilderSettings.bPython:
+ return
+ CvUtil.pyPrint("City Acquired Event: %s" % (pCity.getName()))
+
+
+@handler("cityAcquiredAndKept")
+def onCityAcquiredAndKept(iPlayer, pCity):
+ CvUtil.pyPrint("City Acquired and Kept Event: %s" % (pCity.getName()))
+ CvUtil.pyPrint(
+ "NewOwner: %s, PreviousOwner: %s"
+ % (
+ PyPlayer(pCity.getOwner()).getCivilizationName(),
+ PyPlayer(pCity.getPreviousOwner()).getCivilizationName(),
+ )
+ )
+
+
+@handler("cityLost")
+def onCityLost(city):
+ player = PyPlayer(city.getOwner())
+ if not events._LOG_CITYLOST:
+ return
+ CvUtil.pyPrint(
+ "City %s was lost by Player %d Civilization %s"
+ % (city.getName(), player.getID(), player.getCivilizationName())
+ )
+
+
+@handler("cityDoTurn")
+def onCityDoTurn(pCity, iPlayer):
+ CvAdvisorUtils.cityAdvise(pCity, iPlayer)
+
+
+@handler("cityBuildingUnit")
+def onCityBuildingUnit(pCity, iUnitType):
+ if not events._LOG_CITYBUILDING:
+ return
+ CvUtil.pyPrint(
+ "%s has begun building a %s"
+ % (pCity.getName(), gc.getUnitInfo(iUnitType).getDescription())
+ )
+
+
+@handler("cityBuildingBuilding")
+def onCityBuildingBuilding(pCity, iBuildingType):
+ if not events._LOG_CITYBUILDING:
+ return
+ CvUtil.pyPrint(
+ "%s has begun building a %s"
+ % (pCity.getName(), gc.getBuildingInfo(iBuildingType).getDescription())
+ )
+
+
+@handler("cityRename")
+def onCityRename(pCity):
+ if pCity.getOwner() == gc.getGame().getActivePlayer():
+ __eventEditCityNameBegin(pCity, True)
+
+
+@handler("victory")
+def onVictory(iTeam, iVictory):
+ if iVictory >= 0 and iVictory < gc.getNumVictoryInfos():
+ victoryInfo = gc.getVictoryInfo(int(iVictory))
+ CvUtil.pyPrint(
+ "Victory! Team %d achieves a %s victory" % (iTeam, victoryInfo.getDescription())
+ )
+
+
+@handler("vassalState")
+def onVassalState(iMaster, iVassal, bVassal):
+ if bVassal:
+ CvUtil.pyPrint("Team %d becomes a Vassal State of Team %d" % (iVassal, iMaster))
+ else:
+ CvUtil.pyPrint(
+ "Team %d revolts and is no longer a Vassal State of Team %d" % (iVassal, iMaster)
+ )
+
+
+#################### TRIGGERED EVENTS ##################
+
+
+def __eventEditCityNameBegin(city, bRename):
+ popup = PyPopup.PyPopup(CvUtil.EventEditCityName, EventContextTypes.EVENTCONTEXT_ALL)
+ popup.setUserData((city.getID(), bRename))
+ popup.setHeaderString(text("TXT_KEY_NAME_CITY"))
+ popup.setBodyString(text("TXT_KEY_SETTLE_NEW_CITY_NAME"))
+ # Absinthe: if not a rename, it should offer the CNM__eventEditCityBegin name as the default name
+ if bRename:
+ popup.createEditBox(city.getName())
+ else:
+ szName = get_data_from_upside_down_map(CITIES_MAP, city.getOwner(), city)
+ if szName == "-1":
+ popup.createEditBox(city.getName())
+ else:
+ szName = unicode(szName)
+ popup.createEditBox(szName)
+ # Absinthe: end
+ popup.setEditBoxMaxCharCount(15)
+ popup.launch()
+
+
+def __eventEditCityNameApply(playerID, userData, popupReturn):
+ "Edit City Name Event"
+ iCityID = userData[0]
+ bRename = userData[1]
+ player = gc.getPlayer(playerID)
+ city = player.getCity(iCityID)
+ cityName = popupReturn.getEditBoxString(0)
+ if len(cityName) > 30:
+ cityName = cityName[:30]
+ city.setName(cityName, not bRename)
+
+
+def __eventEditCityBegin(argsList):
+ "Edit City Event"
+ px, py = argsList
+ CvWBPopups.CvWBPopups().initEditCity(argsList)
+
+
+def __eventEditCityApply(playerID, userData, popupReturn):
+ "Edit City Event Apply"
+ if getChtLvl() > 0:
+ CvWBPopups.CvWBPopups().applyEditCity((popupReturn, userData))
+
+
+def __eventPlaceObjectBegin(argsList):
+ "Place Object Event"
+ CvDebugTools.CvDebugTools().initUnitPicker(argsList)
+
+
+def __eventPlaceObjectApply(playerID, userData, popupReturn):
+ "Place Object Event Apply"
+ if getChtLvl() > 0:
+ CvDebugTools.CvDebugTools().applyUnitPicker((popupReturn, userData))
+
+
+def __eventAwardTechsAndGoldBegin(argsList):
+ "Award Techs & Gold Event"
+ CvDebugTools.CvDebugTools().cheatTechs()
+
+
+def __eventAwardTechsAndGoldApply(playerID, netUserData, popupReturn):
+ "Award Techs & Gold Event Apply"
+ if getChtLvl() > 0:
+ CvDebugTools.CvDebugTools().applyTechCheat((popupReturn))
+
+
+def __eventShowWonderBegin(argsList):
+ "Show Wonder Event"
+ CvDebugTools.CvDebugTools().wonderMovie()
+
+
+def __eventShowWonderApply(playerID, netUserData, popupReturn):
+ "Wonder Movie Apply"
+ if getChtLvl() > 0:
+ CvDebugTools.CvDebugTools().applyWonderMovie((popupReturn))
+
+
+## Platy Builder ##
+def __eventEditUnitNameBegin(argsList):
+ pUnit = argsList
+ popup = PyPopup.PyPopup(CvUtil.EventEditUnitName, EventContextTypes.EVENTCONTEXT_ALL)
+ popup.setUserData((pUnit.getID(), CyGame().getActivePlayer()))
+ popup.setBodyString(text("TXT_KEY_RENAME_UNIT"))
+ popup.createEditBox(pUnit.getNameNoDesc())
+ popup.setEditBoxMaxCharCount(25)
+ popup.launch()
+
+
+def __eventEditUnitNameApply(playerID, userData, popupReturn):
+ unit = gc.getPlayer(userData[1]).getUnit(userData[0])
+ newName = popupReturn.getEditBoxString(0)
+ unit.setName(newName)
+ if CyGame().GetWorldBuilderMode():
+ WBUnitScreen.WBUnitScreen(CvPlatyBuilderScreen.CvWorldBuilderScreen()).placeStats()
+ WBUnitScreen.WBUnitScreen(CvPlatyBuilderScreen.CvWorldBuilderScreen()).placeCurrentUnit()
+
+
+def __eventEditCityNameBegin(city, bRename):
+ popup = PyPopup.PyPopup(CvUtil.EventEditCityName, EventContextTypes.EVENTCONTEXT_ALL)
+ popup.setUserData((city.getID(), bRename, CyGame().getActivePlayer()))
+ popup.setHeaderString(text("TXT_KEY_NAME_CITY"))
+ popup.setBodyString(text("TXT_KEY_SETTLE_NEW_CITY_NAME"))
+ # Absinthe: if not a rename, it should offer the CNM__eventEditCityBegin name as the default name
+ if bRename:
+ popup.createEditBox(city.getName())
+ else:
+ szName = get_data_from_upside_down_map(CITIES_MAP, city.getOwner(), city)
+ if szName == "-1":
+ popup.createEditBox(city.getName())
+ else:
+ szName = unicode(szName)
+ popup.createEditBox(szName)
+ # Absinthe: end
+ popup.setEditBoxMaxCharCount(15)
+ popup.launch()
+
+
+def __eventEditCityNameApply(playerID, userData, popupReturn):
+ city = gc.getPlayer(userData[2]).getCity(userData[0])
+ cityName = popupReturn.getEditBoxString(0)
+ city.setName(cityName, not userData[1])
+ if CyGame().GetWorldBuilderMode() and not CyGame().isInAdvancedStart():
+ WBCityEditScreen.WBCityEditScreen().placeStats()
+
+
+def __eventWBUnitScriptPopupApply(playerID, userData, popupReturn):
+ sScript = popupReturn.getEditBoxString(0)
+ pUnit = gc.getPlayer(userData[0]).getUnit(userData[1])
+ pUnit.setScriptData(CvUtil.convertToStr(sScript))
+ WBUnitScreen.WBUnitScreen(CvPlatyBuilderScreen.CvWorldBuilderScreen()).placeScript()
+ return
+
+
+def __eventWBPlayerScriptPopupApply(playerID, userData, popupReturn):
+ sScript = popupReturn.getEditBoxString(0)
+ gc.getPlayer(userData[0]).setScriptData(CvUtil.convertToStr(sScript))
+ WBPlayerScreen.WBPlayerScreen().placeScript()
+ return
+
+
+def __eventWBCityScriptPopupApply(playerID, userData, popupReturn):
+ sScript = popupReturn.getEditBoxString(0)
+ pCity = gc.getPlayer(userData[0]).getCity(userData[1])
+ pCity.setScriptData(CvUtil.convertToStr(sScript))
+ WBCityEditScreen.WBCityEditScreen().placeScript()
+ return
+
+
+def __eventWBScriptPopupBegin():
+ return
+
+
+def __eventWBGameScriptPopupApply(playerID, userData, popupReturn):
+ sScript = popupReturn.getEditBoxString(0)
+ CyGame().setScriptData(CvUtil.convertToStr(sScript))
+ WBGameDataScreen.WBGameDataScreen(CvPlatyBuilderScreen.CvWorldBuilderScreen()).placeScript()
+ return
+
+
+def __eventWBPlotScriptPopupApply(playerID, userData, popupReturn):
+ sScript = popupReturn.getEditBoxString(0)
+ pPlot = CyMap().plot(userData[0], userData[1])
+ pPlot.setScriptData(CvUtil.convertToStr(sScript))
+ WBPlotScreen.WBPlotScreen(CvPlatyBuilderScreen.CvWorldBuilderScreen()).placeScript()
+ return
+
+
+# def __eventWBStoredDataValuePopupApply(playerID, userData, popupReturn):
+# sScript = popupReturn.getEditBoxString(0)
+# try:
+# int(sScript)
+# bInt = True
+# except ValueError:
+# bInt = False
+# if bInt:
+# iValue = int(sScript)
+# WBStoredDataScreen.WBStoredDataScreen(
+# CvPlatyBuilderScreen.CvWorldBuilderScreen()
+# ).changeListTableValue(userData[0], iValue)
+# return
+
+
+def __eventWBLandmarkPopupApply(playerID, userData, popupReturn):
+ sScript = popupReturn.getEditBoxString(0)
+ pPlot = CyMap().plot(userData[0], userData[1])
+ iPlayer = userData[2]
+ if userData[3] > -1:
+ pSign = CyEngine().getSignByIndex(userData[3])
+ iPlayer = pSign.getPlayerType()
+ CyEngine().removeSign(pPlot, iPlayer)
+ if len(sScript):
+ if iPlayer == gc.getBARBARIAN_PLAYER():
+ CyEngine().addLandmark(pPlot, CvUtil.convertToStr(sScript))
+ else:
+ CyEngine().addSign(pPlot, iPlayer, CvUtil.convertToStr(sScript))
+ WBPlotScreen.iCounter = 10
+ return
+
+
+### REGISTER POPUP HANDLERS ###
+events.setPopupHandlers(
+ CvUtil.EventEditCityName, "EditCityName", __eventEditCityNameBegin, __eventEditCityNameApply
+)
+events.setPopupHandlers(
+ CvUtil.EventPlaceObject, "PlaceObject", __eventPlaceObjectBegin, __eventPlaceObjectApply
+)
+events.setPopupHandlers(
+ CvUtil.EventAwardTechsAndGold,
+ "AwardTechsAndGold",
+ __eventAwardTechsAndGoldBegin,
+ __eventAwardTechsAndGoldApply,
+)
+events.setPopupHandlers(
+ CvUtil.EventEditUnitName, "EditUnitName", __eventEditUnitNameBegin, __eventEditUnitNameApply
+)
+
+## Platy Builder ##
+events.setPopupHandlers(
+ CvUtil.EventWBLandmarkPopup,
+ "WBLandmarkPopup",
+ __eventWBScriptPopupBegin,
+ __eventWBLandmarkPopupApply,
+)
+events.setPopupHandlers(
+ CvUtil.EventShowWonder, "ShowWonder", __eventShowWonderBegin, __eventShowWonderApply
+)
+events.setPopupHandlers(
+ 1111, "WBPlayerScript", __eventWBScriptPopupBegin, __eventWBPlayerScriptPopupApply
+)
+events.setPopupHandlers(
+ 2222, "WBCityScript", __eventWBScriptPopupBegin, __eventWBCityScriptPopupApply
+)
+events.setPopupHandlers(
+ 3333, "WBUnitScript", __eventWBScriptPopupBegin, __eventWBUnitScriptPopupApply
+)
+events.setPopupHandlers(
+ 4444, "WBGameScript", __eventWBScriptPopupBegin, __eventWBGameScriptPopupApply
+)
+events.setPopupHandlers(
+ 5555, "WBPlotScript", __eventWBScriptPopupBegin, __eventWBPlotScriptPopupApply
+)
+# events.setPopupHandlers(
+# 7777, "WBStoredDataValue", __eventWBScriptPopupBegin, __eventWBStoredDataValuePopupApply
+# ),
+## Platy Builder ##
diff --git a/export-paths.sh b/export-paths.sh
index e15752deb..c53bfa411 100755
--- a/export-paths.sh
+++ b/export-paths.sh
@@ -27,10 +27,10 @@ LOCAL_PATHS=(
"$SCRIPT_DIR/Assets/Python/data/maps"
"$SCRIPT_DIR/Assets/Python/utils"
"$SCRIPT_DIR/Assets/Python/models"
- "$SCRIPT_DIR/Assets/Python/components"
"$SCRIPT_DIR/Assets/Python/EntryPoints"
"$SCRIPT_DIR/Assets/Python/pyWB"
"$SCRIPT_DIR/Assets/Python/screens"
+ "$SCRIPT_DIR/Assets/Python/BUG"
)
CURRENT_PYTHONPATHS=(