[r83]: civ4ffplus / trunk / Assets / Python / FinalFrontierGameUtils.py History

Download this file

FinalFrontierGameUtils.py    836 lines (649 with data), 32.6 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
# Final Frontier
# Civilization 4 (c) 2007 Firaxis Games
# Designed & Programmed by: Jon 'Trip' Shafer
from CvPythonExtensions import *
import CvUtil
import CvEventInterface
import PyHelpers
from CvSolarSystem import printd
import CvSolarSystem
import CvAI
# globals
gc = CyGlobalContext()
localText = CyTranslator()
class FFGameUtils:
"Miscellaneous game functions"
def __init__(self):
self.dBuildingBonuses = { gc.getInfoTypeForString("BUILDING_FARM") : gc.getInfoTypeForString("BONUS_WHEAT"),
gc.getInfoTypeForString("BUILDING_RANCH") : gc.getInfoTypeForString("BONUS_COW"),
gc.getInfoTypeForString("BUILDING_HARBOR") : gc.getInfoTypeForString("BONUS_FISH"),
gc.getInfoTypeForString("BUILDING_PLANTATION") : gc.getInfoTypeForString("BONUS_SPICES"),
gc.getInfoTypeForString("BUILDING_WINERY") : gc.getInfoTypeForString("BONUS_WINE"),
gc.getInfoTypeForString("BUILDING_COTTONMILL") : gc.getInfoTypeForString("BONUS_COTTON")}
def isVictoryTest(self):
return True #Don't check for starting settlers- there aren't any!
def isVictory(self, argsList):
eVictory = argsList[0]
return True
def isPlayerResearch(self, argsList):
ePlayer = argsList[0]
return True
def getExtraCost(self, argsList):
ePlayer = argsList[0]
return 0
def createBarbarianCities(self):
return False
def createBarbarianUnits(self):
return False
def skipResearchPopup(self,argsList):
ePlayer = argsList[0]
return False
def showTechChooserButton(self,argsList):
ePlayer = argsList[0]
return True
def getFirstRecommendedTech(self,argsList):
ePlayer = argsList[0]
return TechTypes.NO_TECH
def getSecondRecommendedTech(self,argsList):
ePlayer = argsList[0]
eFirstTech = argsList[1]
return TechTypes.NO_TECH
def canRazeCity(self,argsList):
iRazingPlayer, pCity = argsList
return True
def canDeclareWar(self,argsList):
iAttackingTeam, iDefendingTeam = argsList
return True
def skipProductionPopup(self,argsList):
pCity = argsList[0]
return False
def showExamineCityButton(self,argsList):
pCity = argsList[0]
return True
def getRecommendedUnit(self,argsList):
pCity = argsList[0]
return UnitTypes.NO_UNIT
def getRecommendedBuilding(self,argsList):
pCity = argsList[0]
return BuildingTypes.NO_BUILDING
def updateColoredPlots(self):
return False
def isActionRecommended(self,argsList):
pUnit = argsList[0]
iAction = argsList[1]
return False
def unitCannotMoveInto(self,argsList):
ePlayer = argsList[0]
iUnitId = argsList[1]
iPlotX = argsList[2]
iPlotY = argsList[3]
return False
def cannotHandleAction(self,argsList):
pPlot = argsList[0]
iAction = argsList[1]
bTestVisible = argsList[2]
return False
def canBuild(self,argsList):
iX, iY, iBuild, iPlayer = argsList
return -1 # Returning -1 means ignore; 0 means Build cannot be performed; 1 or greater means it can
def cannotFoundCity(self,argsList):
iPlayer, iPlotX, iPlotY = argsList
return False
def cannotSelectionListMove(self,argsList):
pPlot = argsList[0]
bAlt = argsList[1]
bShift = argsList[2]
bCtrl = argsList[3]
return False
def cannotSelectionListGameNetMessage(self,argsList):
eMessage = argsList[0]
iData2 = argsList[1]
iData3 = argsList[2]
iData4 = argsList[3]
iFlags = argsList[4]
bAlt = argsList[5]
bShift = argsList[6]
return False
def cannotDoControl(self,argsList):
eControl = argsList[0]
return False
def canResearch(self,argsList):
ePlayer = argsList[0]
eTech = argsList[1]
bTrade = argsList[2]
return False
def cannotResearch(self,argsList):
ePlayer = argsList[0]
eTech = argsList[1]
bTrade = argsList[2]
return False
def canDoCivic(self,argsList):
ePlayer = argsList[0]
eCivic = argsList[1]
return False
def cannotDoCivic(self,argsList):
ePlayer = argsList[0]
eCivic = argsList[1]
return False
def canTrain(self,argsList):
pCity = argsList[0]
eUnit = argsList[1]
bContinue = argsList[2]
bTestVisible = argsList[3]
return False
def cannotTrain(self,argsList):
pCity = argsList[0]
eUnit = argsList[1]
bContinue = argsList[2]
bTestVisible = argsList[3]
return False
def canConstruct(self,argsList):
pCity = argsList[0]
eBuilding = argsList[1]
bContinue = argsList[2]
bTestVisible = argsList[3]
bIgnoreCost = argsList[4]
return False
def cannotConstruct(self,argsList):
pCity = argsList[0]
eBuilding = argsList[1]
bContinue = argsList[2]
bTestVisible = argsList[3]
bIgnoreCost = argsList[4]
# CP - validate eBuilding (I don't know why this is needed - if it is calling this with an
# invalid building code then something in the caller is broken)
if (eBuilding < 0):
CvSolarSystem.printd("CvGameUtils.cannotConstruct, passed eBuilding < 0 (%d)" % (eBuilding) )
return True
#FinalFrontier = CvEventInterface.getEventManager().FinalFrontier #FFPBUG
pSystem = CvSolarSystem.getSystemAt(pCity.getX(), pCity.getY()) #FFPBUG
pPlanet = pSystem.getPlanet(pSystem.getBuildingPlanetRing())
pCivilization = gc.getCivilizationInfo( gc.getPlayer(pCity.getOwner()).getCivilizationType())
bNotHere = False
pBuildingInfo = gc.getBuildingInfo(eBuilding)
# Cannot build a building if it already exists on the currently "Building" Planet
if (pPlanet):
if (pPlanet.isHasBuilding(eBuilding)):
bNotHere = True
else:
return True # this should never happen
#Moon and Rings restrictors moved to XML tags: TC01
if (pBuildingInfo.isMoon()) and (not pPlanet.isMoon()):
bNotHere = true
if (pBuildingInfo.isRings()) and (not pPlanet.isRings()):
bNotHere = true
if (eBuilding in self.dBuildingBonuses):
if not pPlanet.isBonus():
bNotHere = True
elif (pPlanet.getBonusType() != self.dBuildingBonuses[eBuilding]):
# the planet has a bonus, but it is the wrong one - since there can be only one bonus in a system
# and we know it has the wrong one, theis building can not be built anywhere in this system
return True
# On a disabled planet we can only build nuke immune buildings
if (not pBuildingInfo.isNukeImmune()) and pPlanet.isDisabled():
bNotHere = True
# Prereqs are required for the Planet
for iNeededBuildingClassLoop in range(gc.getNumBuildingClassInfos()):
if (pBuildingInfo.isBuildingClassNeededOnPlanet(iNeededBuildingClassLoop)):
iNeededBuildingLoop = pCivilization.getCivilizationBuildings(iNeededBuildingClassLoop )
if (not pPlanet.isHasBuilding(iNeededBuildingLoop)):
bNotHere = True
break
# CP - now for the "if we can't build it here, try it on some other planet in the system" upgrade.
# This is the core functionality of the improvement, and is all new.
# Skip if this if this is for a player, not an AI.
#
# Note: I'm not positive that this is working properly. If the AI ever calls this function when
# the build queue is not empty, then it can change the current build planet out from under whatever
# is currently being built, possibly continuing to build the thing currently in the queue on an
# invalid planet (such as one that already has the building, or that does not have a prereq building
# on it). So far I have not seen any mysterious bad behavior, but I can't be certain.
if bNotHere and (not gc.getPlayer(pCity.getOwner()).isHuman()):
for iPlanetLoop in range(pSystem.getNumPlanets()):
pLoopPlanet = pSystem.getPlanetByIndex(iPlanetLoop)
if (pLoopPlanet != pPlanet) and (pLoopPlanet.isPlanetWithinCulturalRange()) :
# skip the planet we are already using and planets not in the cultural range
if (pBuildingInfo.isMoon()) and (not pLoopPlanet.isMoon()):
continue
if (pBuildingInfo.isRings()) and (not pLoopPlanet.isRings()):
continue
if (pLoopPlanet.isHasBuilding(eBuilding)):
continue # already has one here, skip rest of loop
if (eBuilding in self.dBuildingBonuses):
if not pPlanet.isBonus():
# planet does not have bonus but one is required by this building
continue
elif (pPlanet.getBonusType() != self.dBuildingBonuses[eBuilding]):
# the planet has a bonus, but it is the wrong one - since there can be only one bonus in a system
# and we know it has the wrong one, this building can not be built anywhere in this system
return True
if (not pBuildingInfo.isNukeImmune()) and pLoopPlanet.isDisabled():
continue
hasPrereq = True
for iNeededBuildingClassLoop in range(gc.getNumBuildingClassInfos()):
if (pBuildingInfo.isBuildingClassNeededInCity(iNeededBuildingClassLoop)):
iNeededBuildingLoop = pCivilization.getCivilizationBuildings(iNeededBuildingClassLoop ) # get this civilization's building for this buildingclass
if (not pLoopPlanet.isHasBuilding(iNeededBuildingLoop)):
hasPrereq = False
break # one missing prereq is all that has to happen so skip checking for more
# If we get here with hasPrereq == True then we are at a planet that is
# not the one we started with, is within the cultural/influence range,
# does not already have a building of this type, and does have all prereq buildings.
# At this point we may, in the furture, want to add some additional checks, in particular
# we may want to check if the planet has any population assigned to it and skip if if
# it doesn't but the building type is one of the ones that modifies the planet's yield
# (which gains you nothing if the planet has no people on it). At the moment I'm not doing
# this because it may work fine without it - when the system's population assignments are
# recalculated it may shift people to the planet after the improvement is done.
# Also, we may want to add the planet to a list and then do some sort of selection
# process to determine which of the possible planets to use - for now, this is just
# using the first planet that it finds.
if (hasPrereq == True) :
bNotHere = False # don't block the build
if (not bTestVisible) : # only actually change the ring if not just testing "visibility"
pSystem.setBuildingPlanetRing(pLoopPlanet.getOrbitRing()) # switch to this new planet
CvSolarSystem.printd("CvGameUtils.cannotConstruct, %s active planet ring set to %d (turn = %d, owner = %s, building = %s, bContinue = %d, bTestVisible = %d)" % (pCity.getName(), pLoopPlanet.getOrbitRing(), CyGame().getElapsedGameTurns(), gc.getPlayer(pCity.getOwner()).getName(), pBuildingInfo.getType(), bContinue, bTestVisible) )
else:
CvSolarSystem.printd("CvGameUtils.cannotConstruct, %s active planet ring not set, bTestVisible = true (turn = %d, owner = %s, building = %s, bContinue = %d, bTestVisible = %d)" % (pCity.getName(), CyGame().getElapsedGameTurns(), gc.getPlayer(pCity.getOwner()).getName(), pBuildingInfo.getType(), bContinue, bTestVisible) )
break # we have done what we needed to do, bail out of the loop entirely
return bNotHere
def canCreate(self,argsList):
pCity = argsList[0]
eProject = argsList[1]
bContinue = argsList[2]
bTestVisible = argsList[3]
return False
def cannotCreate(self,argsList):
pCity = argsList[0]
eProject = argsList[1]
bContinue = argsList[2]
bTestVisible = argsList[3]
return False
def canMaintain(self,argsList):
pCity = argsList[0]
eProcess = argsList[1]
bContinue = argsList[2]
return False
def cannotMaintain(self,argsList):
pCity = argsList[0]
eProcess = argsList[1]
bContinue = argsList[2]
return False
def AI_chooseTech(self,argsList):
ePlayer = argsList[0]
bFree = argsList[1]
return TechTypes.NO_TECH
def AI_chooseProduction(self,argsList):
pCity = argsList[0]
FinalFrontier = CvEventInterface.getEventManager().FinalFrontier
bOverride = FinalFrontier.getAI().doCityAIProduction(pCity)
return bOverride
def AI_unitUpdate(self,argsList):
pUnit = argsList[0]
FinalFrontier = CvEventInterface.getEventManager().FinalFrontier
bOverride = false
# Only do it for actual AI units, not automated human ones
pPlayer = gc.getPlayer(pUnit.getOwner())
if (not pPlayer.isHuman()) and (not pPlayer.isBarbarian()) and pPlayer.isAlive() and (not pUnit.isNone()) and (not pUnit.isDead()):
iConstructShip = gc.getInfoTypeForString(gc.getDefineSTRING("CONSTRUCT_SHIP"))
if (pUnit.getUnitClassType() == iConstructShip):
bOverride = FinalFrontier.getAI().doConstructionShipAI(pUnit)
return bOverride
def AI_doWar(self,argsList):
eTeam = argsList[0]
return False
def AI_doDiplo(self,argsList):
ePlayer = argsList[0]
return False
def calculateScore(self,argsList):
ePlayer = argsList[0]
bFinal = argsList[1]
bVictory = argsList[2]
FinalFrontier = CvEventInterface.getEventManager().FinalFrontier
iMaxPopulation = FinalFrontier.iMaxPopulation
iPopulationScore = CvUtil.getScoreComponent(gc.getPlayer(ePlayer).getPopScore(), gc.getGame().getInitPopulation(), iMaxPopulation, gc.getDefineINT("SCORE_POPULATION_FACTOR"), True, bFinal, bVictory)
printd("Pop Score Stuff")
printd(gc.getPlayer(ePlayer).getPopScore())
printd(gc.getGame().getInitPopulation())
printd(iMaxPopulation)
printd(iPopulationScore)
iPlayerLandScore = gc.getPlayer(ePlayer).getTotalLand()
iLandScore = CvUtil.getScoreComponent(iPlayerLandScore , gc.getGame().getInitLand(), gc.getGame().getMaxLand(), gc.getDefineINT("SCORE_LAND_FACTOR"), True, bFinal, bVictory)
printd("Land Score Stuff")
printd(iPlayerLandScore)
printd(gc.getGame().getInitLand())
printd(gc.getGame().getMaxLand())
printd(iLandScore)
iTechScore = CvUtil.getScoreComponent(gc.getPlayer(ePlayer).getTechScore(), gc.getGame().getInitTech(), gc.getGame().getMaxTech(), gc.getDefineINT("SCORE_TECH_FACTOR"), True, bFinal, bVictory)
iWondersScore = CvUtil.getScoreComponent(gc.getPlayer(ePlayer).getWondersScore(), gc.getGame().getInitWonders(), gc.getGame().getMaxWonders(), gc.getDefineINT("SCORE_WONDER_FACTOR"), False, bFinal, bVictory)
iTotalScore = int(iLandScore + iWondersScore + iTechScore + iPopulationScore)
printd("Player %d Score: %d Pop: %d Land: %d Tech: %d Wonders: %d" %(ePlayer, iTotalScore, iPopulationScore, iLandScore, iTechScore, iWondersScore))
return iTotalScore
def doHolyCity(self):
return False
def doHolyCityTech(self,argsList):
eTeam = argsList[0]
ePlayer = argsList[1]
eTech = argsList[2]
bFirst = argsList[3]
return False
def doGold(self,argsList):
ePlayer = argsList[0]
return False
def doResearch(self,argsList):
ePlayer = argsList[0]
return False
def doGoody(self,argsList):
ePlayer = argsList[0]
pPlot = argsList[1]
pUnit = argsList[2]
return False
def doGrowth(self,argsList):
pCity = argsList[0]
return False
def doProduction(self,argsList):
pCity = argsList[0]
return False
def doCulture(self,argsList):
pCity = argsList[0]
return False
def doPlotCulture(self,argsList):
pCity = argsList[0]
bUpdate = argsList[1]
return False
def doReligion(self,argsList):
pCity = argsList[0]
return False
def cannotSpreadReligion(self,argsList):
iOwner, iUnitID, iReligion, iX, iY = argsList[0]
return False
def doGreatPeople(self,argsList):
pCity = argsList[0]
return False
def doMeltdown(self,argsList):
pCity = argsList[0]
pSystem = CvSolarSystem.getSystemAt(pCity.getX(), pCity.getY())
iMeltPlanet = -1
# check to see if there is a meltdown
for iBuilding in range(gc.getNumBuildingInfos()):
if pCity.getNumBuilding(iBuilding) > 0 :
iBuildingNukeExRand = gc.getBuildingInfo(iBuilding).getNukeExplosionRand()
if iBuildingNukeExRand != 0 :
if CyGame().getSorenRandNum(iBuildingNukeExRand, "FFP: meltdown check in doMeltdown callback") == 0 :
# a building has had a meltdown, check planets for buildings of this type and pick one
lPlanets = []
for iPlanet in range(pSystem.getNumPlanets()):
pPlanet = pSystem.getPlanetByIndex(iPlanet)
if pPlanet.isHasBuilding(iBuilding) :
lPlanets.append(pPlanet)
iMeltPlanet = CyGame().getSorenRandNum(len(lPlanets), "FPP: meltdown planet")
pMeltPlanet = lPlanets[iMeltPlanet]
# for the sake of simplicity, have it so that no star system will get more than one meltdown in a turn
break # break out of building loop
if iMeltPlanet == -1 :
# no meltdown so exit now (always return True to avoid DLL's meltdown processing)
return True
pPlayer = gc.getPlayer(pCity.getOwner()) # defined now since we don't need it above
pCityPlot = pCity.plot()
# Meltdown effects (same as nuke effects, but applied to meltdown planet instead of best planet)
# 1) set the planet to be disabled
# 2) remove all buildings from the now dead planet, dealing with capitol if on this planet
# 3) if thre was a bonus on the planet, remove it from planet and plot
# 4) chance of specified feature being distributed around system
# 5) unit damage (possibly killed)
# 6) population reduction
# 1) disable
pMeltPlanet.setDisabled(true)
pMeltPlanet.setPopulation(0)
# 2) remove buildings
for iBuilding in range(gc.getNumBuildingInfos()):
if pMeltPlanet.isHasBuilding(iBuilding) and not gc.getBuildingInfo(iBuilding).isNukeImmune():
bRemove = True
if (gc.getBuildingInfo(iBuilding).isCapital()):
if (pPlayer.getNumCities () > 1):
# The following call moves the capitol building, removing it from this city's data
# in the DLL (which is why there is no manual setNumRealBuilding in here)
# and adding it to the new capital city's data in the DLL plus adding it to that system's
# current build planet to get it into the Python planet data.
printd("Meltdown: finding new capial system")
pPlayer.findNewCapital()
else:
# This is this civ's only system so we can't move the capitol building to a different one.
# Try to move it to a different planet instead.
printd("Meltdown: moving capitol to different planet in same system")
# Select the planet that is the largest population limit planet
# (using production as tie breaker) that is not the planet being wiped out
bRemove = False
aiPlanetList = pSystem.getSizeYieldPlanetIndexList(1) # 1 is production, arbitrarily selected
for iLoopPlanet in range( len(aiPlanetList)):
pLoopPlanet = pSystem.getPlanetByIndex(aiPlanetList[iLoopPlanet][2])
if (pLoopPlanet.getOrbitRing() != pMeltPlanet.getOrbitRing()):
pLoopPlanet.setHasBuilding(iBuilding, true)
printd("Meltdown: moved Capitol to planet at ring %d" % pLoopPlanet.getOrbitRing())
bRemove = True
break
else:
pCity.setNumRealBuilding(iBuilding, pCity.getNumRealBuilding(iBuilding)-1)
if bRemove :
# The only time this is not the case is when it is the capitol and there is no other
# planet it can be moved to. You always need a Capitol, so it stays on the dead planet
pMeltPlanet.setHasBuilding(iBuilding, false)
# 2.5) unlisted above, but here anyway
if (pSystem.getBuildingPlanetRing() == pMeltPlanet.getOrbitRing()):
# This system's current build planet is the planet being wiped out,
# change it to some other planet, like the new "best" planet.
# There is an issue if every planet in the current infuence range is dead -
# in such a case there is no planet that should be having things built on it.
# With any luck, this will never come up.
pSystem.setBuildingPlanetRing(pSystem.getPlanetByIndex(CvSolarSystem.getBestPlanetInSystem(pSystem)).getOrbitRing())
# 3) remove bonus
if (pMeltPlanet.isBonus()): # planet being melted has a bonus, remove it from the planet and the plot
pMeltPlanet.setBonusType(-1)
pCityPlot.setBonusType(-1)
# 4) feature spread
for iDX in range(-1, 2) :
for iDY in range (-1, 2) :
if (iDX != 0) and (iDY != 0) :
pPlot = plotXY( pCity.getX(), pCity.getY(), iDX, iDY)
if pPlot and not pPlot.isNone():
if not pPlot.isImpassable() and (FeatureTypes.NO_FEATURE == pPlot.getFeatureType()) :
if (CyGame().getSorenRandNum(100, "Meltdown Fallout") < gc.getDefineINT("NUKE_FALLOUT_PROB")) :
pPlot.setImprovementType(ImprovementTypes.NO_IMPROVEMENT)
pPlot.setFeatureType(gc.getDefineINT("NUKE_FEATURE"), 0)
# 5) unit damage - only check units on this plot!
lUnit = []
for i in range(pCityPlot.getNumUnits()):
pLoopUnit = pCityPlot.getUnit(i)
if ( not pLoopUnit.isDead()): #is the unit alive?
lUnit.append(pLoopUnit) #add unit instance to list
for pUnit in lUnit :
if not pUnit.isDead() and not pUnit.isNukeImmune() :
iNukeDamage = gc.getDefineINT("NUKE_UNIT_DAMAGE_BASE") + CyGame().getSorenRandNum(gc.getDefineINT("NUKE_UNIT_DAMAGE_RAND_1"), "Nuke Damage 1") + CyGame().getSorenRandNum(gc.getDefineINT("NUKE_UNIT_DAMAGE_RAND_2"), "Nuke Damage 2")
iNukeDamage *= max(0, (pCity.getNukeModifier() + 100))
iNukeDamage /= 100
if pUnit.canFight() or (pUnit.airBaseCombatStr() > 0) :
printd("Meltdown: unit %s damaged for %d" % (pUnit.getName().encode('unicode_escape'), iNukeDamage))
pUnit.changeDamage(iNukeDamage, PlayerTypes.NO_PLAYER)
elif iNukeDamage >= gc.getDefineINT("NUKE_NON_COMBAT_DEATH_THRESHOLD") :
printd("Meltdown: non-combat unit %s killed from damage over threshold" % (pUnit.getName().encode('unicode_escape'),))
pUnit.kill(false, PlayerTypes.NO_PLAYER)
# 6) population reduction
iNukedPopulation = (pCity.getPopulation() * (gc.getDefineINT("NUKE_POPULATION_DEATH_BASE") + CyGame().getSorenRandNum(gc.getDefineINT("NUKE_POPULATION_DEATH_RAND_1"), "Population Nuked 1") + CyGame().getSorenRandNum(gc.getDefineINT("NUKE_POPULATION_DEATH_RAND_2"), "Population Nuked 2"))) / 100
iNukedPopulation *= max(0, (pCity.getNukeModifier() + 100))
iNukedPopulation /= 100
pCity.changePopulation(-(min((pCity.getPopulation() - 1), iNukedPopulation)))
# Now update the city and display
FinalFrontier = CvEventInterface.getEventManager().FinalFrontier
FinalFrontier.getAI().doCityAIUpdate(pCity)
pSystem.updateDisplay()
# give message that this has happened
szBuffer = localText.getText("TXT_KEY_MISC_MELTDOWN_CITY", (pCity.getName(),))
CyInterface().addMessage( pCity.getOwner(), False, gc.getDefineINT("EVENT_MESSAGE_TIME"), szBuffer,
"AS2D_MELTDOWN", InterfaceMessageTypes.MESSAGE_TYPE_MINOR_EVENT,
CyArtFileMgr().getInterfaceArtInfo("INTERFACE_UNHEALTHY_PERSON").getPath(), gc.getInfoTypeForString("COLOR_RED"),
pCity.getX(), pCity.getY(), True, True)
return True
def doReviveActivePlayer(self,argsList):
"allows you to perform an action after an AIAutoPlay"
iPlayer = argsList[0]
return False
def doPillageGold(self, argsList):
"controls the gold result of pillaging"
pPlot = argsList[0]
pUnit = argsList[1]
iPillageGold = 0
iPillageGold = CyGame().getSorenRandNum(gc.getImprovementInfo(pPlot.getImprovementType()).getPillageGold(), "Pillage Gold 1")
iPillageGold += CyGame().getSorenRandNum(gc.getImprovementInfo(pPlot.getImprovementType()).getPillageGold(), "Pillage Gold 2")
iPillageGold += (pUnit.getPillageChange() * iPillageGold) / 100
return iPillageGold
def doCityCaptureGold(self, argsList):
"controls the gold result of capturing a city"
pOldCity = argsList[0]
iCaptureGold = 0
iCaptureGold += gc.getDefineINT("BASE_CAPTURE_GOLD")
iCaptureGold += (pOldCity.getPopulation() * gc.getDefineINT("CAPTURE_GOLD_PER_POPULATION"))
iCaptureGold += CyGame().getSorenRandNum(gc.getDefineINT("CAPTURE_GOLD_RAND1"), "Capture Gold 1")
iCaptureGold += CyGame().getSorenRandNum(gc.getDefineINT("CAPTURE_GOLD_RAND2"), "Capture Gold 2")
if (gc.getDefineINT("CAPTURE_GOLD_MAX_TURNS") > 0):
iCaptureGold *= cyIntRange((CyGame().getGameTurn() - pOldCity.getGameTurnAcquired()), 0, gc.getDefineINT("CAPTURE_GOLD_MAX_TURNS"))
iCaptureGold /= gc.getDefineINT("CAPTURE_GOLD_MAX_TURNS")
return iCaptureGold
def citiesDestroyFeatures(self,argsList):
iX, iY= argsList
return False
def canFoundCitiesOnWater(self,argsList):
iX, iY= argsList
return True
def doCombat(self,argsList):
pSelectionGroup, pDestPlot = argsList
return False
def getConscriptUnitType(self, argsList):
iPlayer = argsList[0]
iConscriptUnitType = -1 #return this with the value of the UNIT TYPE you want to be conscripted
return iConscriptUnitType
def getCityFoundValue(self, argsList):
iPlayer, iPlotX, iPlotY = argsList
iFoundValue = -1 # Any value besides -1 will be used
pPlot = CyMap().plot(iPlotX, iPlotY)
iFeatureIDSolarSystem = gc.getInfoTypeForString('FEATURE_SOLAR_SYSTEM')
if (pPlot.getFeatureType() == iFeatureIDSolarSystem and not pPlot.isCity()):
printd("Determing Found Value for Plot at %d, %d" %(iPlotX, iPlotY))
# CP - Adjust base value based on path distance from capital (not straight line distance)
pCapCity = gc.getPlayer(iPlayer).getCapitalCity()
if pCapCity and not pCapCity.isNone() :
iDistance = CyMap().calculatePathDistance(pCapCity.plot(), pPlot)
if iDistance == -1 : # can't get there from here
return 0
else : # no capital city, - would normally mean first city not founded yet, I suppose.
iDistance = 1
iFoundValue = 10000 / (iDistance + 1) # CP - this provides only a small distance penalty
# Determine System value by planetary composition
if (CyGame().getElapsedGameTurns() > 0):
#iFoundValue = 0
FinalFrontier = CvEventInterface.getEventManager().FinalFrontier
pSystem = CvSolarSystem.getSystemAt(iPlotX, iPlotY) #FFPBUG
for iPlanetLoop in range(pSystem.getNumPlanets()):
pPlanet = pSystem.getPlanetByIndex(iPlanetLoop)
iPlanetValue = 0
# Green Planet
if (pPlanet.getPlanetType() == CvSolarSystem.iPlanetTypeGreen):
iPlanetValue = 400
# Not Green Planet
else:
iPlanetValue = 200
# CP - Give some value to planetary resources (God-Emperor, for version 1.6)
if (pPlanet.isBonus()):
iPlanetValue += 100 # This may need adjusting
# Two Civ-specific increase to this.
# The Forge gets -1 food in each system, so extra food is good for them meaning +50 for the resources that give extra food
# Trade routes are very good for the Red Syndicate, so +50 for each trade route
iTraitForge = gc.getInfoTypeForString('TRAIT_THE_FORGE')
iTraitSyndicate = gc.getInfoTypeForString('TRAIT_SYNDICATE')
pPlayer = gc.getPlayer(iPlayer)
pBonus = gc.getBonusInfo(pPlanet.getBonusType())
if (pPlayer.hasTrait(iTraitForge) and pBonus.getHealth() > 0): # all heath providing bonuses increase the planet's food
iPlanetValue += 50
elif (pPlayer.hasTrait(iTraitSyndicate) and pBonus.getHappiness() > 0): # all happy providing bonuses' related buildings give at least 1 extra trade route
pBonusBuilding = gc.getBuildingInfo(FinalFrontier.dBonusBuildings[pPlanet.getBonusType()])
iPlanetValue += 50 * pBonusBuilding.getTradeRoutes()
# Planet Size
iPlanetValue *= (pPlanet.getPlanetSize() + 1) + 2 # The +2 is to simply weight things a bit so that large planets aren't THAT much more valuable than small ones
# Can it be used right away?
if (pPlanet.getOrbitRing() < CvSolarSystem.g_iPlanetRange3):
iPlanetValue *= 2
printd("Orbit Ring %d iPlanetValue: %d" %(pPlanet.getOrbitRing(), iPlanetValue))
iFoundValue += iPlanetValue
else:
iFoundValue = 0
return iFoundValue
def canPickPlot(self, argsList):
pPlot = argsList[0]
return true
def getUnitCostMod(self, argsList):
iPlayer, iUnit = argsList
iCostMod = -1 # Any value > 0 will be used
FinalFrontier = CvEventInterface.getEventManager().FinalFrontier
iCostMod = FinalFrontier.getUnitCostMod(iPlayer, iUnit)
return iCostMod
def getBuildingCostMod(self, argsList):
iPlayer, iCityID, iBuilding = argsList
iCostMod = -1 # Any value > 0 will be used
FinalFrontier = CvEventInterface.getEventManager().FinalFrontier
iCostMod = FinalFrontier.getBuildingCostMod(iPlayer, iCityID, iBuilding)
return iCostMod
def canUpgradeAnywhere(self, argsList):
iOwner, iUnitID = argsList
pUnit = gc.getPlayer(iOwner).getUnit(iUnitID)
return False
def getWidgetHelp(self, argsList):
eWidgetType, iData1, iData2, bOption = argsList
printd("eWidgetType %d, iData1 %d, iData2 %d, bOption %d" % (eWidgetType, iData1, iData2, bOption))
szHelpText = u""
# All the FF specific widget help is for widgets with a type of WidgetTypes.WIDGET_GENERAL (FFP post 1.81, for B5, by G-E)
if (eWidgetType == WidgetTypes.WIDGET_GENERAL):
# Only show tool tip help when players have the tutorial on
if (not CyUserProfile().getPlayerOption(PlayerOptionTypes.PLAYEROPTION_MODDER_1)):
# Selected Planet
if (iData1 == 666):
szHelpText = localText.getText("TXT_KEY_FF_INTERFACE_SELECTED_PLANET_HELP", ())
# Planet Population
elif (iData1 == 667):
szHelpText = localText.getText("TXT_KEY_FF_INTERFACE_PLANET_POPULATION_HELP", ())
# Planet Yield
elif (iData1 == 668):
szHelpText = localText.getText("TXT_KEY_FF_INTERFACE_PRODUCES_HELP", ())
# Planet Assign Building
elif (iData1 == 669):
szHelpText = localText.getText("TXT_KEY_FF_INTERFACE_PLANET_BUILDINGS_HELP", ())
# Planet Widgets in Lower-Right
if (iData1 >= 671 and iData1 <= 678):
pHeadSelectedCity = CyInterface().getHeadSelectedCity()
pSystem = CvSolarSystem.getSystemAt(pHeadSelectedCity.getX(), pHeadSelectedCity.getY()) #FFPBUG
iPlanetRing = iData1 - 670
pPlanet = pSystem.getPlanet(iPlanetRing)
iFood = pPlanet.getTotalYield(pHeadSelectedCity.getOwner(), 0)
iProduction = pPlanet.getTotalYield(pHeadSelectedCity.getOwner(), 1)
iCommerce = pPlanet.getTotalYield(pHeadSelectedCity.getOwner(), 2)
iCultureLevel = pPlanet.getPlanetCulturalRange()
if pPlanet.isBonus():
szHelpText = pPlanet.getName() + "\n" + localText.getText("TXT_KEY_FF_INTERFACE_PLANET_SELECTION_HELP_0", (iFood, iProduction, iCommerce)) + "\n" + localText.getText("TXT_KEY_FFPLUS_PLANET_SELECTION_HELP", (iCultureLevel,)) + "\n" + u"%c " % gc.getBonusInfo(pPlanet.getBonusType()).getChar() + localText.getText("TXT_KEY_FFPLUS_PLANET_SELECTION_BONUS", (gc.getBonusInfo(pPlanet.getBonusType()).getDescription(),)) # Planetary Resource Indicator
else:
szHelpText = pPlanet.getName() + "\n" + localText.getText("TXT_KEY_FF_INTERFACE_PLANET_SELECTION_HELP_0", (iFood, iProduction, iCommerce)) + "\n" + localText.getText("TXT_KEY_FFPLUS_PLANET_SELECTION_HELP", (iCultureLevel,))
if (not CyUserProfile().getPlayerOption(PlayerOptionTypes.PLAYEROPTION_MODDER_1)):
szHelpText += "\n" + localText.getText("TXT_KEY_FF_INTERFACE_PLANET_SELECTION_HELP", ())
return szHelpText
def getUpgradePriceOverride(self, argsList):
iPlayer, iUnitID, iUnitTypeUpgrade = argsList
pPlayer = gc.getPlayer(iPlayer)
pUnit = pPlayer.getUnit(iUnitID)
return -1
def getExperienceNeeded(self, argsList):
# use this function to set how much experience a unit needs
iLevel, iOwner = argsList
iExperienceNeeded = 0
# regular epic game experience
iExperienceNeeded = iLevel * iLevel + 1
iModifier = gc.getPlayer(iOwner).getLevelExperienceModifier()
if (0 != iModifier):
iExperienceNeeded += (iExperienceNeeded * iModifier + 99) / 100
return iExperienceNeeded