Partisan event.... still bugged after all this patches

r_rolo1

King of myself
Joined
May 19, 2006
Messages
13,818
Location
Lisbon, Portugal
CIV4EventInfos.XML
Code:
		<EventInfo>
			<Type>EVENT_PARTISANS_1</Type>
			<Description>TXT_KEY_EVENT_PARTISANS_1</Description>
			<LocalInfoText/>
			<WorldNewsTexts/>
			<OtherPlayerPopup>TXT_KEY_EVENT_PARTISANS_OTHER_1</OtherPlayerPopup>
			<QuestFailText/>
			<bQuest>0</bQuest>
			<bGlobal>0</bGlobal>
			<bTeam>0</bTeam>
			<bPickCity>0</bPickCity>
			<bPickOtherPlayerCity>0</bPickOtherPlayerCity>
			<bDeclareWar>0</bDeclareWar>
			<iGold>0</iGold>
			<bGoldToPlayer>0</bGoldToPlayer>
			<iRandomGold>0</iRandomGold>
			<iCulture>0</iCulture>
			<iEspionagePoints>0</iEspionagePoints>
			<bGoldenAge>0</bGoldenAge>
			<iFreeUnitSupport>0</iFreeUnitSupport>
			<iInflationMod>0</iInflationMod>
			<iSpaceProductionMod>0</iSpaceProductionMod>
			<Tech>NONE</Tech>
			<TechFlavors/>
			<iTechPercent>0</iTechPercent>
			<iTechCostPercent>0</iTechCostPercent>
			<iTechMinTurnsLeft>0</iTechMinTurnsLeft>
			<PrereqTech>NONE</PrereqTech>
			<UnitClass>NONE</UnitClass>
			<iNumFreeUnits>0</iNumFreeUnits>
			<bDisbandUnit>0</bDisbandUnit>
			<iUnitExperience>0</iUnitExperience>
			<iUnitImmobileTurns>0</iUnitImmobileTurns>
			<UnitPromotion/>
			<UnitName/>
			<UnitCombatPromotions/>
			<UnitClassPromotions/>
			<BuildingClass>NONE</BuildingClass>
			<iBuildingChange>0</iBuildingChange>
			<BuildingExtraYields/>
			<BuildingExtraCommerces/>
			<BuildingExtraHappies/>
			<BuildingExtraHealths/>
			<iHappy>0</iHappy>
			<iHealth>0</iHealth>
			<iHurryAnger>0</iHurryAnger>
			<iHappyTurns>0</iHappyTurns>
			<iRevoltTurns>0</iRevoltTurns>
			<iMinPillage>0</iMinPillage>
			<iMaxPillage>0</iMaxPillage>
			<iFood>0</iFood>
			<iFoodPercent>0</iFoodPercent>
			<FreeSpecialistCounts/>
			<FeatureType>NONE</FeatureType>
			<iFeatureChange>0</iFeatureChange>
			<ImprovementType>NONE</ImprovementType>
			<iImprovementChange>0</iImprovementChange>
			<BonusType>NONE</BonusType>
			<iBonusChange>0</iBonusChange>
			<RouteType>NONE</RouteType>
			<iRouteChange>0</iRouteChange>
			<BonusRevealed>NONE</BonusRevealed>
			<BonusGift>NONE</BonusGift>
			<PlotExtraYields/>
			<iConvertOwnCities>0</iConvertOwnCities>
			<iConvertOtherCities>0</iConvertOtherCities>
			<iMaxNumReligions>-1</iMaxNumReligions>
			<iOurAttitudeModifier>0</iOurAttitudeModifier>
			<iAttitudeModifier>0</iAttitudeModifier>
			<iTheirEnemyAttitudeModifier>0</iTheirEnemyAttitudeModifier>
			<iPopulationChange>0</iPopulationChange>
			<AdditionalEvents/>
			<EventTimes/>
			<ClearEvents/>
			<PythonCallback>applyPartisans1</PythonCallback>
			<PythonExpireCheck/>
			<PythonCanDo>canApplyPartisans1</PythonCanDo>
			<PythonHelp>getHelpPartisans1</PythonHelp>
			<Button>,Art/Interface/Buttons/Process/Blank.dds,Art/Interface/Buttons/Beyond_the_Sword_Atlas.dds,8,5</Button>
			<iAIValue>1000</iAIValue>
		</EventInfo>
		<EventInfo>
			<Type>EVENT_PARTISANS_2</Type>
			<Description>TXT_KEY_EVENT_PARTISANS_2</Description>
			<LocalInfoText/>
			<WorldNewsTexts/>
			<OtherPlayerPopup>TXT_KEY_EVENT_PARTISANS_OTHER_2</OtherPlayerPopup>
			<QuestFailText/>
			<bQuest>0</bQuest>
			<bGlobal>0</bGlobal>
			<bTeam>0</bTeam>
			<bPickCity>0</bPickCity>
			<bPickOtherPlayerCity>0</bPickOtherPlayerCity>
			<bDeclareWar>0</bDeclareWar>
			<iGold>0</iGold>
			<bGoldToPlayer>0</bGoldToPlayer>
			<iRandomGold>0</iRandomGold>
			<iCulture>0</iCulture>
			<iEspionagePoints>0</iEspionagePoints>
			<bGoldenAge>0</bGoldenAge>
			<iFreeUnitSupport>0</iFreeUnitSupport>
			<iInflationMod>0</iInflationMod>
			<iSpaceProductionMod>0</iSpaceProductionMod>
			<Tech>NONE</Tech>
			<TechFlavors/>
			<iTechPercent>0</iTechPercent>
			<iTechCostPercent>0</iTechCostPercent>
			<iTechMinTurnsLeft>0</iTechMinTurnsLeft>
			<PrereqTech>NONE</PrereqTech>
			<UnitClass>NONE</UnitClass>
			<iNumFreeUnits>0</iNumFreeUnits>
			<bDisbandUnit>0</bDisbandUnit>
			<iUnitExperience>0</iUnitExperience>
			<iUnitImmobileTurns>0</iUnitImmobileTurns>
			<UnitPromotion/>
			<UnitName/>
			<UnitCombatPromotions/>
			<UnitClassPromotions/>
			<BuildingClass>NONE</BuildingClass>
			<iBuildingChange>0</iBuildingChange>
			<BuildingExtraYields/>
			<BuildingExtraCommerces/>
			<BuildingExtraHappies/>
			<BuildingExtraHealths/>
			<iHappy>0</iHappy>
			<iHealth>0</iHealth>
			<iHurryAnger>0</iHurryAnger>
			<iHappyTurns>0</iHappyTurns>
			<iRevoltTurns>0</iRevoltTurns>
			<iMinPillage>0</iMinPillage>
			<iMaxPillage>0</iMaxPillage>
			<iFood>0</iFood>
			<iFoodPercent>0</iFoodPercent>
			<FreeSpecialistCounts/>
			<FeatureType>NONE</FeatureType>
			<iFeatureChange>0</iFeatureChange>
			<ImprovementType>NONE</ImprovementType>
			<iImprovementChange>0</iImprovementChange>
			<BonusType>NONE</BonusType>
			<iBonusChange>0</iBonusChange>
			<RouteType>NONE</RouteType>
			<iRouteChange>0</iRouteChange>
			<BonusRevealed>NONE</BonusRevealed>
			<BonusGift>NONE</BonusGift>
			<PlotExtraYields/>
			<iConvertOwnCities>0</iConvertOwnCities>
			<iConvertOtherCities>0</iConvertOtherCities>
			<iMaxNumReligions>-1</iMaxNumReligions>
			<iOurAttitudeModifier>0</iOurAttitudeModifier>
			<iAttitudeModifier>0</iAttitudeModifier>
			<iTheirEnemyAttitudeModifier>0</iTheirEnemyAttitudeModifier>
			<iPopulationChange>0</iPopulationChange>
			<AdditionalEvents/>
			<EventTimes/>
			<ClearEvents/>
			<PythonCallback>applyPartisans2</PythonCallback>
			<PythonExpireCheck/>
			<PythonCanDo>canApplyPartisans2</PythonCanDo>
			<PythonHelp>getHelpPartisans2</PythonHelp>
			<Button>,Art/Interface/Buttons/Process/Blank.dds,Art/Interface/Buttons/Beyond_the_Sword_Atlas.dds,8,5</Button>
			<iAIValue>1000</iAIValue>
		</EventInfo>
CIV4EventTriggerInfos.XML
Code:
<EventTriggerInfo>
			<Type>EVENTTRIGGER_PARTISANS</Type>
			<WorldNewsTexts>
				<Text>TXT_KEY_EVENTTRIGGER_PARTISANS</Text>
			</WorldNewsTexts>
			<TriggerTexts>
				<TriggerText>
					<Text>TXT_KEY_EVENT_TRIGGER_PARTISANS_1</Text>
					<Era>NONE</Era>
				</TriggerText>
			</TriggerTexts>
			<bSinglePlayer>0</bSinglePlayer>
			<iPercentGamesActive>100</iPercentGamesActive>
			<iWeight>-2</iWeight>
			<bProbabilityUnitMultiply>0</bProbabilityUnitMultiply>
			<bProbabilityBuildingMultiply>0</bProbabilityBuildingMultiply>
			<Civic>CIVIC_EMANCIPATION</Civic>
			<iMinTreasury>0</iMinTreasury>
			<iMinPopulation>0</iMinPopulation>
			<iMaxPopulation>0</iMaxPopulation>
			<iMinMapLandmass>0</iMinMapLandmass>
			<iMinOurLandmass>0</iMinOurLandmass>
			<iMaxOurLandmass>-1</iMaxOurLandmass>
			<MinDifficulty>NONE</MinDifficulty>
			<iAngry>0</iAngry>
			<iUnhealthy>0</iUnhealthy>
			<UnitsRequired/>
			<iNumUnits>0</iNumUnits>
			<iNumUnitsGlobal>0</iNumUnitsGlobal>
			<iUnitDamagedWeight>0</iUnitDamagedWeight>
			<iUnitDistanceWeight>0</iUnitDistanceWeight>
			<iUnitExperienceWeight>0</iUnitExperienceWeight>
			<bUnitsOnPlot>0</bUnitsOnPlot>
			<BuildingsRequired/>
			<iNumBuildings>0</iNumBuildings>
			<iNumBuildingsGlobal>0</iNumBuildingsGlobal>
			<iNumPlotsRequired>0</iNumPlotsRequired>
			<bOwnPlot>0</bOwnPlot>
			<iPlotType>-1</iPlotType>
			<FeaturesRequired/>
			<TerrainsRequired/>
			<ImprovementsRequired/>
			<BonusesRequired/>
			<RoutesRequired/>
			<ReligionsRequired/>
			<iNumReligions>0</iNumReligions>
			<CorporationsRequired/>
			<iNumCorporations>0</iNumCorporations>
			<bPickReligion>0</bPickReligion>
			<bStateReligion>0</bStateReligion>
			<bHolyCity>0</bHolyCity>
			<bPickCorporation>0</bPickCorporation>
			<bHeadquarters>0</bHeadquarters>
			<Events>
				<Event>EVENT_PARTISANS_1</Event>
				<Event>EVENT_PARTISANS_2</Event>
			</Events>
			<PrereqEvents/>
			<bPrereqEventPlot>0</bPrereqEventPlot>
			<OrPreReqs/>
			<AndPreReqs/>
			<ObsoleteTechs/>
			<bRecurring>1</bRecurring>
			<bTeam>0</bTeam>
			<bGlobal>0</bGlobal>
			<bPickPlayer>0</bPickPlayer>
			<bOtherPlayerWar>0</bOtherPlayerWar>
			<bOtherPlayerHasReligion>0</bOtherPlayerHasReligion>
			<bOtherPlayerHasOtherReligion>0</bOtherPlayerHasOtherReligion>
			<bOtherPlayerAI>0</bOtherPlayerAI>
			<iOtherPlayerShareBorders>0</iOtherPlayerShareBorders>
			<OtherPlayerHasTech>NONE</OtherPlayerHasTech>
			<bPickCity>0</bPickCity>
			<bPickOtherPlayerCity>0</bPickOtherPlayerCity>
			<bShowPlot>1</bShowPlot>
			<iCityFoodWeight>0</iCityFoodWeight>
			<PythonCanDo/>
			<PythonCanDoCity/>
			<PythonCanDoUnit/>
			<PythonCallback/>
		</EventTriggerInfo>
CvEventManager.py
Code:
def onCityRazed(self, argsList):
		'City Razed'
		city, iPlayer = argsList
		iOwner = city.findHighestCulture()
		
		# Partisans!
		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)
			
		CvUtil.pyPrint("City Razed Event: %s" %(city.getName(),))
I was definitely not a fan of the pre-3.17 partisan event, especially of the bug that made the event appear regardless of the target civ having the Emancipation civic ( try to play a OCC-AW in 3.13 and you'll see what I mean ;) ). And I thinked that it was fixed with 3.17 patch....

Unitl yesterday :(

What happened was that mystyfly IMed me asking about a strange phenomenon he had seen: he had razed a city of a civ and the partisans were of other civ that he was also warring and that the first civ had captured to the the second one 10 turns ago.

I decided to look to the code ( with the precious help of DanF ) and there are 2 things that, in spite of not conducting to a buggy behaviour most of the times, they can create highly irregular behaviour:

1- Regarding this event, the owner of the city is not the political owner, but the player that passes the city.findHighestCulture() check ( danF thinks the event not refering to the political owner was premeditaded, to avoid exploits ). All the later checks refer to that player, including the Emancipation check. This means that you can even raze a city of a civ that has not Emancipation as civic and get partisans of another civ that you war in war with, if that civ is in war with you and passes the city.findHighestCulture() check. This can happen easily ( but not only ) if you raze a city that belongs to the backward master of a advanced civ now, but that belonged to the advanced vassal ( Monty zerg rushing and vassaling Gandhi comes to mind )

2- Unlike I first thought, city.findHighestCulture() ( the check that decides who is the owner of the razed city in terms of this event ) does not get the plot culture of the city tile ( thanks DanF for this one ), but the actual city culture, that also includes the result of the espionage "spread culture" and that is not displayed in the interface. This means that you have absolutely no way of knowing what nationality the partisans will be ( and if they will appear ) without going to the debug. This also makes way to exploits regarding getting partisans out of foreign cities by using the espoinage culture spreading mission ( I can see that happening in MP easily )

Well, both of the situations are rare and I'm not even sure if 1 is a bug or not ( I'm inclined to being ). I thing this could be solved with getting the highest plot culture civ in city tile instead of the current culture check and making the Emancipation check to get the political owner of the city, regardless of who has the highest culture in city.

Thoughts?
 
If anybody is interested, I'm attaching a save where these things can be tested:



Gilgamesh is the political owner of New York and has the superior plot culture in the city tile (57% vs. 42%). I conquer and raze the city and 2 AMERICAN Infantry Partisans spawn :crazyeye:.

(In the save New York has a Sumerian city culture of 100:culture: and American city culture of 137:culture:, you will need to raise NYC's city culture to 101:culture: in order to produce the plot culture percentage shown in the screenshot, if this is raised to 138:culture: Sumerian Partisans will spawn.)

The strange thing is, that in contrast to the dubious usage the city's findHighestCulture function in order to determine the "owner", the calculation of the actual number of Partisans that spawn uses the plot culture again :crazyeye: (getNumPartisanUnits() in CvRandomEventInterface.py).

There even exists a function CvPlot::findHighestCulturePlayer() which would return the plot "owner" and thus also the dominating nationality of the city (=whose houses you burn to the ground)! IMHO it would be perfectly reasonable and logical to use this function, however, it is not exposed to Python (unlike the function CvPlot::findHighestCultureTeam()). Maybe that is the sole reason the devs chose to use the city's function :dunno:.

I'm afraid your suggestion is impossible to implement, since IIUC the requirements in CIV4EventTriggerInfos.XML must refer to the same player which the event eventually gets triggered for.
Instead I would just get the player with the highest plot culture the old fashioned way and trigger the event for him:
Code:
[SIZE="3"]	def onCityRazed(self, argsList):
		'City Razed'
		city, iPlayer = argsList
		iOwner = -1
		iBestPlotCulture = 0
		for i in range(gc.getMAX_PLAYERS()):
			if (city.plot().getCulture(i) > iBestPlotCulture):
				iBestPlotCulture = city.plot().getCulture(i)
				iOwner = i[/SIZE]
BTW - the exploit example I pm-ed you where you "harvest" the partisans for yourself by razing a city in which you have the highest culture doesn't work of course, because you would have to be at war with yourself :hammer2:, but I agree, one can do crazy things in multiplayer.
 

Attachments

  • PartisansTest.CivBeyondSwordSave
    80.6 KB · Views: 94
I noticed that the partisan milking was impossible in the way you said it ( that is why I avoided to refer to it ), but 2 players can definitely harvest partisans out of a unsuspecting third party: one spreads culture to the third party cities and the other razes those same cities while they maintain a fake war ;) . OFC that the AI is too dumb to play that waltz with a human......

P.S Niklas suggested me in IM that it didn't made any sense in his opinion that cities that never had been under Emancipation civic could spawn partisans ( he was OK with the whole partisan stuff in conquered or highly pressured foreign cities of a foe that had Emancipation... for him they were freedom fighters ). I don't even know if it is possible under current code structure ( this would imply to check civic history of the city.... ) and it borders dangerously game design.....
 
Top Bottom