1. We have added a Gift Upgrades feature that allows you to gift an account upgrade to another member, just in time for the holiday season. You can see the gift option when going to the Account Upgrades screen, or on any user profile screen.
    Dismiss Notice

Guide: Adding a Civilization to DoC (updated)

Discussion in 'Rhye's and Fall - Dawn of Civilization' started by Leoreth, Jan 22, 2016.

  1. Leoreth

    Leoreth Friend Next Door Moderator

    Aug 23, 2009
    This is an updated version of the original guide, reflecting changes to the code base that have happened since then. If you use this guide and encounter a mistake, please let me know.

    Okay, I'll try to write a tutorial on how to insert a new civilization.

    First off, I want to clarify some terminology. Usually, when talking about the game, the terms "civilization" and "player" are used interchangeably. In the code, there is an important difference between the two. You can think of players as "slots" for civilizations in the scenario. Let's say, the current RFC scenario has 26 players. These players can be any civilization, it's just that they are defined as Egypt, Babylonia, China etc. in the scenario. All players may just as well be Egypt.

    Civilizations can be added to the game without affecting it at all. For instance, the Sumerian or Zulu civilizations are in DoC but aren't assigned to any player. Adding a civilization to the game doesn't make it appear. A new player has to be created first before you can assign that civilization to it.

    There is a third term called "team" which you will encounter during the process. Teams are comprised of multiple players and are used in BtS to implement permanent alliances (players that form a permanent alliance become a team, sharing techs and other stuff). Permanent alliances don't exist in RFC, which is why teams and players are treated interchangeably. There are always as many teams as players, and every team is comprised of only one player. For ease of use, teams are ordered in the same way as players are, so that the same ID refers to related teams and players. More on that later.

    Creating your civilization

    I'm going to assume you have all the graphics you need for your civilization. I'm also going to assume you know how to edit XML. It's documented in the modiki and there are some guides out there. Generally it is a good idea to always look for an entry that is most similar to what you want to add, copy it and then modify it to suit your needs. You need to edit the following files:

    1) The civilization itself: XML\Civilizations\CIV4CivilizationInfos.xml
    It's a good idea to insert it in alphabetical order (all current civilizations are ordered this way), but that isn't mandatory. A civilization contains a city list that is used for all cities not covered by the CityNameManager. If you know a name on the list is covered by the CNM you should remove it.

    I have added a couple of extra mandatory XML that have to be accounted for when adding a new civ:

    Identifier: a three letter identifier for the civ, it must match the identifier used for the civilization in various text keys (e.g. UHV or UP texts).
    StartingYear: the spawn year of the civilization (impacts interface only)
    LoadingTimes: the estimated loading times for the three scenarios
    Rating: the number of stars in the different rating categories in the civilization information screen.

    2) Their leader: XML\Civilizations\CIV4LeaderheadInfos.xml
    If you don't have your own leader personality, I suggest you try to think of which existing leader comes closest to the desired behavior of the new LH and just copy their entry.

    3) Their unique building: XML\Buildings\CIV4BuildingInfos.xml
    It's a good idea to copy the building it replaces and make some changes. I suggest you insert the new UB after the building it replaces, this is the current standard.

    4) Their unique unit: XML\Units\CIV4UnitInfos.xml
    Basically the same procedure as with buildings.

    5) Graphics
    If you copy the XML entries, I suggest to keep the ART_DEF_... entry unchanged in the beginning. Everything will look like the building/unit/leader it replaced, but you can be sure that the pointers to the graphics are correct and the mod should load fine without crashes (always start the mod after an XML change to make sure you have no syntax errors). You can create new ART_DEF_... entries in the XML if you have art files they can point to.

    Civilization button and flag: XML\Art\CIV4ArtDefines_Civilization.xml
    Leaderhead graphics: XML\Art\CIV4ArtDefines_Leaderhead.xml
    Building button and graphics: XML\Art\CIV4ArtDefines_Building.xml
    Unit button and graphics: XML\Art\CIV4ArtDefines_Unit.xml

    6) Text
    If you have given your new civilization/leader/unit/building a new TXT_KEY_..., it will show up as that in the game because you haven't yet defined what the text key refers to. You can do that in the XML\Text\ folder. The names of the files in there are very explicit and descriptive, and for the sake of clarity you should put everything in its appropriate file.

    The DynamicNames subfolder is for dynamic names (duh), should also create a new file named DynamicNames_[your civ's name].xml there where you can store its dynamic names. You don't have to put in anything there for the mod to work.

    Adding a new player to the scenario

    Right now we are at the stage where a new civ with all its stuff is in the civilopedia, but doesn't exist in the scenario. The mod should run fine, but behave unexpectedly in some occasions. That is because several Python and C++ constants still need to be adjusted after you have added new civs, buildings and units to the XML files. All of this will happen in the process.

    7) Scenario files: Private Maps\
    This is where new players can be added. The following changes are required for all scenarios in this folder.

    Adding a team: as I said, every player needs its own team, so you first have to add a new team. You can do this by adding another
    to the long list of identical statements right at the beginning of the file. You don't have to set anything else for teams (don't worry about techs, we're going to do that in Python later).

    Adding a player: Just replicate the pattern from the other players:
            LeaderType=[The leader you have added to the XML]
            CivType=[The civilization you have added to the XML]
            Team=[The position of this player entry in the list of player entries]
    The position of this entry is very important because the order of entries determines the order of players in the selection screen of the scenario. This order has to be identical to the order of spawn dates, and must be the same in all scenarios (don't worry if this civ is already alive at the beginning of one of the scenarios). The Team variable has to be ascending for all entries. That means you must increment this value for all players that come after your new one.

    If you have multiple leaders, the leader entry only determines who you will see in the selection screen (and the human players leader as far as savegame name suggestions etc. are concerned). AI leaders will always be assigned by Python.

    If your scenario has independents and barbarians present at the beginning of the game (anything except 3000 BC), you must find all their unit (BeginUnit/EndUnit) and city (BeginCity/EndCity) entries and increment their UnitOwner/CityOwner values by one. This is because your new player has invariably been inserted before the independents and barbarians, which means their ID has increased by one, which you now have to account for. The same goes for the PlayerXXCulture=Y entries for cities, where you have to increment XX by one.

    Your new player now exists in the scenario. At this point, the mod is guaranteed to crash on start. To fix this, the new player has to be accounted for in the DLL.

    DLL adjustments

    8) Increase the maximum number of players: CvDefines.h
    Find the line that begins with #define MAX_CIV_PLAYERS and increment its value by one.

    9) Defining the new player's constant: CvEnums.h
    Find the entry "enum PlayerTypes" and add a new constant for your civilization according to its position in the scenario files. Even if you do not intend to use the constant in C++ code (likely if you don't want to code special effects for them), you have to add it so the constants for all following players are increased by one corresponding to their new position.

    10) Adjusting global constants: CvRhyes.h
    Depending on your changes, you have to increment a couple of constants here by one:
    - BEGIN_WONDERS (unless your civ's unique building has already been in the game)
    - NUM_BUILDINGS_PLAGUE (unless your civ's unique building has already been in the game)
    - NUM_PL
    - NUM_CIVS (unless your player's civilization has already been in the game)

    11) CvGame.cpp
    initDiplomacy(): you can define here if you want your player to be at war with the Independents at the start of a scenario

    (All AI code is optional - the game will run without it - but strongly encouraged to give your new civ a unique and historically appropriate behavior.)

    12) Further AI stuff: CvCityAI.cpp (always use the constant you defined in CvEnums.h).
    AI_bestUnit(): find the switch statement for multiple civilizations and add your civilization here if you want it to prioritize building specific unit types.
    AI_bestBuildingThreshold(): find the switch statement for multiple civilizations and add your civilization here if you want it to prioritize or avoid specific wonders.

    13) Further AI stuff: CvPlayerAI.cpp
    AI_bestTech(): find the switch statement for multiple civilizations and add your civilizations here if you want it to prioritize or avoid specific technologies.
    AI_bestReligion(): add your civ to this check if you don't want it to convert to Christianity too easily

    With this, we're done with the DLL changes, you only have to compile your code now. It's important to rebuild the entire project because you changed some header files.

    Python adjustments

    All of these files are in Assets\Python\.

    14) Set constants: Consts.py
    This is basically the Python equivalent of CvRhyes.cpp, which means that you have a lot to do.

    Increase iNumPlayers by one and add a constant for your player in the list below it (order according to scenario file).
    Increase iNumCivilizations by one and add a constant for your civilization in the list below it (order according to the XML file).

    After that comes a list of geographical groups where you have to insert your player according to its location, it should always be in one group per type.

    lNeighbors: insert into list of all players your new player is a neighbor to, and add an own list of neighbors for this player
    lOlderNeighbors: as neighbors, but only includes those that have spawned before

    tBirth: insert your spawn year in the correct location in the tuple
    tFall: year after which a civilization becomes more unstable
    tVictoryYears: to display the turn in the victory goal display
    tRebirth: scripted respawn, make sure to add a -1 for your civ even if you don't want it to respawn
    tRebirthCiv: the civilization a player respawns as (add -1)
    tResurrectionIntervals: list of intervals in which a civ can randomly respawn, add an empty list even if you don't want it to respawn
    tYear: starting year and BC/AD

    tGoals: UHV goal text keys again, this time accounting for game speed too (marathon/epic/normal), tGoals2 is for respawns again, just copy tGoals1 if you don't want it to respawn

    dDawnOfMan3000BC: add your civ here (order doesn't matter here, but I suggest you keep it), you can define the text key XML\Text\CIV4GameText_Dawn_of_Man.xml. If your player is available from start in later scenarios, you might want to set a different DOM text in the following dictionaries.

    The following entries are double for respawns again, just do it twice if you don't want to define a respawn. Order is important again.

    tStartingGold: gold at the beginning of the game
    lEnemyCivsOnSpawn: chance to start at war with (multiple entries increase chances)
    lTotalWarOnSpawn: if it starts at war with these civs, the war will be fought longer
    tAggressionLevel: how often the AI will start wars
    tAIStopBirthThreshold: the chance to fight a newly spawned civ
    tResurrectionProb: chances for a random resurrection
    tPatienceThreshold: how the civ reacts to bribes
    tMaxColonists: number of free settlers and ships the AI will receive during the game

    Increase iNumUnits by one if you added a UU, and add a constant for it in the correct location according to the XML in the list below.
    Increase iNumBuildings by one if you added a UB, and add a constant for it in the correct location according to the XML in the list below.

    Increase iNumLeaders by the amount of leaders you have added, and insert constants for them into the list below.

    In the following, a lot of further maps and constants for your new civilization are defined. They are defined by its civilization constant (iCivXXX) not the player constant (iXXX) unless otherwise noted. The order of insertion does not matter, but for the sake of clarity I suggest inserting them according to spawn date like the existing entries are ordered.

    15) Define AI settler maps: SettlerMaps.py
    This map (dWarMaps) influences both AI settling behavior and the historicity of a tile. A value of 90 or higher makes a historical tile. This is also the value for which the AI will usually settle a tile, the higher it is, the more likely for this tile to be chosen. 20 is chosen for water tiles. 40-90 can be settled by the AI, but are rarely prioritized. Values of 3 mean the tile is forbidden from settling.

    16) Define AI war maps: WarMaps.py
    The dWarMaps map determines how much cities on a specific tile will be targeted in wars by this civilization (useful to guide its conquests in a historical way). Values between 0-10 are used. 10 is usually for their own core which they ought to recover at all costs, 8 for important historical expansion. This map also increases chances of declaring war against players holding many cities with high values here.

    17) Define capital locations, birth, core, and further areas: Areas.py
    Here, entries in tuples (beginning with t) are required and dictionaries (beginning with d) are optional. All entries in this file are by player constant (iXXX). If the elements are a pair of tuples, they describe the bottom left and top right corners of a rectangle.

    tCapital: starting location
    dChangedCapitals: new capital locations after rebirth etc. (bReborn = true)
    dNewCapitals: dynamic capital location changes triggered by a specific event (entering an era etc.)
    dRespawnCapitals: new capital locations after random respawns

    tBirthArea: area flipped on spawn
    dBirthAreaExceptions: tiles excluded from birth area

    tCoreArea: the core of the civilization
    dChangedCoreArea: new core area after respawn etc. (bReborn = true)
    dCoreAreaExceptions: tiles excluded from core area
    dChangedCoreAreaExceptions: tiles excluded from changed core area

    (The pattern for corea areas repeats for normal and broader areas)

    dRespawnArea: area flipped on respawn, if different from core

    dRebirthPlot: the spawn plot for a reborn civilization
    dRebirthArea: are flipped on rebirth
    dRebirthAreaExceptions: tiles excluded from rebirth area

    18) Civilization modifiers: Modifiers.py

    Add your civilization to the lOrder list according to its spawn date. This is the position of your civ in the following tuples of modifiers.

    The purpose of the modifiers should be evident from their names. Except tHealth, they are all in percentage points.

    19) Parameters influencing AI behavior: AIParameters.py

    All entries here are optional, if left your civ will use the default values you can find in the getter methods.

    dTakenTilesThreshold: maximum number of culturally controlled tiles (by another city) the AI will tolerate for a new city location
    dDistanceSubtrahend: the higher the value, the closer the AI will build its cities to existing cities
    dDistanceFactor: the higher the value, the more the distance to other cities will affect city locations chosen by the AI
    dCompactnessModifier: the higher the value, the more the AI will prefer to found new cities close to its own existing cities (compact vs far flung empires)
    dTargetDistanceModifier: how much the distance to a target city will prevent the AI from trying to conquer it. The value is in tenths, i.e. ten is normal.
    dReligiousTolerance: how likely the civilization is to persecute non-state religions

    20) Script their spawn: RiseAndFall.py

    In the beginning, you should make a copy of the constant from Consts.py and get the PyPlayer and PyTeam objects for your player.

    assign600ADGold(): set their starting gold if they appear in the 600 AD scenario
    assign1700ADGold(): set their starting gold if they appear in the 1700 AD scenario
    init1700ADDiplomacy(): set the relations between players at the beginning of the 1700 AD scenario

    createAdditionalUnits(): spawn the units received should they end up in a war on spawn
    createStartingUnits(): spawn the starting stack (note: the createSettlers() method spawns as many settlers as specified minus the cities already present in their core, but at least one)
    createRespawnUnits(): spawn units received after a scripted respawn
    createStartingWorkers(): spawn workers received after the capital is founded

    21) Adjust barbarians: Barbs.py
    You might not have to do anything here, but it's worth checking if a minor city exists in your new civilizations area, in which case you might want to disable its spawn. You can also add new barbarian spawns here to challenge your new civ, or remove old ones that are now represented by a proper civilization.

    22) Include in city name manager: CityNameManager.py
    If your new civilization has the same language as an existing civilization, you have it easy here:

    getLanguages(): include a check for your civilization and return the appropriate language(s). In every situation, the languages will be tried in order until one is found that has a name for this tile or city.

    If you want to add a new language, increment iNumLanguages by one and include it in the list below (position doesn't really matter). You still have to include your civ in the getLanguages() method as below.

    Afterwards, go to dFoundMaps and make a new entry for your language. As with settler and war maps, I suggest using OpenOffice Calc or a similar spreadsheet editor.

    Also, go to tRenames and define how your new language translates city names. Order is important here, based on where you have inserted your new language in the list above.

    Every city in the CNM is referenced by its identifier in tRenames. For example, the identifier for Venice is "Venezia", but defining a name for "Venezia" in tRenames will also take care for renaming "Venice", "Venedig", "Venise" and so on. You can look up a name in dIdentifiers. If you want to rename a city that is not yet handled in dIdentifiers, you have to add it to that dict.

    23) Adjust the AI communications script: Communications.py
    Add your new player to one of the pools at the beginning of the file. I usually only choose the third one.

    24) Unique Power and Unique Historical Victory: Victory.py
    You can code your UHV in the Victory.py file. Due to the variety of possible victory conditions I won't go into detail here, I suggest you choose similar goals to those that already exist and locate and replicate their code.

    Unique Powers are similar, because they are basically extra rules for potentially every aspect of the game. Usually you will have to locate the part of the code that controls the aspect you want it to affect, and then make an exception there.

    25) The mod should run again now. Have fun with your new civilization!
    Crimean Lord likes this.
  2. Leoreth

    Leoreth Friend Next Door Moderator

    Aug 23, 2009
    Further notes:

    In the future, we are trying to enable editing the settler and war maps in the WB and then export the result to paste into the corresponding file, that should make things a lot easier.

    Also, merijn_v1 has written an additional guide on how to best handle ID changes in the scenario files:
    NKN suggests using regexes:
    I don't plan to do this manually anymore the next time I have to do it. Expect me to start writing an update script soon, I will share it here as soon as I have it together.
  3. merijn_v1

    merijn_v1 Black Belt

    Dec 29, 2008
    The city of the original vlaai
    Some notes I made for myself when adding new civs. Some are useful reminders, others are parts that are missing in the guide.
    (These notes were last updated around the release of v1.15, so some parts might be outdated)

    5) When the UU art, set the <TrainSound> to AS2D_UNIT_BUILD_UNIQUE_UNIT. This is not required, but nice for flavor.
    5) Make sure all button path do NOT start with a comma. (Unless you use atlas') It will cause a CTD when you try to build that item in your city. It is only necessary for units, buildings and projects, as those are the only items that you can build in cities, but it's better to do it for all paths just in case.

    9) Add the new LH to enums.h
    10) Some lines are removed in the current version, so you do not have to edit those anymore.

    26) Optional: Add the dynamic names to DynamicCivs.py
    26) Add the starting leader to DynamicCivs.py (will cause an error if you don't)

    27) Add the starting techs to Civilizations.py
    27) Add the tech preferences and wonder preferences to Civilizations.py (Remove this from section 12) and 13))

    28) Add the list of Great People Names in GreatPeoples.py

    24) Many UHV involve a certain area. You can add that area to the tooltip in Python/EntryPoints/CvScreenInterface.py @getUHVTileInfo(). The text is in Regions.xml.
    24) If you do a wonder build UHV and you want to prevent the AI building that wonder before the spawn of the new civ, add that building to CvPlayer.CPP @canConstruct(). Scroll down until you find a list of wonders. (Hint: search for isHumanVictoryWonder)

    7) You can use this script to easily change the civ constants in the scenario files. (credits for the original script to 1SDAN) You still need to manually add BeginTeam and BeginPlayer. https://forums.civfanatics.com/threads/modmodding-q-a-thread.516755/page-99#post-15188302 (Requires 32-bit version of Notepad++)

    8-13) Maybe a link to the How to Compile a DLL guide is useful.
    (Maybe add the general advice that people who try to build a DLL for the first time to start with building a DLL with unmodded files is also useful.)

    15-16-17) We have the WB editor/exporter now which can be used.
    Last edited: Jan 13, 2019
  4. 1SDAN

    1SDAN Brother Lady

    Oct 27, 2014
    Doesn't this thread need to be updated for the decoupled civ slots? Is the reason it hasn't already because more changes are coming in the future that'll impact such efforts and thus writing up what is essentially an entire additional guide is 無駄無駄無駄無駄無駄
  5. BlackEmperor94

    BlackEmperor94 Chieftain

    Feb 2, 2021
    "dNewCapitals: dynamic capital location changes triggered by a specific event (entering an era etc.)"
    How can I make the civilizations I play with change its capital automatically after a certain event or condition (specifically after a certain year, for example I want the Arabs to change he Capital from Mecca o Damascus automatically after the year 660).
  6. Leoreth

    Leoreth Friend Next Door Moderator

    Aug 23, 2009
    You have to write the code to do that. It's in the History.py module currently, iirc.
  7. BlackEmperor94

    BlackEmperor94 Chieftain

    Feb 2, 2021
    Can you please detail it to me how can I apply this? better if it was specific to this case (Change Arab capital to Damascus after year 660).
    I would really appreciate your help on this.
    I have already learned how to adjust some aspects to the scenario to make it more historically accurate using the guides in this thread, thank you.
  8. Leoreth

    Leoreth Friend Next Door Moderator

    Aug 23, 2009
    I'm not going to teach you to program or program things for you, sorry.
    DanLT3 likes this.

Share This Page