3rd option for resource placement

Vilyathar

Chieftain
Joined
Mar 2, 2022
Messages
19
Hopefully this is the right spot for this. So, in the custom game options you can choose either "standard" or "balanced" resources. In the civ4bonusinfos xml you can pick which resources are put near players when balanced resources is selected. My question is, is there an easy way to add a third option, an alternative to balanced, where it is DIFFERENT resources that are guaranteed to spawn near you? Say for example if for some reason you wanted to ensure everyone starts with marble, cows, and incense. One could go in and edit the bonusinfos before starting that game, and then edit it back to normal later, but that would be a pain, and would be easy to overlook or forget stuff when you are editing the xml back and forth. I have done a lot of playing with xml files for civ4, but I've never tried to actually mess with the code (I'm not a programmer and would probably seriously mess stuff up without specific instructions). Can anyone tell me if this is possible without doing something super complicated? Thanks!
 
You could create a mod that does this ... it's certainly possible using BTS events relatively simply
 
luckily the magic xml pixie has dropped by and gave me this:

Stick the modified xml files in your mod directory, never overwrite the originals - back them up, write-protect, whatever

Code:
        <EventTriggerInfo>
            <Type>EVENTTRIGGER_VILYATHAR_FREESTUFF</Type>
            <WorldNewsTexts/>
            <TriggerTexts>
                <TriggerText>
                    <Text>The mighty Vilyathar has decreed we get free stuff!</Text>
                    <Era>NONE</Era>
                </TriggerText>
            </TriggerTexts>
            <bSinglePlayer>0</bSinglePlayer>
            <iPercentGamesActive>100</iPercentGamesActive>
            <iWeight>-1</iWeight>
            <bProbabilityUnitMultiply>0</bProbabilityUnitMultiply>
            <bProbabilityBuildingMultiply>0</bProbabilityBuildingMultiply>
            <Civic>NONE</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>1</iNumPlotsRequired>
            <bOwnPlot>1</bOwnPlot>
            <iPlotType>-1</iPlotType>
            <FeaturesRequired/>
            <TerrainsRequired/>
            <ImprovementsRequired>
                <ImprovementType>NONE</ImprovementType>
            </ImprovementsRequired>
            <BonusesRequired/>
            <RoutesRequired>
                <RouteType>NONE</RouteType>
            </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_VILYATHAR_FREESTUFF</Event>
            </Events>
            <PrereqEvents/>
            <bPrereqEventPlot>0</bPrereqEventPlot>
            <OrPreReqs/>
            <AndPreReqs/>
            <ObsoleteTechs/>
            <bRecurring>0</bRecurring>
            <bTeam>0</bTeam>
            <bGlobal>1</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>canTriggerVilyatharFreestuff</PythonCanDo>
            <PythonCanDoCity/>
            <PythonCanDoUnit/>
            <PythonCallback/>
        </EventTriggerInfo>

        <EventInfo>
            <Type>EVENT_VILYATHAR_FREESTUFF</Type>
            <Description>Oooh lovely!</Description>
            <LocalInfoText/>
            <WorldNewsTexts/>
            <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>BONUS_MARBLE</BonusType>
            <iBonusChange>1</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/>
            <PythonExpireCheck/>
            <PythonCanDo/>
            <PythonHelp/>
            <Button>Art/Interface/Buttons/button_g.dds</Button>
            <iAIValue>1000</iAIValue>
        </EventInfo>

really simple stuff. On turn 1, <iPercentGamesActive>100 (every game), <iWeight>-1 (automatically), the game will check the capital city tiles for one with <RouteType>NONE (no roads, railroads) and <ImprovementType>NONE (no mines, cottages, etc) and dump a <BonusType>BONUS_MARBLE there

shouldn't need to specify the tile doesn't have a bonus already, the game doesn't dump one on top of another .... it least I'm pretty sure it doesn't

you might not be able to see the resource yet, if that requires a tech you haven't acquired yet

this is a very long winded way of doing it, i bet a clever python coder could do it in a concise few lines ... I'll have a think and see if I can find something to steal. Sorry, write something better

first entry goes in eventtriggerinfos.xml, second in eventinfos.xml. Be careful to attach them at the end, keeping the xml file structure intact ... it has container header/footers marking 'the set of forms in this file' and 'the set of set of forms in this file' which won't take kindly to being ignored, a good xml checker is advisable

hope I'm hitting the sweet spot between making it easy and not insulting your intelligence, but you can clone these.

Important: EVENTTRIGGER_VILYATHAR_FREESTUFF can only work if it has a unique name, ditto EVENT_VILYATHAR_FREESTUFF which it controls. I think at the start of a game there is a list of events that will run, and duplicates are ignored, so if event 1 delivers ... errr salad and event 2 say, tinned anaconda slices, and they are both called eventtrigger_FREESTUFF only the (?) first one will trigger. You need eventtrigger_FREESTUFF_AGAIN as a top-level label to run a separate event. Seems obvious but I've done it. 1-watt-bulb.jpg

If the event is called

event_FREESTUFF

for both events, rather than

event_FREESTUFF and event_FREESTUFF_A (or whatever)

you'll get two copies of the same event triggering, so pair triggers with the same-named events for clarity and dullness. Caveat: funny titled events make you laugh years later

Oh no! The xml pixie has run off ...
 
This helps a lot. I was also asking if there was a way to make this able to be turned on and off in the menus somewhere at the start of a new game, but I suppose that is probably too much to ask without actually messing with the python. Thanks.
 
I was also asking if there was a way to make this able to be turned on and off in the menus somewhere at the start of a new game, but I suppose that is probably too much to ask without actually messing with the python. Thanks.
Yes, to add a new choice to the "Resources" custom map option, you'd have to make some changes to each map script that has that option (or at least to each map script that you want to use) and to the BonusBalancer class (Warlords\Assets\Python\CvMapGeneratorUtil.py).
[...] In the civ4bonusinfos xml you can pick which resources are put near players when balanced resources is selected. [...]
Not how it works I think. Maybe you refer to the bNormalize flag in XML; that says which resources can be added by normalizeAddFoodBonuses and normalizeAddExtras in the DLL, regardless of map options. The resources affected by the BonusBalancer are listed directly in the Python code:
Code:
class BonusBalancer:
   def __init__(self):
       self.gc = CyGlobalContext()
       self.map = CyMap()
       
       self.resourcesToBalance = ('BONUS_ALUMINUM', 'BONUS_COAL', 'BONUS_COPPER', 'BONUS_HORSE', 'BONUS_IRON', 'BONUS_OIL', 'BONUS_URANIUM')
       self.resourcesToEliminate = ('BONUS_MARBLE', )
With Balanced Resources, metals, horse and oil don't get placed randomly, and, instead, one instance of each of those resources is placed within 5 tiles of each starting tile. Actually, the option always goes from top to bottom and left to right within that 11x11 square and picks the first tile that satisfies the placement constraints. So the strategic resources will usually be somewhere 5 tiles to the west of each starting tile. :rolleyes: And Marble is, for some (probably misguided) reason, not placed at all.
 
There's wonders that insert resources close to the city hosting them, so rather than editing every map script (zzzzz) could use that workaround ... with a switch that disables it after turn 1?
 
Yes, to add a new choice to the "Resources" custom map option, you'd have to make some changes to each map script that has that option (or at least to each map script that you want to use) and to the BonusBalancer class (Warlords\Assets\Python\CvMapGeneratorUtil.py).Not how it works I think. Maybe you refer to the bNormalize flag in XML; that says which resources can be added by normalizeAddFoodBonuses and normalizeAddExtras in the DLL, regardless of map options. The resources affected by the BonusBalancer are listed directly in the Python code:
Code:
class BonusBalancer:
   def __init__(self):
       self.gc = CyGlobalContext()
       self.map = CyMap()
      
       self.resourcesToBalance = ('BONUS_ALUMINUM', 'BONUS_COAL', 'BONUS_COPPER', 'BONUS_HORSE', 'BONUS_IRON', 'BONUS_OIL', 'BONUS_URANIUM')
       self.resourcesToEliminate = ('BONUS_MARBLE', )
With Balanced Resources, metals, horse and oil don't get placed randomly, and, instead, one instance of each of those resources is placed within 5 tiles of each starting tile. Actually, the option always goes from top to bottom and left to right within that 11x11 square and picks the first tile that satisfies the placement constraints. So the strategic resources will usually be somewhere 5 tiles to the west of each starting tile. :rolleyes: And Marble is, for some (probably misguided) reason, not placed at all.

I had read somewhere that it was the bnormalize flag that set those, yes. Makes sense that it is wrong since editing the bnormalize flag and running a few tests with balanced resources on did not change which resources were generated lol. That's good to know. So one would have to go into the python code and change that "self.resourcesToBalance" line to read different ones, I suppose? Ah well. There are lots of ways to make the resource you want happen (including just plonking one in worldbuilder on single player mode...) but I was hoping to find a way to set it up and be able to toggle it on or off in the menu settings. I knew it was a stretch even before I asked, but I figured someone might know something I didn't. Thanks.
 
There are lots of ways to make the resource you want happen (including just plonking one in worldbuilder on single player mode...) but I was hoping to find a way to set it up and be able to toggle it on or off in the menu settings. [...]
There are also several ways to implement options; one could e.g. add another checkbox to the Custom Game screen or piggyback onto some unimportant existing game option. Unfortunately, however, the map scripts interact with the BonusBalancer in such an awkward way (initializing the balancer already when the Custom Game screen loads - i.e. before game options can be set - and later accessing the lists directly rather than call the isSkipBonus method) that I don't think that changes to the map scripts could be avoided.

You could easily put an alternative list of resources in BonusBalancer.__init__ and leave it commented out - so that switching between the two lists only requires the comment characters to be removed or added (and Civ to be exited if running).
Code:
self.resourcesToBalance = ('BONUS_ALUMINUM', 'BONUS_COAL', 'BONUS_COPPER', 'BONUS_HORSE', 'BONUS_IRON', 'BONUS_OIL', 'BONUS_URANIUM')
self.resourcesToEliminate = ('BONUS_MARBLE', )
# Uncomment to overwrite resource lists
#self.resourcesToBalance = ('BONUS_COW', 'BONUS_MARBLE', 'BONUS_INCENSE')
#self.resourcesToEliminate = ()
 
There are also several ways to implement options; one could e.g. add another checkbox to the Custom Game screen or piggyback onto some unimportant existing game option. Unfortunately, however, the map scripts interact with the BonusBalancer in such an awkward way (initializing the balancer already when the Custom Game screen loads - i.e. before game options can be set - and later accessing the lists directly rather than call the isSkipBonus method) that I don't think that changes to the map scripts could be avoided.

You could easily put an alternative list of resources in BonusBalancer.__init__ and leave it commented out - so that switching between the two lists only requires the comment characters to be removed or added (and Civ to be exited if running).
Code:
self.resourcesToBalance = ('BONUS_ALUMINUM', 'BONUS_COAL', 'BONUS_COPPER', 'BONUS_HORSE', 'BONUS_IRON', 'BONUS_OIL', 'BONUS_URANIUM')
self.resourcesToEliminate = ('BONUS_MARBLE', )
# Uncomment to overwrite resource lists
#self.resourcesToBalance = ('BONUS_COW', 'BONUS_MARBLE', 'BONUS_INCENSE')
#self.resourcesToEliminate = ()

That might be the best option then. Thanks for your help.
 
Top Bottom