Kael's Guide to XML Changes in Beyond the Sword

A Modders Guide to Beyond the Sword

About the authors:
Kael - Lead designer of the Beyond the Sword scenario Fall from Heaven: Age of Ice
Impaler[WrG] - Lead designer and programmer of the Unit Art Styles and Modular XML features of BtS, Team Leader of the CCCP (Civ4 Community Core Project)
Solver - Design Consultant and programming contributor for Beyond the Sword

We’ve read articles describing the new game play that is coming in Beyond the Sword (BtS), and tantalizing hints about what it will offer. This article was written to detail some of the new features of BtS that may not mean much to the average player, but will be important to mod makers.

Disclaimer (21/07/2008): Until BtS ships nothing is locked down. Everything in here is subject to change. Anything that is or isn’t in BtS as it is recorded here may be due to last minute changes or my own mistakes in documenting.



1.0 Less Grunt Work

First off, two things BtS removes. Mod makers are very familiar with the Civ4FormationInfos.xml and Civ4CityLSystem.xml files. In vanilla Civ4 and Warlords, units added to the game have to be added to the formations file, and any building you want to show up in the city has to be added to the CityLSystem file. BtS does away with the need to update these files with each new entry.


1.1 CIV4FormationInfos.xml

Instead the formation file includes formation types. Then when you create a new unit you define its formation type (ex: FORMATION_TYPE_ANIMAL) and it uses that definition for formations with that unit instead of having to be defined per unit. So the following would be an attribute of a unit in the CIV4UnitInfos.xml file:


I’ll include a copy of one of the definitions of a formation file here. But in general modders won’t need to ever touch it again. Personally, I modified mine to add some larger groups than the default. But even in this it was easier than in Vanilla or Warlords because I just created the new formation and assigned it to FORMATION_TYPE_DEFAULT (or whatever formation type I wanted to use) and all the units began using it.

    <Name>IDLE (1)</Name>


1.2 CIV4CityLSystem.xml

Likewise the LSystem size of a building is set in its art definition (ex: LSYSTEM_3x2) instead of having to define every building in the LSystem file.


That’s it. The game takes care of the rest.


2.0 Modular XML

Ever wanted to add a new unit to a mod without touching any of the original files? Or wanted to add new objects to an existing mod, but then the base mod changes and you have to redo your work? Modular XML allows the game to load several different XML files as a single file.

With it you can add a new unit, unit class and unit art file that only contains the data for your new unit. Then if the base mod changes it won’t effect your files and you don’t have to re-update your changes.

This is even more promising when considering the ability to merge XML mods. You could take 3 different mods that each introduce a new civilization, unique units and buildings and play them together by just copying them into the appropriate directory. No need to merge code and if the makers of those mods update their files it’s easy enough to reapply without affecting everything else in your game.

For more details on Modular XML, check out Appendix A of this guide.


3.0 Unit Art Styles

There has been a lot of amazing work done creating new unit art for civilization 4. Many of these units have been implemented as “flavor” units, sharing identical stats but added to the game to vary the artwork of different civilizations. Unfortunately this requires a new unit to be added to the game, a swordsman (for example) that is a duplicate in every way except its art definition.

BtS allows us to define unit art types, similar to the building art types in warlords. With it you can have one unit definition but configure different civilizations to use different art for that unit. So the Greek scout can be made to look different than an Aztec scout without adding a new unit to the game.

There are 3 steps required to enable this.


3.1 Step 1: CIV4CivilizationsInfos.xml

In this file we need to define the civilizations Unit Art Style as follows:


This is very similar to the way city art styles were defined in warlords but added as a separate attribute so modders can use different unit and city building styles. A NONE value will cause the Civ to use all default Unit Art.


3.2 Step 2: CIV4UnitArtStyleTypeInfos.xml

This is a new XML file in BtS. It contains the definition for the Unit Art Style and allows a new unit art meshes to be used for a given unit. In the example below the ART_DEF_UNIT_ARCHER_EURASIAN is the Early art definition used for an Archer and ART_DEF_UNIT_ARCHER_EUROPEAN is used in the middle and late periods. The Archer like most units has only one UnitMesh as specified on its CIV4UnitInfos.xml element. But units can actually have any number of Meshes, the Settler units are the only Original game units to use more then one Mesh and to modify these simply list the replacement Meshes as <UnitMeshGroup> elements, they will be matched in the order with the CIV4UnitInfos meshes and replace it one for one, any number of Meshes can be present in a Unit and all can be substituted in this way.

Any Unit not given replacements for a StyleType will simply be defaulted to the Art from the UnitInfos.xml file and any individual ARTDEFs can be referenced any number of times and in as many different StyleTypes as desired allowing considerable sharing and creation of Styles which differ only at certain time periods to reflect cultures branching and merging.

                <MiddleArtDefineTag> ART_DEF_UNIT_ARCHER_EUROPEAN </MiddleArtDefineTag>
                <LateArtDefineTag> ART_DEF_SETTLER_MALE_EUROPEAN </LateArtDefineTag>
                <MiddleArtDefineTag> ART_DEF_SETTLER_MALE_EUROPEAN </MiddleArtDefineTag>
                <EarlyArtDefineTag>ART_DEF_SETTLER_FEMALE </EarlyArtDefineTag>
                <LateArtDefineTag>ART_DEF_SETTLER_FEMALE </LateArtDefineTag>
                <MiddleArtDefineTag>ART_DEF_SETTLER_FEMALE </MiddleArtDefineTag>


3.3 Step 3: CIV4ArtDefines_Unit.xml

Just as in Civ4 the Unit Art Information has to exist for the unit. But instead of using the default one assigned to that unit in the Civ4UnitInfos.xml (ART_DEF_UNIT_ARCHER for example) Unit Art Styles allowed us to use a alternate one such as this:

        <ShadowAttachNode>BIP Pelvis</ShadowAttachNode>

Note that the unit button graphic is defined on the UnitArtInfo, it is no longer set in the CIV4UnitInfos.xml file. This allows us to use different buttons for different unit art styles. This change will also require modders converting older mods to BtS to move all their button info into the art file.

By modifying the SDK you can create alternative types of StyleUnit logic with their own xml files and logic structures such as Units which show different Artwork based on how heavily they are damaged or the presense of specific Promotions.


4.0 Mod Specific Interface

Firaxis’ default blue interface is pretty good but isn’t appropriate to all mods. It is possible to change your interface in vanilla Civ4 and Warlords but it is a game setting and isn’t moddable. BtS changes that. Modders can change the color of the interface, fonts, bars, everything to design the interface they want for their mod.

First you will need the following entry in your CIV4ArtDefines_Misc.xml file:


Anything in the “..\Sid Meier's Civilization 4\Resource” subdirectory’s can be overwritten by matching files placed in the “..\Sid Meier's Civilization 4\Beyond the Sword\Mods\[ModName]\Resource” container. The Resource container must contain a Civ4.thm file that redirects it to the appropriate mod specific resources as follows:

// *** Control Bitmap Theme file

// Set the resource 
resource_path    "Mods/[ModName]/Resource";

// Setup common properties
include            "Mods/[ModName]/Resource/Themes/Civ4/Civ4Theme.thm";

Detailing all the possible options that can be themed is beyond the scope of this document, it is basically everything that can be done with earlier versions, but now these themes can be included with mods instead of being applied to the whole game. If you are interested in creating a theme for your mod you can start now by creating that theme in the vanilla or warlords resource container (make sure to make a backup copy of the original). Then when BtS comes out you can copy it into your mods directory and begin using it.


5.0 New python functions

Firaxis has been hard at work adding new python functions, places where we can intercept functions and apply our own logic to keep things from happening (as in disabling units from being able to enter certain plots in unitCannotMoveInto) or modify the actions (such as creating new experience point requirements in getExperienceNeeded).


5.1 CvEventManager.py

These python functions don’t inherently make the game better. But they do offer an opportunity for creative modders to do amazing things. With a few lines of python it becomes easy to intercept nuke explosions and warn the world of their use, increase their effect, or even trigger massive post-apocalyptic effects.

  • plotFeatureRemoved - Passed the plot, the feature that was removed and the city (if the plot was a city)
  • plotPicked - ? not called from the SDK
  • nukeExplosion - Passed the plot and the unit that caused the explosion
  • gotoPlotSet - ? not called from the SDK
  • cityHurry - Called whenever a production is hurried in a city
  • unitSpreadReligionAttempt - Passed the unit, the attempted religion and if it was successful or not
  • UnitGifted - Passes the unit, the old owner of the unit and the plot that unit is in
  • unitBuildImprovement - Passed the unit, the improvement type they are building and if it is complete or not
  • corporationFounded - Passed the corporation and the founding player
  • corporationSpread - Passed the corporation, the owning player and the city
  • corporationRemove - Passed the corporation, the owning player and the city
  • playerChangeStateReligion - Passed the player, the new religion and the old religion
  • playerGoldTrade - Passed the player giving the gold, the player receiving and the amount exchanged


5.2 CvGameUtils.py

  • isVictory - Allows a check to see if any player is allowed to achieve victory yet
  • canDeclareWar - To give modders the option to enable/disable war declarations dynamically
  • unitCannotMoveInto - To block moving into plots based on any criteria
  • canBuild - To block the creations of improvements based on any criteria
  • cannotFoundCity - Passed the player and the coordinates of the plot
  • cannotSpreadReligion - To block the ability to spread religions
  • citiesDestroyFeatures - To enable or disable feature destruction when cities are created
  • canFoundCitiesOnWater - To allow cities to be created on water tiles
  • doCombat - To replace the SDK combat function with a python process
  • getConscriptUnitType - To provide the unit type provided through conscription
  • getCityFoundValue - To modify the AI’s preference for city placement
  • canPickPlot - ? not called from the SDK
  • getUnitCostMod - To modify the cost of units dynamically
  • getBuildingCostMod - To modify the cost of buildings dynamically
  • canUpgradeAnywhere - To allow the unit to be upgraded anywhere
  • getWidgetHelp - To add additional text to mouse over help
  • getUpgradePriceOverride - To replace the upgrade price with a new value
  • getExperienceNeeded - To replace the experience system with a different values

This is in addition to additional data sent to other python functions. For example, the onUnitMove function now has the old plot passed to it as well. So if you want to perform a python action when a unit leaves his cultural borders that is now easier to do.


6.0 Help Attribute

This may seem like a minor thing but it is so effective and easy to use that it deserves special mention. There is a new schema attribute called Help on Traits, Units, Promotions, Terrain, Buildings, Bonuses, Features and Technologies. Help is intended to hold a text string such as TXT_KEY_UNIT_GIANT_DEATH_ROBOT_HELP and anything in that string is displayed in mouse over help text for that object.

In earlier versions if modders wanted to add additional help text they would need to modify the SDK. This is so much easier.


7.0 Promotions can change the look of models

I am going to apologize beforehand for the lack of detail in this section. I’m not a graphics guy and I haven’t used this feature myself. But I have toyed with some of the units that use it. Basically it is possible to have a model changed based on the promotions it has.

For example, you could make a bomber model that, if it has the correct promotion, shows a bomb strapped to its bottom. Then if the promotion is removed, say by a bombing action, the model would be changed so the bomb is no longer visible. The same could be done in showing swords and axes in units hands, armor they are wearing, units surrounded in clouds of putrid gas, radiation, etc.

I will stress that this isn’t as simple as making a promotion, pointing it to model art and having everything work. The model has to be made with the “attachment” built into it. By default it isn’t displayed, but with the promotion it shows up. So it will be significant modeling work to use this function, but I have no doubt the amazing artists here at CivFanatcis will have a lot of fun with this feature.


8.0 Events

Random events are one of the new features in Civ4: Beyond the Sword. The game ships with over 150 events, which vary from happiness and diplomatic bonuses to free promotions and technological breakthroughs. The event system provides a great foundation for modders to build open, as all events can be modded and new ones can be added.

You can create a wide array of possible events through XML modding only, but events can also be enhanced by Python for more versatility. Appendix B of this guide has some examples of events that can be modded in. The events described therein, along with some others, can be found in an event mod created by Solver. Think of the mod as an addendum to this guide, if you will. It can be found at (mod will linked after BtS releases).

It’s important to understand the two basic building blocks of the event system; triggers and events. “Triggers” are a collection of parameters indicating conditions when they can activate. Triggers check whether you have the required technologies, population, etc. If the trigger’s conditions are met, it has a chance of activating. When a trigger is activated, it gives the player choice between one or more “events” (well, when there is only one event, there’s no choice). Events themselves are what provides the specific results that then affect the player.

Players may be inclined to think of the event system as consisting of “events” and “choices” – that’s not really accurate. Every choice is a separate event, and a trigger is what gives those choices.

As most other things in Civ4, events are primarily handled in the SDK. Events are described by the CvEventInfo class, which mimics the XML description of events. Appendix B has a description of event tags in the XML file. If you can read C++, you may want to take a look at the definition of CvEventInfo. The correspondence between member functions of that class and the XML values should be fairly obvious.

Event triggers are kept in Civ4EventTriggerInfos.xml and that file, along with triggers in general, will be described after the event description explanations.

For more details on events, check out the Event Guide in Appendix B.


9.0 The Python Callback Defines file

BtS is fast. One of the things Firaxis did to speed up the game was implement a PythonCallbackDefines.xml file. That file has entries for many CPU intensive python functions such as the following:


By default (as configured above) the Found City python routine will never be called. If you want to use that function in your mod you will need to include a modded copy of the PythonCallbackDefines.xml with the iDefineIntVal set to 1 to enable that python callback. The following python functions are disabled by default:


Keep in mind that these python functions were selected because they called frequently enough to constitute a significant processor cost if they are enabled. So if you will be enabling them for use in your mod expect that slower computers may suffer a performance hit.

This article won’t cover all of the new attributes in BtS. But I did pull the new attributes on some of the most frequently modded elements in the game. Most are self explanatory for those familiar with Firaxis’ naming conventions, and I included notes with those of special interest.

Many of these attributes were added for a specific scenario in BtS (and so that modders could easily use these functions). Don’t assume that just because an attribute exists here that it is used in the epic game.


10.1 Units

  • Help - See section 6.0 for details (Optional)
  • bQuickCombat - Forces that unit to use quick combat
  • bSpy - Unit can perform espionage missions in opponents territory
  • bCanMoveAllTerrain - If the unit can move on all terrain (including land and water tiles)
  • bRenderAlways - ? not in the SDK
  • bSuicide - If true the unit dies after attacking
  • bLineofSight - Only allows the unit to see in the facing direction
  • bHiddenNationality - If true other players cant tell the unit nationality and it can attack without war
  • bAlwaysHostile - The unit is an enemy regardless of diplomacy
  • FlankingStrikes - Allows the units to perform flanking strikes against specified unit classes
  • CorporationSpread - Allows the unit to spread corporations
  • PrereqCorporation - The unit can only be trained in cities with the specified corporation
  • iAdvancedStartCost - The cost to create the unit through advanced start
  • iAdvancedStartCostIncrease - Additional cost per unit bought through advanced start
  • bNoRevealMap - Unit may not reveal unexplroed terrain
  • iAirUnitCap - How many air capacity the unit takes up in a city
  • iDropRange - If the unit can be used as a paratrooper
  • iEspionagePoints - Amount of espionage provided by a great spy work
  • TerrainPassableTechs - Allows the ability to move through the terrain if the appropriate tech is known
  • FeaturePassableTechs - Allows the ability to move through the feature if the appropriate tech is known
  • iCombatLimit - Max damage this unit can do as a percent, set to 100 it can kill units
  • TerrainAttacks - Modifier when attacking into the specified terrain
  • FeatureAttacks - Modifier when attacking into the specified feature
  • FormationType - Type of Formation used, See section 1.1 for details
  • Button - The Button attribute has been removed from the Unit definition to the UnitArtDef


10.2 Promotions

  • Help - See section 6.0 for details
  • LayerAnimationPath - This is used to allow promotions to modify the look of units
  • StateReligionPrereq - Makes the promotion require the selected state religion
  • iAirRangeChange - Modifies the air range of the unit
  • iInterceptChange - Modifies the interception chance of the unit
  • iEvasionChange - Modifies the evasion chance of the unit
  • iCargoChange - Modifies the cargo capacity of the unit
  • TerrainAttacks - Percentile modifier when attacking into the specified terrain
  • FeatureAttacks - Percentile modifier when attacking into the specified feature


10.3 Buildings

  • Help - See section 6.0 for details
  • bStateReligion - if set to true the building can’t be built if the player doesn’t have a state religion
  • PrereqCorporation - requires the specified corporation
  • FoundsCorporation - building the building will found the specified corporation
  • GlobalCorporationCommerce - values set here will modify the commerce rates for corporations
  • NoBonus - If the building blocks are resource
  • DiploVoteType - replaces bDiploVote
  • bAllowsNukes - if a building can allow nukes, similar to current projects
  • iAdvancedStartCost - The cost to create the building through advanced start
  • iAdvancedStartCostIncrease - Additional cost per building bought through advanced start
  • iGoldenAgeModifier - Percentage change the building makes to the length of golden ages for the owner
  • iAirUnitCapacity - If the building effects the amount of air units that can be stored in the city
  • iEnemyWarWearinessModifier - Enemies suffer this percentage change to their war weariness
  • iForeignTradeRouteModifier - Percentage change to the intercontinental trade route yield
  • iEspionageDefense - Percentage defense against spy missions
  • RiverPlotYieldChanges - Modified the yields of river tiles for that city
  • ImprovementFreeSpecialists - Grants free specialists for each occurrence of improvement


10.4 LeaderHeads

  • iEspionageWeight - Sets that AI leaders preference for espionage
  • iFreedomAppreciation - Sets the AI leaders preference for colonization
  • FavoriteReligion - Sets the AI leaders favorite religion


10.5 Technologies

  • Help - See section 6.0 for details
  • iAdvancedStartCost - The cost to start with the tech through advanced start
  • iAdvancedStartCostIncrease - Additional cost per tech bought through advanced start
  • bRiverTrade - Allows trade along rivers


10.6 Features

  • Help - See section 6.0 for details
  • iTurnDamage - Causes the feature to do damage to units in the tile
  • bVisibleAlways - If the feature is always displayed
  • bNukeImmune - If the feature is unaffected by nukes
  • OnUnitChangeTo - If a unit moves into the tile the feature changes to the specified feature
  • iAdvancedStartRemoveCost - Cost to remove the feature through advanced start


10.7 Improvements

  • Help - See section 6.0 for details
  • iAdvancedStartCost - The cost to create the unit through advanced start
  • iAdvancedStartCostIncrease - Additional cost per improvement bought through advanced start
  • iFeatureGrowth - Modifies the feature growth rate in the tile
  • iHappiness - If the improvement grants a happiness bonus
  • bOutsideBorders - If the improvement can be built outside of the players borders


11.0 New Game Parameters

11.1 New Global Defines

There were 17 new global defines in Warlords. It’s fair to say that Firaxis has outdone themselves here too, giving modders easy control over even more functions. Remember that all Global Define changes should be made in GlobalDefinesAlt.xml.

  • RECON_VISIBILITY_RANGE - Specifies the range for recon missions
  • CITY_FREE_CULTURE_GROWTH_FACTOR - Modifier to the culture growth rate in tiles
  • GREAT_WORKS_CULTURE_TURNS - Great work culture will be divided out over this many turns
  • NUM_CORPORATION_PREREQ_BONUSES - The maximum amount of bonuses a corporation can require
  • NUM_ROUTE_PREREQ_OR_BONUSES - Maximum amount of Bonus requirements for a route
  • MAX_NATIONAL_WONDERS_PER_CITY_FOR_OCC - Controls how much clothing the leaders have, don’t look at Pacal naked!
  • POWER_HEALTH_CHANGE - Effect of power on the cities health
  • INTERCEPTION_MAX_ROUNDS - Maximum combat rounds during interception
  • MAX_INTERCEPTION_DAMAGE - Maximum amount of damage done during interception
  • MIN_INTERCEPTION_DAMAGE - Minimum amount of damage done during interception
  • RANGE_COMBAT_DAMAGE - Base ranged damage, modified by the relative strength of the two units
  • FOUND_CORPORATION_CITY_RAND - The higher the number the more random the assignment of corporations
  • GOLDEN_AGE_GREAT_PEOPLE_MODIFIER - Modifier to great person growth during golden ages
  • OVERSEAS_TRADE_MODIFIER - Modifier to trade between continents
  • DEFY_RESOLUTION_POP_ANGER - Amount of anger generated by AI leaders when you defy a resolution
  • DEFY_RESOLUTION_ANGER_DIVISOR - The higher this is, the longer it takes for AI leaders to forget their defy resolution anger
  • TEMP_HAPPY - Amount of happiness gifted from events
  • CORPORATION_FOREIGN_SPREAD_COST_PERCENT - Modifier to corporation spread costs
  • MAX_INTERCEPTION_PROBABILITY - Maximum chance of interception
  • MAX_EVASION_PROBABILITY - Maximum chance of evasion (you knew that right!)
  • FOW_WAS_VISIBLE_COLOR - ? Not in the SDK, I assume this controls the color of the Fog of War
  • FOW_MINIMAP_WAS_VISIBLE_COLOR - ? Not in the SDK, I assume this controls the color of the Fog of War on the minimap
  • CITY_SCREEN_FOG_ENABLED - If this is set to true then fog appears on the city screen
  • AI_CAN_DISBAND_UNITS - Set to false to keep the AI from being able to disband units
  • CITY_SCREEN_CLICK_WILL_EXIT - If clicking on the screen will exit the city screen
  • WATER_POTENTIAL_CITY_WORK_FOR_AREA - If cities can work water tiles
  • LAND_UNITS_CAN_ATTACK_WATER_CITIES - If land domain units are able to attack cities on water
  • CITY_MAX_NUM_BUILDINGS - If modders would like to set a maximum number of buildings per city
  • RANGED_ATTACKS_USE_MOVES - If performing a ranged attack uses the units movement
  • ROUTE_Z_BIAS - ? Not in the SDK
  • RIVER_Z_BIAS - ? Not in the SDK
  • NEW_CITY_BUILDING_VALUE_MODIFIER - Modifier to the AI’s preference to add a building to a new city
  • IGNORE_PLOT_GROUP_FOR_TRADE_ROUTES - If this is set the player doesn’t need to own tiles to trade through them
  • EVENT_PROBABILITY_ROLL_SIDES - The higher this number the less likely events are to occur
  • FIRST_EVENT_DELAY_TURNS - Events won’t trigger any earlier than the turn configured here
  • CIVILOPEDIA_SHOW_ACTIVE_CIVS_ONLY - If the pedia only displays active civs
  • CITY_AIR_UNIT_CAPACITY - Default air unit capacity of cities
  • COLONY_NUM_FREE_DEFENDERS - Amount of units gifted when a colony is split off
  • SHIP_BLOCKADE_RANGE - Range of tiles an enemy ship keeps trade routes from going through
  • PATH_DAMAGE_WEIGHT - The higher this is the more the AI will avoid pathing through damaging tiles
  • RENDER_AREABORDER_UNDER_FEATURES - If the game should display borders under features
  • RENDER_GLOBEVIEW_CLOUDS - If the game should display clods when zoomed out
  • RENDER_WATER - If the game should actively render water
  • USE_MODDERS_PLAYEROPTION_1 - Forces player option 1 as defined in CIV4PlayerOptionInfos.xml
  • USE_MODDERS_PLAYEROPTION_2 - Forces player option 2 as defined in CIV4PlayerOptionInfos.xml
  • USE_MODDERS_PLAYEROPTION_3 - Forces player option 3 as defined in CIV4PlayerOptionInfos.xml

The following defines give modders more control over camera settings:


The following defines are applied as percentage cost adjustments to the associated espionage mission:


The following defines are used when costing options in advanced start:


The following Global Defines have new values in BtS:

  • CIV4_VERSION - Changed to 300
  • SAVE_VERSION - Changed to 300
  • BASE_GOLDEN_AGE_UNITS - Changed from 2 to 1
  • UNIT_TRAIL_RESOLUTION - Changed from 10.0 to 5.0

The following Global Defines have been removed from BtS:



11.2 New ini options

BtS also contains some new settable options in your <modname>.ini file. Those who have been modding for a while have run across CustomAssets compatibility problems. The issue is that a modder may install his mod to the CustomAssets directory, or the player may change files there. Those changes may be compatible with the epic game so the user doesn't notice a problem until they go to load a mod and it doesn't work. I can't tell you how many people post with mod load problems caused by this. I know there is even a greater percentage that never post at all, they just think the mod doesn't work.

I would highly recommend that every modder set NoCustomArt and and NoCustomAssets to 1 for your BtS mods to keep these kind of issues from occuring.

  • NoCustomArt - set to 0 CustomAssets art resources are loaded, set to 1 they aren't loaded
  • NoCustomAssets - set to 0 CustomAssets XML and python resources are loaded, set to 1 they aren't loaded
  • NoCustomScenario - set to 0 custom scenarios are allowed, set to 1 they are blocked
  • ForceScenario - set to 1 to force a scenario, 0 to allow anything (free play, custom game, etc)
  • NoTeams - 0 to allow teams, 1 to block teams
  • ForceStandardEra - 0 to allow era selection as normal, 1 to force the game to start in the standard era
  • SkipMainMenu - 0 to allow the main menu to play as normal, 1 to skip it


12.0 What can you do now?

It is a good time to review everything you have in your mod and consider cutting elements that may not be working as well as you hoped. For SDK and Python mods review your code and look for ways to clean it up or remove sections that you can live without.

If you don’t keep a changelog for your mod then you should go through and document your changes. I would recommend running Beyond Compare (http://www.scootersoftware.com/) between your files and base version (if you are a Warlords mod then between your files and the Warlords files, if you are a vanilla mod then between your mod and the vanilla files). There are a lot of minor tweaks that we make and forget about; this will let you capture all those changes.

This article should give you enough information about what is coming in BtS to begin planning additions to your mod. Events that you would like to add, new python functions you would like to take advantage of, etc. Maybe even redo the current way you are doing some thing so they use the new features. All of that design work can be done now. Before you play BtS ask yourself how you would like to see events implemented (from a game play perspective) and what sort of events you would like to see. When BtS comes out you may be surprised to see that they are as you envisioned or better, or you might like your idea more and you will have everything you need to try your idea out.


13.0 Converting to Beyond the Sword

Even total conversion mods will find it easier to move their changes into BtS files rather to try to convert their files into BtS files. For example, you do not want to try you make your CIV4UnitInfos.xml BtS compatible. Instead take the default BtS CIV4UnitInfos.xml and start adding your changes to it. Although it seems faster to do the former in the long run you will be fighting unexpected differences, possibly even crashes. Better to start clean.

Secondly, if you are converting a mod with a lot of changes, don’t add everything at once.

Convert a few, units or buildings, add in a new civ or two and then play a game. Make sure everything is working before you add more. There is nothing as frustrating as spending a large amount of time converting only to find a generic crash that you have to start isolating by backing out all the changes you just made.

Examine the XmlLoadUtilitySet.cpp file to see all the files types the game loads, a good rule of thumb you should port your mod in the order these files load to avoid dangling reference errors, thus Techs come early followed by Buildings then Units Classes, then the Types, then Leaders and Civilizations near last.

If you aren’t a total conversion mod seriously consider the Modular XML feature of BtS. At the very least it will keep you from having to convert your mod each time Firaxis releases a patch (since changes to their core files won’t affect your files). It also makes it easier for fellow modders and players to integrate your mod with others.

If your planning to port a large mod to BtS coordinate with makers of the components you’ve integrated in the past to see if they will be going Modular for BtS thus saving you time and effort. For your own unique contents start off by separating it from the games original contents, then create a module that consists of modifications to the original contents if you have any and bit by bit convert and modularize the new materials adding them into the mod and testing as you go and adding and updating modules made by others.

The BtS SDK files naturally come on the CD, they wont be available until the game is in stores, porting mods to the Warlords code base will be tricky in some situations due to the changes in many function arguments and the elimination of a few functions entirely. Fortunately several beta testers are already working on porting code, the CCCP (Civ4 Community Core Project) headquartered at (http://forums.civfanatics.com/forumdisplay.php?f=195) is an effort to make a DLL combining many popular extensions to the code in such a way as to make them all optional and defaulting to have no effect. Its distributed as a kind of Skeleton mod consisting of just the DLL, code base and modified Schemas. Moders who cant compile their own DLL can then use it as base to start adding their own contents and activating just the specific features they want. Alternatively those that can code can add their own mods thus getting a jump on BtS porting. The CCCP is an ongoing effort, everyone is encouraged to contribute and share their code modifications for integration into the Project. The BtS version of CCCP should be available as soon as BtS hits store shelves allowing for immediately play testing and use in porting.

Python will not be completely reliable either due to changes in the callback interface, but it should be simpler to get these running again as desired due to their interpreted nature and ease of coding.


14.0 Appendix A - Modular XML Loading

14.1 Introduction

Modular XML Loading (MXMLL) is a new feature in BtS designed to assist mod makers in sharing and combining their modifications. Those familiar with the XML files from Vanilla Civ4 and Warlords know that the game loads from several dozen different XML files, one file for Buildings, and one for Units etc. Before it was only possible to load one file of each type and that file had to reside in a very specific file pathway and be of exactly the right name to load correctly. MXMLL is an optional way to create mods that circumvent these restrictions; using it you can create 'Modules' small self-contained packages that can all be loaded simultaneously. Allowing the user an easy way to play many mods at the same time. This guide is intended for mod makers, it will instruct you in the rules, structures and best practices involved in making modules and converting existing mods into the modules format. Once a module is made no one need to use tedious cutting and pasting to combine mods, and modders will be able to update their objects without affecting the objects made by others.


14.2 Making Modules

Because most previous mods have been in the "Monolithic" format, aka one file of each type, most new Modules will be made by one of three strategies:

  1. Extraction of existing content pieces from Warlords mods into BtS compatible modules perhaps with an eye towards breaking the mod down completely into a 'library' of modules.
  2. Then theirs large scale whole mod conversion into module format for purposes of organization and size reduction.
  3. Creation of new content from scratch.

The strategy you use will depend on the nature of your modification. Makers of 'components' and content that is meant to be used in a wide variety of larger mods will want to take the library approach. For example extensions to the new Unit Art Style feature could be packaged as a library of Style Types, each module containing a list of all the Art for one Style along with the art itself. It’s then easy for the user to drop that module in and get the effects. For mods that grow increasingly complex and interdependent with cross references such as new techs required by new units that require new resources to build it becomes harder to make modules that can stand alone. In these instances modularizing may be more useful as a means of organizing large files by breaking them up into categories. Team projects can benefit from the distributed nature of the work as team members work on separate files without needing to remerge them (for particularly large project Version control Software is highly recommended). Lastly fans of mods can more easily submit modules that implement their recommended changes/fixes and these can be tested and integrated faster.


14.3 How it Works

MXMLL operates entirely during the xml-loading portion of the game. During loading the game reads data for each file type one by one so that it can determine the count of each type of game element and properly index them. For each file the games "Base" content loads as normal from the default file pathways your familiar with from Warlords. Then there is a check on a Config parameter "ModularLoading" if 1 (true) then a search is made through the new "Modules" folder within the Mod being played and custom assets. A regular expression is used to determine the type of each XML file and only those of the appropriate type are loaded. Elements within the Modules load after Base content and can step-on (replace) Base data that has a matching Type Tag name, modules will also step on each other with the last one to load being the one seen in game. Module loading order is not affected by whether the module resides in Custom Assets or the Mod itself, either could step on the other so simply avoid ever having two conflicting modules.


14.4 What Doesn’t Work

Unfortunately there is one class of files that don't work with MXMLL, any that deals with Sound and Audio data. These have not been made compatible, also several file types like MissionInfos.xml and CommerceTypes.xml are linked with Enums in the SDK thus any extensions of these files would have no effect without a corresponding modification in the SDK. It's recommended you not try to make Modules with these files.


14.5 Naming Rules

The file naming system that must be used to get a modular xml file to load is strict but simple and universal. Because * is a multi-character wild card you can place a descriptive name at the front such as Ninja_CIV4UnitInfos.xml. Also there can be any number of intervening directories under the xml directory so data can be nested to your hearts content example "modules/Custom Units/Ninja/Ninja_CIV4UnitInfos.xml". This is in contrast to the games default loading, which was and still is very rigid in its structure. Failure to have a file match the regular expression is the most likely reason for content to silently (no load warning) not show up in the game.


14.6 Supported File Types

The following types of files are supported, in all instances the game will search and find files matching modules/*_TYPE.xml ware TYPE is one of the following strings.

Spoiler for Supported File Types:

  • CIV4ArtDefines_Interface -
  • CIV4ArtDefines_Movie -
  • CIV4ArtDefines_Misc -
  • CIV4ArtDefines_Unit -
  • CIV4ArtDefines_Building -
  • CIV4ArtDefines_Civilization -
  • CIV4ArtDefines_Leaderhead -
  • CIV4ArtDefines_Bonus -
  • CIV4ArtDefines_Improvement -
  • CIV4ArtDefines_Terrain -
  • CIV4ArtDefines_Feature -
  • CIV4BasicInfos -
  • CIV4NewConceptInfos -
  • CIV4CityTabInfos -
  • CIV4CalendarInfos -
  • CIV4SeasonInfos -
  • CIV4MonthInfos -
  • CIV4DenialInfos -
  • CIV4InvisibleInfos -
  • CIV4UnitCombatInfos -
  • CIV4DomainInfos -
  • CIV4UnitAIInfos -
  • CIV4GameText -
  • GlobalDefines -
  • PythonCallbackDefines -
  • CIV4AttitudeInfos -
  • CIV4MemoryInfos -
  • CIV4GameSpeedInfo -
  • CIV4TurnTimerInfo -
  • CIV4WorldInfo -
  • CIV4ClimateInfo -
  • CIV4SeaLevelInfo -
  • CIV4AdvisorInfos -
  • CIV4TerrainInfos -
  • CIV4EraInfos -
  • CIV4UnitClassInfos -
  • CIV4SpecialistInfos -
  • CIV4VoteSourceInfos -
  • CIV4TechInfos -
  • Civ4FeatureInfos -
  • CIV4ReligionInfo -
  • CIV4AnimationInfos -
  • CIV4AnimationPathInfos -
  • CIV4PromotionInfos -
  • CIV4TraitInfos -
  • CIV4GoodyInfo -
  • CIV4HandicapInfo -
  • CIV4CursorInfo -
  • CIV4CivicOptionInfos -
  • CIV4UpkeepInfo -
  • CIV4HurryInfo -
  • CIV4SpecialBuildingInfos -
  • CIV4CultureLevelInfo -
  • CIV4BonusClassInfos -
  • CIV4VictoryInfo -
  • CIV4BonusInfos -
  • CIV4CorporationInfo -
  • Civ4RouteInfos -
  • CIV4ImprovementInfos -
  • CIV4BuildingClassInfos -
  • CIV4BuildingInfos -
  • CIV4SpecialUnitInfos -
  • CIV4ProjectInfo -
  • CIV4CivicInfos -
  • CIV4LeaderHeadInfos -
  • CIV4ColorVals -
  • CIV4PlayerColorInfos -
  • CIV4EffectInfos -
  • CIV4EntityEventInfos -
  • CIV4BuildInfos -
  • CIV4UnitInfos -
  • CIV4UnitArtStyleTypeInfos -
  • CIV4CivilizationInfos -
  • CIV4Hints -
  • CIV4MainMenus -
  • CIV4SlideShowInfos -
  • CIV4SlideShowRandomInfos -
  • CIV4WorldPickerInfos -
  • Civ4SpaceShipInfos -
  • CIV4YieldInfos -
  • CIV4CommerceInfo -
  • CIV4GameOptionInfos -
  • CIV4MPOptionInfos -
  • CIV4ForceControlInfos -
  • CIV4ThroneRoomCameraInfos -
  • CIV4ThroneRoomInfos -
  • CIV4ThroneRoomStyleInfos -
  • CIV4EventInfos -
  • CIV4EventTriggerInfos -
  • Civ4RouteModelInfos -
  • CIV4RiverInfos -
  • CIV4RiverModelInfos -
  • CIV4WaterPlaneInfos -
  • CIV4TerrainPlaneInfos -
  • CIV4CameraOverlayInfos -
  • CIV4ProcessInfo -
  • CIV4EmphasizeInfo -
  • CIV4MissionInfos -
  • CIV4ControlInfos -
  • CIV4CommandInfos -
  • CIV4AutomateInfos -
  • CIV4VoteInfo -
  • CIV4CameraInfos -
  • CIV4InterfaceModeInfos -
  • CIV4FormationInfos -
  • CIV4AttachableInfos -
  • CIV4DiplomacyInfos -
  • Civ4QuestInfos -
  • Civ4TutorialInfos -
  • CIV4EspionageMissionInfo -


14.7 Schema

The main drawback of this directory flexibility is that every XML file still needs to be validated before loading and Civ demands the Schema be in the same directory as the file it’s validating. If not the loading fails and a warning is thrown which you can OK past to continue loading but their will then likely be subsequent "ITEM NOT FOUND" warnings as the other files associated with the module are left with dangling references. In some instances its possible to just copy the original Schema files unmodified and run off that but it will eventually lead to hard to fix cross-validation errors when you start to use any modified Schema, thus its recommend that all module schemas be renamed with a simple "module name_" at the front to match the module the module their in. This will ensure that the Schema is only used locally and doesn’t break other modules. Remember to update the header of the files that use that Schema so they will reference it properly. This is especially true for Modules that are going to use a new XML tag that will be read with a modified DLL, the local Schema will allow your module to load under a unmoded DLL and will isolate the modified Schema from invalidating other XML files, best of all it will remain back compatible with unmodified DLL's provided no tags are removed.


14.8 Organization

Though not required it’s recommended that modders use these organization proposals to keep everyone on the same page and make modules easy to use. Within the modules directory there will be two directories for each of the major data types, one for Modifications to existing objects "Modified TYPE" and one for new material called "Custom TYPE" ware TYPE corresponds with a file type. Things like whole Civilizations that have dependent sub elements should have their sub elements nested within their own directories so the single package contains everything necessary to add or remove the Civ from the game. In general content should be in the smallest pieces able to standalone such as a single Unit, Tech or Building. Only if multiple elements are inter-dependent due to cross referencing should they be packaged together, this can be done by just listing multiple elements on each xml file just as the games original 'monolithic' files were organized. If all the interdependencies are within a single such xml file they will load cleanly

  1. Create a new Directory bearing the module name pick something descriptive yet simple, example ** - "Ninja"
  2. Copy all the necessary art files into the directory, including button images, animations for units and leaders can sometimes be omitted and referenced.
  3. Copy the contents of a template folder appropriate for the type of object your making, this includes blank xml files and schema files necessary for the object.
  4. Add the module name from of each xml file including any schemas, example "_CIV4UnitInfos.xml" becomes "Ninja_CIV4UnitInfos.xml"
  5. Open each non-schema xml file and add the module name in front of the Schema name at the top of the file.
  6. If extracting an object from an existing mod Copy the xml entry for each type of file from the original mods single monolithic file into the modules appropriate xml file.

    If the original mod was for Warlords or even Vanilla the xml element just copied will likely be out of date and missing new BtS elements necessary to function properly, to update these run a diff program with an xml file of the same type that is up to date merging in the missing element and putting in appropriate values.
  7. Open the ArtDef file for the module, for each pathway listing change the path to "module/TYPE/MODULE/FILE", TYPE will be the kind of object such as "Custom Civilizations" or "Modified Techs", MODULE is simply the directory name you used in step 1 and FILE the name of the appropriate art file like Ninja_button.dds
  8. If a large module consisting of multiple objects such as a new Civilization with Unique Units, Buildings and Leaders then complete and test the top most object (the Civilization) first then return to step 1 and create each sub element within the higher element as a sub folder, on step 7 be sure to take into account additional directory layer.
  9. Discard any files that came with the template that you are not modifying to save on space, for example Unique Units and Buildings don't need to define new Unit or Building Types.
  10. Finally fill out the readme.txt so others who use your module can credit you and contact you, include any special configuration options or dependencies that would be helpful to know.


14.9 Troubleshooting

Some of the most common problems you will have and theirs cause & fixes

No difference at all is apparent with no error on loading –

This is due the modular xml files being completely bypassed. You can check your xml log to confirm that the files never loaded. First check to ensure the Modular Loading option on the Config file is set to 1. If theirs still nothing happening see that the modules packages are placed within "Assets/modules" not directly under Assets or in the xml directory. And lastly make sure the xml files contain '_' characters, its easy to forget to add them.
Magenta buttons or 'Red Ball' Units and Buildings –

The file pathway on the ArtDef is wrong and the file can’t be found. Double check your Art files, did you remember to put them in them in the module? Check the ArtDef and make sure the pathway matches the modules path, this will usually be "modules/TYPEOFMODULE/MODULENAME/FILENAME" or you can reference contents from the original installed artwork.
Error during loading "invalid according to schema" –

This can have two causes, if the error message is followed by a specific tag and line something like "<TAG> on line # is invalid" then your schema and xml file aren’t in synch, one is for Warlords and the other BtS it could be either way and you would get similar error readings. On the other hand the invalid message without any follow up indicates they schema wasn't found and you haven't got a match between the schema name and the schema reference, see steps 4 & 5.
Error during loading "reference not found" –

This error results when a string name isn't found in the global hash. You can hit OK to get past and continue loading to hunt more errors and the unfound string is just truncated to NONE. Modular loading never removes any of the game original strings so as long as a Module only references things from the original game (or mod) this error won't occur. But if your creating Modules that require each other say for example two units, unit A which can upgrade to B, A will need to reference B and loading A without B would throw this error.
Looking at the object in the Civilivilopedia shows a blank page, no button in a list or python exception –

This is usually due to a missing ArtDef, example a unit references an Artdef call BLA_ARTDEF which isn't being found either because its been misnamed or isn't loading because its name lacks an underscore '_' or is just plain missing. Once this is corrected the blank page will cease and you will at least see Magenta buttons.


14.10 Cache Loading

When cache loading is active the regular expression searching will be skipped for each file that can be loaded in this way (the 13 largest files comprising the bulk of the content), other file types will still search and load modules. When the game detects changes in Custom Assets or Mod Assets it will conduct the full search and write the contents of all modules it finds into the Cache files, these will load on subsequent games at higher speed. It appears from testing that the game can in some case be tricked into falsely trying to cache load when Modules are added or removed so its recommended that you explicitly DE-activate cache loading by pressing SHIFT as the game loads after adding or removing modules to be on the safe side. If you get an error during Cache loading the first fix to try is just reloading without Caching.


14.11 Templates

To help make the creation of modules easier I have included as set of templates for several of the major file types. These folders contain an empty copy of each file that needs to be included to get a new element of that type into the game. To modify an object you only need to include a copy of files your actually modifying, for example changing the name of a Building would only require a short Game Text file and everything else could be discarded. A typical template looks like this.

<?xml version="1.0"?> 
<!-** - edited with XMLSPY v2004 rel. 2 U (http://www.xmlspy.com) by Soren Johnson (Firaxis Games) --> 
<!-** - Sid Meier's Civilization 4 --> 
<!-** - Copyright Firaxis Games 2005 --> 
<!-** - --> 
<!-** - Tech Infos --> 
<Civ4TechInfos xmlns="x-schema:_CIV4TechnologiesSchema.xml"> 


14.12 Resources

A new sub forum will soon be opening on the CFC CIV4 Creation and Customization forum, called the "Plug and Play" forum found at (http://forums.civfanatics.com/forumdisplay.php?f=255) it will be dedicated to the posting of new modules. Another resource already under development is the 'Library' branch of the CCCP at (http://sourceforge.net/projects/civ4ccp/library/) ware you can find a growing collection of modules of all types, these were initially written for Warlords version of MXMLL and will be converted to BtS. All these modules are free to download, use, modify and distribute. Purplexus of CFC is the chief module maker for the initial Warlords version and moderates the new 'P&P' forum and CCCP library and is the most experienced 'guru' of modules as of this writing, he can provide additional tips and help on creating modules, expect more detailed guides from him in coming weeks based on user feedback.


15.0 Appendix B** - Event Guide

15.1 Civ4EventInfos.xml

Assets\XML\Events\Civ4EventInfos.xml is the main file describing all the in-game events. This section will describe the tags in that file, explaining their meaning.

  • Type - this is the event type identifier. Takes the form of EVENT_NAME
  • Description - identifier of the text string which contains the event description. Typically takes the form of TXT_KEY_EVENT_NAME, and description text strings can be found in Assets\XML\Text\Civ4GameText_Events_BTS.xml
  • LocalInfoText - identifier of the text string, if any, to be shown to the affected player.
  • WorldNewsTexts - specifies text, if any, to be shown to every player in the world (who has met the affected civilization) when the event occurs.
  • OtherPlayerPopup - specifies text, if any, to show in a popup to the other player affected. In BtS, is used for the Partisans event.
  • QuestFailText - specifies text, if any, to be displayed if the quest has been failed. Obviously, used for quests.
  • bQuest - can be either 0 or 1. If set to 1, then the event is actually a quest.
  • bGlobal - can be either 0 or 1. If set to 1, then the event will apply to all players. That is used for events that complete a quest in order to reset it for every player.
  • bTeam - can be either 0 or 1. If set to 1, then it will apply to all players on the same team. It’s not used in any of the events shipping with BtS.
  • bPickCity - can be either 0 or 1. If set to 1, then the event affects a city of the player for whom the event was triggered.
  • bPickOtherPlayerCity - can be either 0 or 1. If set to 1, the event affects a foreign city. For example, you can be given the choice of spending some espionage points to worsen the effects this event deals to the foreign city. Used in conjunction with <bPickCity>, creates an event that affects the player’s city and a foreign city. Famine is one example of such an event in BtS.
  • bDeclareWar - can be either 0 or 1. If set to 1, will cause the affected player and the other player to go to war.
  • iGold - is a number. Specifies the base amount of gold that the affected player gains. If set to a negative number, the player will lose the gold. Can also optionally affect the other player – see below.
  • bGoldToPlayer - can be either 0 or 1. Works in conjunction with <iGold>. If set to 1, then the gold value of <iGold> will be given to the other player. Since it requires another player, it’s only useful for events that involve another player.
  • iRandomGold - is a number. Specifies the cap for an extra random amount of gold that is added to iGold to produce the total amount of gold.
  • iCulture - is a number. Specifies the amount of culture to be added to a city – only useful for events targeting a city.
  • iEspionagePoints - is a number. Specifies the amount of espionage points that the affected player will gain towards the other player.
  • bGoldenAge - can be either 0 or 1. If set to 1, triggers a golden age for the affected player.
  • iFreeUnitSupport - is a number. Specifies how many extra free units the player is allowed to support.
  • iInflationMod - is a number. Specifies by how much the affected player’s inflation modifier is changed.
  • iSpaceProductionMod - is a number. Specifies by how much the player’s spaceship part production modifier is changed. A value of 10, for example, would speed SS production up by 10%.
  • Tech - is a technology identifier. NONE for no technology. If set, explicitly specifies a technology towards which you can gain beakers.
  • TechFlavors - if not empty, contains one or more flavor types. For events that result in progress towards a technology, flavors affect which technology will be picked. For example, FLAVOR_RELIGION with a value of 1 will make you more likely to have progress towards a religious technology.
  • iTechPercent - is a number. Specifies by how many percent closer the player will become to the technology. The technology can be set explicitly (see <Tech>) or chosen randomly. Negative numbers can be used to set research back.
  • iTechCostPercent - is a number. Specifies how many percent of the technology’s beaker cost to convert to a gold value.
  • iTechMinTurnsLeft - is a number. Specifies that the event may only affect techs for which the player needs at least this many turns to research. For example, setting to 2 for an event that advances research progress would mean that progress won’t be advanced for a tech that you’re about to complete in 2 turns.
  • PrereqTech - is a technology identifier. NONE for no technology. If set, then the technology is required for this event. Used to create event choices that the player can not pick unless he has the tech.
  • UnitClass - is a unit class identifier. NONE for no unit class. Specifies a unit class for receiving free units – see below.
  • iNumFreeUnits - is a number. Specifies how many free units of the class given in <UnitClass> the player should receive. For example, with <UnitClass> set to UNITCLASS_CROSSBOWMAN and <iNumFreeUnits> to 2, the player would get 2 free Crossbowmen, or 2 free Chu-Ko-Nu if Chinese.
  • bDisbandUnit - can be either 0 or 1. If set to 1, disbands (kills) the affected unit.
  • iUnitExperience - is a number. Specifies the amount of free XP received by the affected unit.
  • iUnitImmobileTurns - is a number. Specifies the number of turns that the affected unit will remain immobile. Immobile units can still defend.
  • UnitPromotion - is a promotion identifier. For events that affect a specific unit (as determined by the trigger), can be used to apply a promotion to that specific unit. It’s not used in BtS, however – instead, Python callbacks are used (example: the Champion event).
  • UnitName - is a text string identifier. If specified, will set the affected unit’s name to the specified string.
  • UnitCombatPromotions - if non-empty, contains free promotions that all units of a selected combat type receive. Format to fill is as follows:

The above would give all archery units a free Combat I promotion.

  • UnitClassPromotions - similar to above. If non-empty, contains free promotions for all units of a selected unit class to receive. Format as follows:

That would give all Axeman-class units Shock.

  • BuildingClass - is a building class identifier. NONE for no building. Explicitly gives a building class to be affected by the event. Used with <iBuildingChange>, see below.
  • iBuildingChange - is a number. Specifies how many buildings of the class specified in <BuildingClass> to add. Since a city can only contain 1 of a building, the only useful values are 1 to add a building and -1 to remove it. So, if <BuildingClass> is a BUILDINGCLASS_FORGE and <iBuildingChange> is -1, the event would remove the affected city’s Forge.
  • BuildingExtraYields - if non-empty, contains information that modifies yield given by a building. For example, a building can be made to produce extra food or hammers. Format to fill as follows:

The above would give your Harbours 2 extra commerce. If <bPickCity> is 0, the change will apply to all buildings of the class in your civ. If <bPickCity> is 1, only the building in the affected city will be modified.

  • BuildingExtraCommerces - similar to above, if non-empty, contains information tat modifies commerce outputs given by a building. Note that this is not for pure commerce (to change that, use BuildingExtraYields and YIELD_COMMERCE as per the above example), but rather for commerce types – research, culture, gold or espionage. Format to fill as follows:

The above would add 1 gold to the output of your Markets. Just as with the <BuildingExtraYields>, if <bPickCity> is 0, the change will apply to all buildings of the class in your civ. If <bPickCity> is 1, only the building in the affected city will be modified.

  • BuildingExtraHappies - another similar tag, if non-empty, assigns extra happiness to buildings. Format as follows:

That’s to add 1 happiness to a Theatre. Once again, if <bPickCity> is 0, the change will apply to all buildings of the class in your civ. If <bPickCity> is 1, only the building in the affected city will be modified.

  • BuildingExtraHealths - works just like <BuildingExtraHappies> above, but adds extra health.

That would give +1 health to your Hospitals. If <bPickCity> is 0, the change will apply to all buildings of the class in your civ. If <bPickCity> is 1, only the building in the affected city will be modified.

  • iHappy - is a number. Specifies extra happiness to give. If <bPickCity> is 0, the change will apply to the entire civ. If bPickCity> is 1, only the affected city’s happiness will be modified.
  • iHealth - is a number. Specifies extra health to give. If <bPickCity> is 0, the change will apply to the entire civ. If <bPickCity> is 1, only the affected city’s health will be modified.
  • iHurryAnger - is a number. Specifies extra whipping unhappiness to give. Unhappy citizens created by events using this variable will have the “We can not forget your cruel oppression!” unhappiness. You can be extra evil by setting <bPickCity> to 0, which would give the penalty in all cities. Ack!
  • iHappyTurns - is a number. Specifies the amount of turns to give temporary happiness. The amount of happy faces given is specified in Assets\XML\GlobalAssets.xml as the TEMP_HAPPY variable. It defaults to 1 in BtS. Therefore, setting <iHappyTurns> to 10 would ensure +1 happiness for 10 turns. Once again, if <bPickCity> is 0, the change will apply to the entire civ. If <bPickCity> is 1, only the affected city’s happiness will be modified.
  • iRevoltTurns - is a number. Specifies the amount of turns that the city will spend in revolt (no production, etc., like newly captured cities). Must be city-targeted, that is, used in conjunction with <bPickCity> or <bPickOtherPlayerCity> set to 1.
  • iMinPillage - is a number. Specifies the minimum amount of terrain improvements that will be pillaged (removed). If used with a city-targeting event, then the pillaged improvement will be in the city’s radius. If the event doesn’t target a city, the improvement may be anywhere.
  • iMaxPillage - is a number. Specifies the maximum amount of terrain improvement that will be pillaged(removed). Works in conjunction with <iMinPillage> and must be equal or greater than <iMinPillage>, see above. Setting both variables to an equal value will result in exactly that many improvements getting pillaged.
  • iFood - is a number. Specifies the amount of stored food to be added in a city. If <bPickCity> is 0, the change will apply to the entire civ. If <bPickCity> is 1, only the affected city’s food stores will be modified.
  • iFoodPercent - is a number. Specifies by how many percent to modify the stored food in a city. You can remove all the stored food by setting this value to -100. If <bPickCity> is 0, the change will apply to the entire civ. If <bPickCity> is 1, only the affected city’s food stores will be modified.
  • FreeSpecialistCounts - if non-empty, describes the free specialists added to a city. Can only be used with events that target a city. Format is as follows:

That would add a free Scientist to the city.

  • FeatureType - is a feature type identifier, NONE for no feature types. Sets the feature type that the event will add or remove in a plot, used in conjunction with <iFeatureChange>, see below.
  • iFeatureChange - is a number. If used, should only take the values of 1 or -1. Setting to 1 would add the feature described in <FeatureType> to the affected plot, setting to -1 would remove the feature.
  • ImprovementType - is an improvement type identifier, NONE for no improvement. Sets the improvement type that the event will add or remove in a plot, used in conjunction with <iImprovementChange>, see below.
  • iImprovementChange - is a number. If used, should only take the values of 1 or -1. Setting to 1 would add the improvement described in <ImprovementType> to the affected plot, setting to -1 would remove the improvement.
  • BonusType - is a bonus (resource) type identifier, NONE for no bonus. Sets the bonus type that the event will add or remove in a plot, used in conjunction with <iBonusChange>, see below.
  • iBonusChange - is a number. If used, should only take the values of 1 or -1. Setting to 1 would add the bonus described in <BonusType> to the affected plot, setting to -1 would remove the bonus.
  • RouteType - is a route type identifier, NONE for no route. Sets the route type that the event will add or remove in a plot, used in conjunction with <iRouteChange>, see below.
  • iRouteChange - is a number. If used, should only take the values of 1 or -1. Setting to 1 would add the route described in <RouteType> to the affected plot, setting to -1 would remove the route.
  • BonusRevealed - is a bonus type identifier, NONE for no bonus. If used, will reveal the specified bonus to the affected player, even if he has no technology to normally see the bonus.
  • BonusGift - is a bonus type identifier, NONE for no bonus. If used, will make the affected player gift the specified bonus to the other player. As such, it can only be used with events that affect two players.
  • PlotExtraYields - if non-empty, contains information that modifies the yields of the affected plot. Format is as follows:

The above would add 1 commerce to the affected plot.

  • iConvertOwnCities - is a number. Specifies the number of the player’s cities that will be converted to the trigger religion, the religion being added to the city if not already present. The religion is determined in event triggers.
  • iConvertOtherCities - is a number. Specifies the number of foreign cities that will be converted to the trigger religion. The religion is determined in event triggers.
  • iMaxNumReligions - is a number. Specifies the maximum amount of religions that may be present in a city in order for it to be converted by either <iConvertOwnCities> or <iCnvertOtherCities>. If you wish to ignore the amount of religions already in the city, set this variable to -1.
  • iOurAttitudeModifier - is a number. Specifies the attitude modifier of the affected player towards the other player.
  • iAttitudeModifier - is a number. Specifies the attitude modifier of the other player towards the affected player.
  • iTheirEnemyAttitudeModifier - is a number. Specifies the attitude modifier of the affected player towards the other player’s worst enemy and vice versa. For example, if set to -1, Civ A is the affected player and Civ B is the other player, then Civ A will have -1 towards Civ B’s worst enemy and Civ B’s worst enemy will also have a -1 modifier towards Civ A.
  • iPopulationChange - is a number. Specifies the population change in the city – negative numbers indicate population loss. If <bPickCity> is 0, the change will apply to the entire civ. If <bPickCity> is 1, only the affected city’s population will be modified.
  • AdditionalEvents - if non-empty, specifies extra events that will have a chance of occuring if that event happens. For example,

means that EVENT_AIRLINER_CRASH_4 will be triggered with a likelihood of 50%.

  • EventTimes - if non-empty, it can be used to set up delayed events. Has to be used along with <AdditionalEvents> above. Fill as follows:

In case the event filled in <AdditionalEvents> does not trigger due to the random roll, the event timer will kick in, making it occur later.

  • ClearEvents - if non-empty, specifies the events which get reset and the probability of that happening. For example:

This resets the EVENT_DUSTBOWL_2 unconditionally, which means that the event is considered to not have occurred.

  • PythonCallback - If non-empty, specifies the Python function that is called when the event occurs. See the section on Python for more information.
  • PythonExpireCheck - if non-empty, specifies the Python function that is called to check whether the event expires. See the section on Python for more information.
  • PythonCanDo - If non-empty, specifies the Python function that is called to verify whether the event can be triggered. See the section on Python for more information.
  • PythonHelp - If non-empty, specifies the Python function that generates the help text for this event. See the section on Python for more information.
  • Button - Specifies the art file which is displayed as the event’s button.
  • iAIValue - is a number. Reflects the AI trigger value for this event.


15.2 CIV4EventTriggers.xml

So that’s it as far as event descriptions go in the XML. However, that is only one side of the event description. The other side are triggers. Triggers are described in Assets\XML\Civ4EventTriggerInfos.xml. In essence, every trigger is a set of conditions. If these conditions are true, then events tied to that particular trigger can occur (some have extra Python checks, that’s in the Python section). Events that are tied to a trigger are also described in this file. Predictably enough, the SDK class for event triggers is CvEventTriggerInfo.
So, here are the tags describing triggers.

  • Type - this is the trigger type identifier. Takes the form of EVENTTRIGGER_NAME
  • WorldNewsTexts - is a text string identifier, which spiecifies the text to be displayed to all players when the event occurs.
  • TriggerTexts - text string identifiers can be specified for additional trigger messages, in particular, texts tied to an era. For instance, the Ruins effect:

Here, separate text is being given for every era, so that the correct text would appear at the appropriate time.

  • bSinglePlayer - can be either 0 or 1. If set to 1, the event can only trigger in singleplayer games.
  • iPercentGamesActive - is a number from 0 to 100. When you start a new game, not all events will be in it. This number determines the probability of this event trigger being included in a new game. Thus you can create events that will be rarely seen – or, on the contrary, be eligible to occur in every game.
  • iWeight - is a number that affects the probability of this trigger triggering. Applies to events that are active in this game only (as does everything else). Set to -1 if the trigger needs to always occur if the other conditions are met (for example, triggers that determine quest completion should be with -1).
  • bProbabilityUnitMultiply - can be either 0 or 1. If set to 1, the trigger probability increases as the player builds more units.
  • bProbabilityBuildingMultiply - can be either 0 or 1. If set to 1, the trigger probability increases as the player builds more buildings.
  • Civic - is a civic identifier, NONE for no civic. If used, specifies the civic required for the trigger to activate.
  • iMinTreasury ** - is a number. Specifies the minimum amount of gold in the player’s treasury for the trigger to activate.
  • iMinPopulation** - is a number. Specifies the minimum total population that a player must have for the trigger to activate.
  • iMaxPopulation - is a number. Specifies the maximum total population that a player is allowed to have for the trigger to activate.
  • iMinMapLandmass - is a number. Specifies the minimum amount of land areas that must be on the map for the trigger to activate. Can be used, essentially, to specify the minimum amount of continents required.
  • iMinOurLandmass - is a number. Specifies the minimum amount of land areas that must be under player’s control (specifically, have cities on them) for the trigger to activate.
  • iMaxOurLandmass - is a number. Specifies the maximum amount of land areas that the player is allowed to control for the trigger to activate. Use -1 to have no restrictions.
  • MinDifficulty - is a difficulty level specifier, NONE for no difficulty. If used, specifies the minimum difficulty level required for the event trigger to activate,
  • iAngry - is a number. Specifies the minimum anger level (unhappiness – happiness) in a city for the trigger to activate. Applies to triggers that target a city.
  • iUnhealthy - is a number. Specifies the minimum unhealthiness level (bad health – good health) in a city for the trigger to activate. Applies to triggers that target a city.
  • UnitsRequired - if non-empty, contains information about required units to trigger. So, if specified, events can only be triggered for the listed unit classes. Example:

Such a trigger would make the event only affect the listed naval units.

  • iNumUnits - is a number. Specifies the amount of unts that must be on a plot for the trigger to activate – used for events which pick a plot. If used in conjunction with <UnitsRequired>, only units of the listed classes will be counted.
  • iNumUnitsGlobal - is a number. Specifies the amount of units that the player must have for the trigger to activate. If used in conjunction with <UnitsRequired>, only units of the listed classes will be counted.
  • iUnitDamagedWeight - is a number. Denotes the probability of the trigger activating for wounded units. Set to 1 for event triggers that you wish to deal with damaged units.
  • iUnitDistanceWeight - is a number. For events that affect a plot, increases the probability (if set to 1) of the trigger activating if a unit is far away from the plot.
  • iUnitExperienceWeight - is a number. When set to 1, increases the probability of triggering for a highly-experienced unit.
  • bUnitsOnPlot - can be either 0 or 1. When set to 1, means that the trigger checks for the presence of units (listed in <UnitsRequired>) on the affected plot.
  • BuildingsRequired - if non-empty, contains informations about the buildings required to trigger. Example:

That would denote that a Forge is required for the trigger.

  • iNumBuildings - is a number used in conjunction with <BuildingsRequired>. Set to 1 to indicate that 1 building of that type is required in a city, for city-picking events.
  • iNumBuildingsGlobal - is a number. Specifies the minimum amount of buildings listed in <BuildingsRequired> that the player must have in total for the trigger to activate.
  • iNumPlotsRequired - is a number. Should be set to 1 for triggers that require a plot that meets specific conditions. See below for tags that specify these conditions.
  • bOwnPlot - can be either 0 or 1. If set to 1, specifies that the plot must be owned by the affected player to meet conditions.
  • iPlotType - is a number. Specifies the plot type that the plot must have to meet the condition. Set to -1 to ignore plot type. Unless otherwise modded, 0 stands for peaks (PLOT_PEAK), 1 for hills (PLOT_HILLS), 2 for land plots (PLOT_LAND) and 3 for ocean plots (PLOT_OCEAN). The enumeration listing plot types is PlotTypes in the SDK and Python.
  • FeaturesRequired - if non-empty, specifies the features that the plot must have to meet the condition. For example:

That is to require a plot to have Forest. Note that you can also explicitly require a plot not to have any features as follows:


Please note that flood plains also count as a feature and the above example would exclude any floodplain plots.

  • TerrainsRequired - if non-empty, specifies the terrain type that the plot must have to meet the condition. For example:

to indicate that Grasslands or Plains plots are eligible for the trigger.

  • ImprovementsRequired - if non-empty, specifies the improvements that the plot must have to meet the condition. As an example:

That is to require a Plantation. Note that you can, just like with Features, set the variable to NONE to explicitly require no improvement to be present.

  • BonusesRequired - if non-empty, specifies the bonus (resource) types that the plot must have to meet the condition. So,

Requires Incense in the plot. And again, setting the variable to NONE will explicitly require no bonus to be present.

  • RoutesRequired - the last variable specifying plot conditions. If non-empty, specifies the route types that the plot must have to meet the condition.

The above requires either a road or a railroad in the plot.

  • ReligionsRequired - if non-empty, specifies the religions required for the trigger to activate. For triggers that affect a city, the religions must be present in the city. For triggers not affecting a city, the religion must be present anywhere in the civilization. Hence:

That code would check for the presence of Buddhism, Confucianism and Taoism. It’s used in conjunction with the next variable, see below.

  • iNumReligions - is a number. Specifies how many of the religions listed in <ReligionsRequired> must be present for the trigger to activate. If <ReligionsRequired> has been left empty, then any religions will do. For example, for a trigger that affects a city, if <ReligionsRequired> is empty and <iNumReligions> is 2, then cities with at least different 2 religions in them will be eligible for the trigger.
  • CorporationsRequired - if non-empty, specifies the corporations required for the trigger to activate. For triggers that affect a city, the religions must be present in the city. For triggers not affecting a city, the religion must be present anywhere in the civilization.

That would require the first corporation, which is Cereal Mills. Just like <ReligionsRequired>, this is used in combination with the next variable.

  • iNumCorporations - is a number. Works exactly like <iNumReligions>, but for corporations instead of religions. Specifies how many of the corporations listed in <CorporationsRequired> must be present for the trigger to activate. If <CorporationsRequired> has been left empty, then any corporation will do.
  • bPickReligion - can be either 0 or 1. If set to 1, then the trigger will pick a religion for the events that it activates. Which religion is picked can be further specified by the next variables.
  • bStateReligion - can be either 0 or 1. If set to 1 and <bPickReligion> is 1, then the affected player’s state religion will be picked.
  • bHolyCity - can be either 0 or 1. If set to 1 and <bPickReligion> is 1, then the player must own the religion’s holy city in order for it to be picked. If the trigger also picks a city, then the picked city must be the religion’s holy city. For example, if <bPickReligion>, <bStateReligion>, <bHolyCity> are all 1 and the trigger picks a city (<bPickCity> is also 1), then the city picked will be the holy city of the player’s state religion, provided he owns that city.
  • bPickCorporation - can be either 0 or 1. If set to 1, then a corporation will be picked by the trigger. The corporation must be present in the player’s civilization to be picked.
  • bHeadquarters - can be either 0 or 1. If set to 1 and <bPickCorporation> is 1 then the player must own the corporation’s headquarters in order for it to be picked. If the trigger also picks a city, then the picked city must be the corporation headquarters. Works like <bHolyCity> does for religions.
  • Events - this, ladies and gentlemen, is the holy grail of the trigger XML file. Here event identifiers from Civ4EventInfos.xml are listed that denote the events triggered by this particular trigger. Note that each choice is also technically an event – therefore, for events that have choices, multiple identifiers will be listed. Take a look at the slave revolt event example:

The code means that, when the trigger activates, the player will be allowed to choose between three events. So in-game, a popup with three options will appear. The effects of every choice are, of course, specified in Civ4EventInfos.xml. Triggers that do not have a choice associated with them simply list one event:


Here the player will have no choice but to accept what happened.

  • PrereqEvents - another fun field, this lists the events that must have already happened for this trigger to possibly activate. There are two main uses. One is to simply specify conditional triggers. For example, EVENTTRIGGER_DUSTBOWL_CONT has

That means that the trigger can only activate if the EVENT_DUSTBOWL_2 event has occurred previously.
The second use is for quest done triggers. When creating quests, each quest needs a trigger that checks whether its conditions have been fulfilled. However, a quest can only be completed if it’s been given. Therefore, for example, EVENTTRIGGER_HORSE_WHISPERING_DONE, which fires when you complete the Horse Whispering quest, has:


That code makes sure that the trigger only activates if the EVENT_HORSE_WHISPERING_1 event has occurred, that being the event which assigns the Horse Whispering quest.

  • bPrereqEventPlot - can be either 0 or 1. For triggers that have PrereqEvents specified, if set to 1, means that the trigger will fire on the same plot where the prerequisite events fired. This is used with triggers such as continuing slave revolts or dustbowls – if the prerequisite event has fired, dustbowl or revolts will, if triggered, happen again in the same place where they did before.
  • OrPreReqs - if non-empty, lists technologies that player must have for the trigger to activate. These requirements are Or requirements – that is, only one technology of the listed ones is required. Example:

That allows the trigger to activate if the player has Steam Power or Steel or Scientific Method or Artillery.

  • AndPreReqs - if non-empty, lists technologies that the player must have for the trigger to activate. These are And requirements – the player must have all the listed technologies for the trigger. Example:

This trigger can only fire when the player has both Rifling and Steel technologies.

  • ObsoleteTechs - if non-empty, lists technologies that obsolete the trigger, making it ineligible to activate. If multiple technologies are listed, having any of those will invalidate the trigger for that player.

These settings would obsolete the trigger for any player who has Rifling or Railroad or Economics.

  • bRecurring - can be either 0 or 1. If set to 1, the trigger can activate multiple times throughout the game for the same player. If set to 0, it can only activate once per player. Note that the <ClearEvents> field in event description can reset events, making the game forget they have occurred.
  • bTeam - can be either 0 or 1. If set to 1, the trigger applies to all players on the same team. Not used in any of the events shipping in BtS.
  • bGlobal - can be either 0 or 1. If set to 1, applies to all players. That means that, when triggered for one player, it’s cosidered to have triggered for all players. Combined with <bRecurring> set to 0, it will result in triggers that can only happen once per game.
  • bPickPlayer - can be either 0 or 1. If set to 1, then the trigger will pick another player to affect by the event. This is how events that give stuff to other players or affect relations with them are created. The specific player who gets selected can be further narrowed down by the next six tags.
  • bOtherPlayerWar - can be either 0 or 1. If set to 1, then the trigger can activate when the affected player and the other player are at war. When set to 1, the trigger activates for player pairs at peace.
  • bOtherPlayerHasReligion - can be either 0 or 1. If set to 1, then the other player must have the religion picked by the trigger (see <bPickReligion>). If <bStateReligion> is 0, then the other player must have the religion somewhere in his empire. If <bStateReligion> is 1, then the other player must have the same state religion.
  • bOtherPlayerHasOtherReligion - can be either 0 or 1. Works opposite to the previous variable. If set to 1, the other player must have a different religion than the picked one. If <bStateReligion> is 1, then the other player’s state religion must be different.
  • bOtherPlayerAI - can be either 0 or 1. If set to 1, then the other player must be an AI player.
  • iOtherPlayerShareBorders - is a number. Specifies the minimum amount of land plots that the affected player and the other player must have along the border (adjacent to one another).
  • OtherPlayerHasTech - is a technology identifier, NONE for no technology. If used, specifies the technology that the other player must have for the trigger to activate.
  • bPickCity - can be either 0 or 1. If set to 1, then the trigger will pick a city.
  • bPickOtherPlayerCity - can be either 0 or 1. If set to 1, then the trigger will pick one of the other player’s cities.
  • bShowPlot - can be either 0 or 1. If set to 1, then the plot in which the event happens will be visually highlighted.
  • iCityFoodWeight - is a number. Acts as a probability multiplier for the food stored in a city. That is, for triggers that pick a city, cities with more food stored will have a higher probability of being picked as iCityFoodWeight increases. 1 is a sane value to prioritize cities with a lot of food stored.
  • PythonCanDo - if specified, it’s the name of the Python function which is executed to check whether the trigger can be triggered. See the section on Python for more information.
  • PythonCanDoCity - if specified, it’s the name of the Python function which checks whether a city is eligible to be picked by the trigger. See the section on Python for more information.
  • PythonCanDoUnit - if specified, it’s the name of the Python function which checks whether a unit is eligible to be picked by the trigger. See the section on Python for more information.
  • PythonCallback - if specified, it’s the name of the Python function which is called when the trigger activates. Not used in any of the BtS events. Don’t confuse with <PythonCallback> in event descriptions in Civ4EventInfos.xml, which is the function which gets called when the event happens. See the section on Python for more information.


15.3 Python and Events

XML tags allow a good range of possibilities for modding events and their triggers, but some of the more complicated stuff you might want to do requires the use of Python. Python modding, of course, requires a working knowledge of Python, so if you do not have that, feel free to skip this section. This article won’t teach you Python or how to use Python with Civ4 general. The Python file for event functions is Assets\Python\EntryPoints\CvRandomEventInterface.p y.

Let us first look at how Python can be used in conjuncton with the events described in Civ4EventInfos.xml. As mentioned, each event entry has four Python function tags. If these are filled, then the aproppriate Python functions are called and used in conjunction with whatever XML data has been specified. Here are, again, the tags.

  • PythonCallback - that’s the Python function which is called when the event actually happens. It’s used to give the event effects more complicated than are possible through raw XML. Quests are the best example of that, as their rewards are usually somewhat complicated.

Callback functions don’t need to return a value.

  • PythonExpireCheck - that’s the Python function which is called to see whether the event has expired. It will be called every turn for every event that has occurred. If the event has expired, it gets reset. The practical use of that is for quests. Events that set a quest should sent a Python expiration check function, which will determine the failing conditions of that quest.

Using Python expiration functions will not let you undo regular (non-quest) events. So if you have an event that, say, adds a promotion to all melee units, and add an expiration check to that event, it won’t remove the promotion when the expiration function returns true.

Expiration functions should return a true value for when the event has expired and a false value for when it hasn’t expired.

It’s important to note that expiration functions are only required if the expiration condition can not be described by XML alone. If the only expiration condition you want is, for example, a technology, then you can make the event expire by setting <ObsoleteTechs> in Civ4EventTriggerInfos.xml. That’s the general idea of event Python functions – they complement the XML when it can’t describe what you want.

  • PythonCanDo - that’s the function which gets called to see if the event can be applied/selected. Again, that is required for non-trivial conditions. If the XML specifies, for example, that the event will subtract 100 gold from the treasury, people won’t be able to choose it unless they have 100 gold. But sometimes you will want to have non-trivial codition checks.

If the event can happen, the Python function should return a true value, and a false value if it can’t happen.

  • PythonHelp - this function will generate the help text for the event, if required. That text is displayed in mouseovers. This is primarily required for events whose text can change somewhat, such as having a different number depending on the circumstances. For example, if your event gives the player a free unit per every city, then the event’s help text should be modified according to the number of cities the player has. The function should return a text string.

Now, let’s look at some examples of these Python functions in use. The examples are from events that ship with BtS. First, you’ll notice that functions begin with retrieving data from the argsList passed to them.

def doWeddingFeud2(argsList): 
   iEvent = argsList[0] 
   kTriggeredData = argsList[1]

The first thing you should notice is the argument list that applies to event Python functions. For callback functions (<PythonCallback>), expiration (<PythonExpireCheck>) and help functions (<PythonHelp>) argsList[0] will always contain the event identifier number, and argsList[1] will have an object describing the trigger data. For condition functions (<PythonCanDo>) argsList[0] will be the trigger object data. The type of that object is EventTriggeredData and it contains information about the data that the event was triggered with. You can get the affected player, the other player, the picked city and other things from the object.


15.4 EventTriggeredData

Here’s what you can do with the object in Python. Assume you have an assignment like

kTriggeredData = argsList[0]

Now, there’s a bunch of useful stuff to do with the object through its member variables.

  • kTriggeredData.ePlayer - will return the player ID for whom the event was triggered. To get a CyPlayer object out of it in Python,
player = gc.getPlayer(kTriggeredData.ePlayer)
  • kTriggeredData.eTrigger– will return the trigger type ID of the trigger for this event. That corresponds to an entry in Civ4EventTriggerInfos.xml
trigger = gc.getEventTriggerInfo(kTriggeredData.eTrigger)

will return a trigger info object if you need one.

  • kTriggeredData.iTurn - will return the turn number on which the event was triggered. Useful for expiration checks – you can, for example, easily check how many turns it’s been since the event was triggered.
  • kTriggeredData.iCityId– will return the ID of the city that’s been picked by the event. Remember that city IDs are per-player and not global. Therefore, to get a CyCity object in Python, you would
player = gc.getPlayer(kTriggeredData.ePlayer) 
city = player.getCity(kTriggeredData.iCityId)
  • kTriggeredData.iPlotX– will return the X coordinate of the plot picked by the event.
  • kTriggeredData.iPlotY– will return the Y coordinate of the plot picked by the event.

If you want to access a CyPlot object for the event’s plot, do so by

plot = gc.getMap().plot(kTriggeredData.iPlotX,  kTriggeredData.iPlotY)
  • kTriggeredData.iUnitId– will return the ID of the unit that’s been picked by the event. Just like city IDs, unit IDs are per-player and not global. So, if you want to get a CyUnit object corresponding to the picked unit, do:
player = gc.getPlayer(kTriggeredData.ePlayer) 
unit = player.getUnit(kTriggeredData.iUnitId)
  • kTriggeredData.eOtherPlayer– returns the ID of the other player for events that pick two player. Thus:
player = gc.getPlayer(kTriggeredData.ePlayer) 
otherPlayer = gc.getPlayer(kTriggeredData.eOtherPlayer)

will make player the affected player and otherPlayer the other player, ready for manipulation through Python.

  • kTriggeredData.iOtherPlayerCityId– will return the ID of the other player’s city that’s been picked by the event. To get a CyCity object:
otherPlayer = gc.getPlayer(kTriggeredData.eOtherPlayer) 
otherCity = otherPlayer.getCity(kTriggeredData.iOtherPlayerCityId)
  • kTriggeredData.eReligion– returns the ID of the religion picked by the event.
  • kTriggeredData.eCorporation– returns the ID of the corporation that has been picked by the event.
  • kTriggeredData.eBuilding– returns the ID of the building that has been picked. A CyBuildingInfo object can be obtained:
buildingInfo = gc.getBuildingInfo(kTriggeredData.eBuilding)

The use of these properties enables you to access the information you need about the event and the way it’s been triggered. Now, a full example of a Python function that executes an event:

def doWeddingFeud2(argsList): 
   iEvent = argsList[0] 
   kTriggeredData = argsList[1] 

   player = gc.getPlayer(kTriggeredData.ePlayer) 
   (loopCity, iter) = player.firstCity(false) 

      if loopCity.isHasReligion(kTriggeredData.eReligion): 
      (loopCity, iter) = player.nextCity(iter, false) 
   return 1

This is a fairly straightforward function. It iterates through all cities of the affected player and gives temporary happiness to them if they have the religion that’s been picked by the event trigger. The effect is not particularly complex, but it is something that could not be accomplished purely through XML, so it’s a good example of why Python is useful in event modding.

Here’s an example of a PythonCanDo function, which checks whether the event can be selected.

def canDoWeddingFeud3(argsList): 
   iEvent = argsList[0] 
   kTriggeredData = argsList[1] 

   player = gc.getPlayer(kTriggeredData.ePlayer) 

   if player.getGold() ** - 10 * player.getNumCities() < 0: 
      return false 

   return true

It checks whether the affected player has at least 10 gold per each city he owns. If not, the function returns false and the event can’t happen, otherwise it returns true and allows the event.

A good example of the help-text creating functions comes with the Horse Whispering quest. One of the possible rewards gives you free Horse Archers. Their number is variable, though, meaning it couldn’t exist in the help text. Let’s look at the help text string in BtS text files:

<English>[ICON_BULLET]Receive %d1 [COLOR_UNIT_TEXT]Horse Archers[COLOR_REVERT].</English>

As you can see, there’s a %d1 in the text, which will be substituted by the number. That’s what the getHelpHorseWhisperingDone1 function does in Python.

def getHelpHorseWhisperingDone1(argsList): 
   iEvent = argsList[0] 
   kTriggeredData = argsList[1] 

   map = gc.getMap() 

   iNumUnits = gc.getWorldInfo(map.getWorldSize()).getDefaultPlayers() 
   szHelp = localText.getText("TXT_KEY_EVENT_HORSE_WHISPERING_DONE_HELP_1", (iNumUnits, )) 

   return szHelp

Here, iNumUnits is set to be the default number of players for the current map size and then the number is inserted into the help text string.

Now, an example of an expiration function. Let’s look at the function which checks whether the Master Blacksmith quest has expired. The quest picks a city and expires (becomes impossible to complete) if the city which was picked changes hands or is destroyed.

def expireMasterBlacksmith1(argsList): 
   iEvent = argsList[0] 
   kTriggeredData = argsList[1] 
   player = gc.getPlayer(kTriggeredData.ePlayer) 
   city = player.getCity(kTriggeredData.iCityId)    
   if city == None or city.getOwner() != kTriggeredData.ePlayer: 
      return true 

   return false

Remember, kTriggeredData.ePlayer will always contain the player for whom the event starting the quest was triggered – and kTriggeredData.iCityId will always contain the city ID. The function checks if the city is None (which happens if it’s destroyed) or if the city’s owner isn’t the player to whom the quest was given. In these cases, the function returns true, expiring the event.

Finally, about Python functions that pertain to triggers. Civ4EventTriggers.xml also has Python function tags.

  • PythonCanDo - acts just like the same tag for events. Checks whether the trigger can be activated.
  • PythonCanDoCity - checks whether a city is eligible to be picked by the trigger.
  • PythonCanDoUnit - checks whether a unit is eligible to be picked by the trigger.
  • PythonCallback - acts just like the same tag for events. Gets called if the trigger is fired.

For PythonCanDoCity functions, argsList[0] is the trigger ID, argsList[1] is the player and argsList[2] is the city ID. For PythonCanDoUnit functions, it’s the same with the exception that argsList[2] is the unit ID. Here’s an example of a PythonCanDoUnit function for the Champion Unit trigger.

def canTriggerChampionUnit(argsList): 
   eTrigger = argsList[0] 
   ePlayer = argsList[1] 
   iUnit = argsList[2] 

   player = gc.getPlayer(ePlayer) 
   unit = player.getUnit(iUnit) 

   if unit.isNone(): 
      return false 

   if unit.getDamage() > 0: 
      return false 

   if unit.getExperience() < 3: 
      return false 

   iLeadership = CvUtil.findInfoTypeNum(gc.getPromotionInfo,gc.getNumPromotionInfos(),'PROMOTION_LEADERSHIP') 
   if unit.isHasPromotion(iLeadership): 
      return false 

   return true

After finding the unit, the function checks if it’s damaged or has less than 3 experience – in these cases it returns false. If the unit had the Leadership promotion, it also returns false. If the function returns false, then the unit is not eligible to be picked by the trigger and another one will be found.

That summarizes how events in BtS interact with Python and what the different function types are. Following are examples of some events you can create via modding.


15.5 Creating Events

Well, so creating events is what you probably want to do if you’re reading this guide. In this article, I will show you how to create a few example events, explaining along the way. Without further ado, let’s get straight to it.

Creating an event (assuming XML modification only) will consist of three main parts. One is the creation of a new trigger, which will outline the conditions, second is creation of the event entry itself, which outlines the effects, and then there is adding text to the proper XML file.

The Civilization event:

A somewhat tongue-in-cheek event, a new version of Civilization gets released. You will have three options to deal with it. First, “Let them play!” – boosts happiness in all your cities. Second, “Use this game in education” – will boost the research output of your Universities. Third, “Sell the franchise abroad” – will give you a considerable sum of gold.

So, first we’re going to be creating a new trigger. In Civ4EventTriggerInfos.xml, I create an EVENTTRIGGER_CIV_GAME entry, the code for which follows below.


Almost all tags are at their default values, which means no special conditions. The interesting part is, of course, the <Events> tag, which specifies that the trigger, when activated, will give choices between those 3 events – we will create them next. <OrPreReqs> specifies that the Computers tech is required for the trigger, which makes sense given the event’s context. Nothing fancy is added – we don’t need to pick specific players, cities, plots, check for population, religion or anything like that.

Now, I go into the Civ4EventInfos.xml file and create three new events. The first one is as follows.


Once again, most tags are at their default values. Other than the name and text description tags, the one that matters is <iHappy>, which is set to 1. That means that we’ll get +1 happiness in all cities (<bPickCity> being 0).

For the second choice, I create a second event. In order to waste less screen space, I’ll only show the relevant tags below.


Other tags being at their default values, this means that every University will provide 3 extra research beakers.

And our third event has these tags:


That will give a base 320 gold with an extra possible 80 randomly.

The mechanics of our new event are done! Now, we only need to add text. In Civ4GameText_Events_BTS.xml (in Assets\XML\Text), I add new tags as follows.

    <English>The %s1_civ_adjective game designers have developed a new game of Civilization.</English> 

TXT_KEY_EVENTTRIGGER_CIV_GAME is specified as world news text in the trigger file – that is, everyone will see the above text when the trigger fires.

    <English>Our game designers have developed a new addictive game of Civilization. How shall we proceed?</English> 

That’s specified under the TriggerTexts tag, and will be shown in a popup to the player who gets the event. Now, we only need to add the choice descriptions.

    <English>Send congratulations to the developers. Our people should enjoy this game.</English> 
    <English>This game seems to have great educational potential. Suggest that it be used in our educational system.</English> 
    <English>Computer games? They have no place in our society! Sell the franchise to foreign buyers!</English> 

That’s it, the event is done! It will be in when you star a new game.
Here’s a useful hint. You can test the event in-game. There is a function CvPlayer::trigger() which activates a trigger given its ID. I’ll show you how to activate the event we just created, the general idea is the same for all triggers.

Start BtS in debug mode (by setting CheatCode=chipotle in the ini file). Start a new game in the Future era. Now, press Shift+~ (tilde) to bring up the in-game Python console. You’ll need to find out the ID of the trigger you added. To do so, in the console, enter

import CvUtil 
num = CvUtil.findInfoTypeNum(gc.getEventTriggerInfo, gc.getNumEventTriggerInfos(), ‘EVENTTRIGGER_CIV_GAME’) 
print num

That will output the ID of the Civ Game trigger. It was 176 for me. You don’t have to enter the print num line, but it’s a way of checking if you did everything correctly. If it outputs -1, something went wrong. The same result can be achieved by using another function. Instead of the above, you could do

num = gc.getInfoTypeForString(“EVENTTRIGGER_CIV_GAME”) 
print num

It’s essentially the same, but I prefer the first way for reasons I can’t explain myself. Anyway, when you’ve obtained the trigger number, you need to trigger it for yourself. In the Python console, do:

p = gc.getPlayer(0) 

In single-player, the player with an ID of 0 is always the human, so the first line will give a reference to you. After the second line, a popup should appear just as if the event happened.

It’s important to note that, while the trigger() function can be used to forcefully activate a trigger, it will only work if the requirements are met. That’s why it was important to start a Future era game to test this addition – in the Future era, you already start with Computers. If you had started an Ancient era game, nothing would have happened after using the trigger() function.

The Danthrax event:

Danthrax told me that he would like a warning displayed the first time a slave revolt occurs, with the actual effects of the slave revolt only occuring subsequently. I’ll show how to do that, but will only be inserting the relevant tags here again.

The idea is to make a trigger with the same conditions as slave revolts, and have that trigger produce an event which merely gives a warning. Then, slave revolts are modified to require that warning to have happened. So first, I add a new trigger. I copy the slave revolt trigger and modify it.


We will not need any text displayed when the trigger activates. The event will show a pop-up message anyway. However, <TriggerTexts> may not be empty. The trigger conditions are just like those of the slave revolt trigger. <bRecurring> is set to 0, though, because we only want one warning. Now I make modifications to the slave revolt trigger.


I changed iPercentGamesActive to 100 to make the event active in all games. That’s to avoid situations when the warning appears but no slave revolts an actually happen that game. If the warning event hasn’t been activated for that particular game, slave revolts won’t occur anyway.

Now, it’s time to add the slave revolt warning event itself.


All tags are at their default values so that the event basically does nothing. It will, though, still display a popup with the description text. So, time for text tag addition.

    <English>Sir, our slaves are on the verge of revolting! As long as our society continues to use slaves, there is a possibility of them revolting!</English> 
    <English>The slaves of %s2_city are on the verge of revolt!</English> 

Now that is done, too ** - you will get a warning before your first slave revolt.

Great Beast:

For the last example, here’s a Great Beast event. Your hunters see a beast in a hunting camp, and you are presented with choices. The trigger’s relevant parts are as follows:


As you can see, the trigger requires the player to have a plot with a Camp on it. In addition, Hunting and Polytheism are required, as is a state religion. The event won’t happen after the discovery of education. The first choice is simple – it merely gives +1 food in the plot.


The second choice costs some gold and adds 1 population to a city.


The third choice is more complex, adding 1 happiness temporarily to cities of state religion.


The event XML code does nothing special except calling the Python functions.

def doGreatBeast3(argsList): 
   kTriggeredData = argsList[1] 

   player = gc.getPlayer(kTriggeredData.ePlayer) 
   (loopCity, iter) = player.firstCity(false) 

      if loopCity.isHasReligion(kTriggeredData.eReligion): 
      (loopCity, iter) = player.nextCity(iter, false)

This Python function is called when the event is chosen. It checks all the player’s cities for presence of the state religion (because the religion picked by the trigger will be the state religion), and adds 25 turns to the happiness timer of those cities, which results in +1 happiness for that time.

Also, the help text needs to be displayed appropriately, so here’s the PythonHelp function:

def geHelpGreatBeast3(argsList): 
   kTriggeredData = argsList[1] 
   religion = gc.getReligionInfo(kTriggeredData.eReligion) 

   szHelp = localText.getText("TXT_KEY_EVENT_GREAT_BEAST_3_HELP", (gc.getDefineINT("TEMP_HAPPY"), 25, religion.getChar())) 

   return szHelp

That takes the TXT_KEY_EVENT_GREAT_BEAST_3_HELP text tag, adding the global variable TEMP_HAPPY, the number 25 and the symbol of your state religion into it. The text tag itself looks like this:

<English>[ICON_BULLET]%D1[ICON_HAPPY] in all cities with %F3_religion for %d2 [NUM2:turn:turns]</English> 

And finally, here’s the rest of the text for the event.

   <English>%s1_civ_adjective hunters have discovered a great beast lurking near one of their camps</English> 
   <English>A great beast has been discovered near one of our hunting camps</English> 
   <English>Let it breed and give offspring. Hunt sparingly.</English> 
   <English>Looks like it could feed many people. Organize a hunting party!</English> 
   <English>Hunt it? Are you mad? The beast is a manifestation of a divine spirit!</English> 

I hope this guide was useful in providing an insight into how to mod events in BtS. Remember that you can also download a small event mod at [insert link], which contains the events described in the examples above, as well as a few other tweaks and new events.

Good luck with your modding, and be bold!


16.0 Appendix C - Links

Solvers Event Guide for Beyond the Sword - Updated copy of Solvers Event Guide along with plenty of code examples. A great place to ask any Event questions and get ideas.

Beyond the Sword Editor

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License