xienwolf
Deity
==================================================
================ Table of Contents ===================
==================================================
- When to Mod the DLL
- Setting up the SDK
- What's up with all the files? (introduction to the function of various source files)
- A word to the wise...
- Cloning an already existing Boolean XML tag (Moving <bNoBadGoodies> from UnitInfos to PromotionInfos)
(Absolute beginners start here, we will discuss a lot more detail about C++ in general during this walkthrough than during any future walkthroughs)
- Creating a completely new Boolean XML tag (Adding <bUnique> to UnitClassInfos AND BuildingClassInfos - This tag will allow us to create modular civilizations more easily making Unique Units which do not replace anything else)
- Cloning an already existing Integer XML tag (Basically the same as a Boolean, but now to pass a number instead of an absolute, replace "is" with "get" and "bool" with "int")
- Schema & XML
- CvInfos
- CvGameTextMgr
- Functional Parts
- Exposing to Python
- Creating a completely new Integer XML tag
- Schema & XML
- CvInfos
- CvGameTextMgr
- Functional Parts
- Exposing to Python
- Cloning an already existing String XML tag (Actually treated as an integer in the code, but then "cast" to an enumerator later. Need to use getInfoTypeFor commands to find the right number to save, then treat it just like an integer)
- Schema & XML
- CvInfos
- CvGameTextMgr
- Functional Parts
- Exposing to Python
- Creating a completely new String XML tag
- Schema & XML
- CvInfos
- CvGameTextMgr
- Functional Parts
- Exposing to Python
- Cloning an already existing Array XML tag (Moving <TradeYieldModifiers> from TraitInfos & CivicInfos to TechInfos)
- Creating a completely new Array XML tag
- Schema & XML
- CvInfos
- CvGameTextMgr
- Functional Parts
- Exposing to Python
- Other Functions:
- Adding a Global Define
- Adding a GameOption
- Creating a "Python Callback"
- Creating a Popup
- Adding a new item (Widget) to the interface screen
In Civ, you have 3 choices of where to Mod: XML, Python, and DLL. I'll briefly describe what sets each one apart from the other.
XML
Modding in XML is pretty easy. The only tool you need is a text editor (You COULD just use Notepad, but most people prefer fancier tools like Notepad++, which are still free and much more friendly to use), and the only things you really need to understand are which file to look in, and how to tell one entry apart from another.
Editing XML is what you do when you think a value should be slightly different (hills should be a 30% defensive bonus, not a 25%), or on a different object (Warriors should get better results from Goody Huts, not Scouts). It is also required to add a completely new object to the game (now there is a new Technology: Saturday Morning Cartoons!).
What XML editing cannot do, is change the fundamentals of how things work (you can follow up to 5 religions!), or how things interact (My Mustketmen gain more movement if I own Horses).
If you change something in XML, it will not have any effect until the next time you launch your Mod (from Desktop or main BtS menu).
Python
Python is a location where you can do almost anything. It can be a bit tricky to get accustomed to because you have to know what commands will actually do something, the proper format for those commands, and the proper format for Python in general. The dependance on "white space" can be frustrating (errors because you didn't indent a line properly), but can also be liberating (you don't have to always remember a stupid symbol at the end of each and every line). Editing Python can be done with any text editor, just like editing XML. It doesn't look nearly as bad in Notepad as XML does, but Notepad++ and other more complicated programs still look far better, and often offer tools to help you properly format everything.
Python allows you to change hundreds of things in the game. The primary limitation is that you do not always have access to every piece of information you might like to know, you can only act when called upon to act, and that you cannot easily save your data.
90% of the "new functionality" which someone might dream up can be handled with python editing. XML is still required to add new items to the game (additional units, new Civilizations, more Technologies...), but Python is able to adjust most of the values set in XML dynamically during the course of the game.
A major drawback to python is that things you do here aren't automatically parsed into the Civilopedia, so you have to be careful to write your own documentation, preferably making it readily available in game, but at the least making it easily located along with your download. A second significant drawback is that it is nearly impossible to teach the computer how to understand what you have done in Python and how to take advantage of it in the way a Human might. The final significant drawback to python is that it can really slow down the gameplay if you use too much of it.
Changes in python can be made while the game is in progress. There are a few things which will cause significant errors when you return to the game, but the majority of what you do can be edited, saved, and then loads itself into the game immediately for testing. This makes doing small adjustments to find the exact right values painlessly simple.
DLL
The DLL is the most traditionally intimidating manner in which to mod Civ. This is completely due to the requirement that you compile what you have done before you can test it in game. This is a process which can finish in 2 minutes for easy changes, or take up to 20 minutes for more involved changes. Plus the not-to-insignificant time invested in setting up the tools required to edit and compile. But with walkthroughs readily available on the forums, it is more about taking some time to sit down and carefully follow directions than it is about actually having technical knowledge.
As with Python, the DLL doesn't exist for the purpose of adding new items to the game, that is completely the territory of the XML. But unlike Python, the DLL is able to be used to add new CLASSES of items into the game (I know we have units and buildings and cities and junk, but I want to also make Clothing, Vehicles, and Rural Communities!). There are very few limitations on what can be done in the DLL. You can interrupt any portion of the game at absolutely any point you want (if combat is happening between two units, and both of them have lost 50% of the health they had at the start of battle, I want them to stop and play Rock, Paper, Scissors!)
The only real limitations in the DLL are unlikely to matter to most modders. But some things do remain inaccessible. Most of these deal with graphics on a level which is unlikely to come up due to few people having the graphical AND programming skills at the same time to contemplate such changes. The other limitations are more a matter of practicality. It is considered "bad form" to "Hardcode" the DLL. That is, to have it directly refer to a specific item in your XML structure (like UNIT_WARRIOR) and treat it differently than it would anything else. It is preferred in such cases as that either to use Python, or to create a new XML field (like <bIAmSpecialSoThere>).
Many things can be accomplished in either Python OR the DLL just as easily. In those cases it is usually a question of how often it will be used, and how certain you are that you will keep it the way it is to decide which to use. If you will often change things to find the precise proper balance, keep it in python so that you can change it easily (no recompiling required). If it will be done VERY often (every time a unit moves), or does a LOT at once (checks every plot of the map), it is usually best to place it in the DLL.
In rare cases, you have functions which take a lot of time, so should be in the DLL, but are also VERY specific, so should be done in Python. One might be tempted to break custom and hardcode the DLL for these cases, but instead you can use BOTH the DLL and Python. You do that by creating a "Callback" function, which we will cover at the very end of these tutorials.
Changes in the DLL require that you compile the DLL, replace the previous version of the DLL, and then reload the mod.
If you were able to understand python, you can understand C++. Firaxis was kind enough to use function and variable names which are fairly easy to understand, and it all works much like python does, you have functions which do things, and very often these functions call each other.
This is a nice section to write. Kael and Refar are your friends. Both options are free too.
You can set up Codeblocks with Kael's instructions. Codeblocks is pretty user friendly and nice to get used to at the start. There are some "wrong ways" to compile the SDK, and with Codeblocks, it is very hard not to do it right.
The alternative method is to set up Visual Studio 2008 Express with Refar's guide. This one requires quite a bit more work to set up properly, but the guide still holds your hand nicely and it isn't too hard overall. I would actually encourage you to use Codeblocks and get comfortable with modding the DLL, then "graduate" to VS2008+. The reason that you WILL move on to using 2008 sometime is that you can create what is known as a "Debug DLL." This is a method of finding problems in your code far better than you ever dreamt of before, but you have to understand things pretty well before it is worthwhile.
Due to the release of 3.19, and the updating of Codeblocks and Visual Studios since each of these guides were written, you can look in the Wiki for better updated information, primarily the 3.19 version of the Makefile for Visual Studio
Yes, there are lots of files. But there are lots of XML and python files as well. The point is that you won't use quite a few of them. I'll introduce you to a couple of the files which will be your friends, you can stumble into the others later on. The experience you'll have by then will make answering your questions easier.
Any file that ends with .h is what we call a "Header file." Functions that you create have to be mentioned here, and new variables you create to track data need mentioned here as well (not EVERY variable you ever use, just things you want to save longterm.
Files which end in .cpp are the main files, called "Source files." What happens in here actually does something and controls the game.
Though you might not deal with them until you are quite a bit more comfortable with modifications in the DLL, files ending with AI.cpp focus mostly on controlling how the computer plays. Very little in here actually does something (changes things in game that is), instead it is focused on making the AI decide what to do about life in general.
The beginning of the file names is important as well. If the file starts with Cv, it actually does something. If it starts with Cy, it allows python to do things. This is a process known as "exposing" your functions to python. Most of the time you are trying to allow python to get information (like pUnit.getFirstStrikes()). It can also be used to allow access to functions which do things (like pUnit.changeName("Ralph")). But it doesn't enable functions in python like "def onUnitLost()," that is a bit more complicated and will be covered later (MUCH later). For the time being, we will assume that you don't bother to use python anymore. You are in C++ now, learn it, love it, live it
Ok, so let's begin the introductions!
- CvInfos.cpp & CvInfos.h
- Every time that you add something to the XML (a new field), you will have to add it to this file first. What you do in here is always pretty spread out and can get a bit confusing. But that is what this thread is all about
- CvGameTextMgr.cpp & CvGameTextMgr.h
- This is another file where you have to modify it for almost everything that you do. Unlike most files, you will rarely add new functions or variables, so you will rarely have to modify the header file (remember, that is the file ending with .h). Doing changes here will always be fairly voluntary, but the people who play your mod will love you for it. This is how you set up automated documentation in the pedia
- CvCity.cpp, CvCityAI.cpp & CvCity.h
- As I said, Firaxis was nice about the names they chose to use. You should be able to understand what the next couple of files do on your own. I'll be explaining a few of the things you can't just guess from the filename (and for those of you a bit slower on the uptake, CvCity files are for changing data about a city )
- You may have played Civ long enough to realize that buildings kind of act like Promotions for your city. They enhance your stats/capability in some way. So one might suspect that most of the information from a building will be included in CvCity. That is about 70% correct. However, a lot of information is left on the building (CvInfos), and a fair amount is actually placed on the Player (CvPlayer) or the Team (CvTeam). But buildings will be one of the most important things we deal with in CvCity. Specialists and general terrain will rank in at a tie for second most frequent, and when you start to work with AI
- The AI file here is mostly focused on 2 things: What to build in the city (unit/building/project), and what to build on the map (improvements)
- CvPlayer.cpp, CvPlayerAI.cpp & CvPlayer.h
- Ok, so now we have the Player data. This file can be a bit tricky because it interacts with so many other files, and some things you might think belong in here may actually belong in one of them.
- Mostly, Player data will contain information about your traits, your Civilization, and your Civics/Religion. It might also contain some information about Wonders you own though, as well as some other more creative things which a person may mod into the game
- Player data holds a couple of "raw number" type of information as well, like a list of what events you have already had, which feats you have accomplished, your current treasury size, and espionage point data
- One thing you might suspect belongs here would be Technologies. But you are completely halfway wrong on that one Techs go on your Team, with a very few exceptions.
- The AI file here contains quite a bit of information, mostly for a beginning modder you will probably care that it deals with decisions about what civics to select, which tech to research, and attitude values toward other leaders, possibly you also care that this is where the AI decides how/where to found cities, what to agree on in diplomacy and which units to delete if it needs to
- CvTeam.cpp, CvTeamAI.cpp & CvTeam.h
- Unfortunately those of you who play mostly single-player games and don't often form permanent alliances will not have a very natural grasp of what belongs to the team, and what belongs to the player. So if that is the case for you, just remember to always check in both sets of files for information you want to find/modify
- Team data tracks what techs you have, and is quite important for war and UN matters
- Includes capitulation mechanics (such as land target definition, power measurements, etc), voluntary vassalage, trade denials, etc. When in CvTeamAI, DENIAL_[insert phrase] simply refers to the message the AI will give when an option is 'redded out'. Thus, NO_DENIAL (always with human, and with some trade options relating to vassals) means that the option is never 'redded-out'. The rest tend to be self-explanatory.
- CvUnit.cpp, CvUnitAI.cpp & CvUnit.h
- This and CvCity are really where most of modding will take place. While buildings enhance a city, promotions enhance a unit. In general, information from the promotion is loaded onto the unit when it gains the promotion, but in a few cases it is left in CvInfos and called on when required (in VERY few cases). Also, the data for the unit itself winds up being split between CvInfos and CvUnit. If the information isn't expected to ever change all game (like if a unit can move on land or on water), then it is left in CvInfos and called from there. But if information is likely to change (like number of movement points, which can be augmented by a promotion), then it is most likely loaded onto the unit when it is created. This is a fairly important distinction for a modder, and many times you will probably have to move things from being just in CvInfos to being just in CvUnit. I won't go into the specifics of what is in CvUnit really as most players are quite familiar with what a unit can do
- AI here is again pretty complicated, but it actually gets scattered across a LOT of files. CvSelectionGroupAI.cpp handles quite a bit about the specifics of a unit, while CvUnitAI.cpp will handle mostly logistics and short term decisions that it may need to make, like where to move, what promotion to take, and if it should upgrade or not
I will not be including any comments in the code because it just inflates the character count and gets in the way of reading what I post in the [ CODE ] blocks here on the forums, but in your own DLL you really REALLY want to comment EVERYTHING, and make it something noticeable.
I personally stole my comment style from the World of Civilization team. It is quite a nice setup, easy to locate when scrolling through a file, stands out nicely in WinMerge, and allows you to revert your code quickly. But in the end, you can use whatever you really want to use, or nothing at all.
The comment style I like to use is this (trust me, it looks better in C++ where the lines aren't broken up by silly character wrapping):
Code:
/*************************************************************************************************/
/** Xienwolf Tweak 03/07/09 **/
/** **/
/** **/
/*************************************************************************************************/
/** ---- Start Original Code ---- **
/** ---- End Original Code ---- **/
/*************************************************************************************************/
/** Tweak END **/
/*************************************************************************************************/
This allows me to record the date I wrote the changes (which I frequently don't update and actually never refer to... as I said, use it how you want to use it ), and to place a nice searchable name. In the two blank lines at the top I will write what I am doing with the edit, like in this example:
Code:
[COLOR="DarkOrchid"]/*************************************************************************************************/
/** Xienwolf Tweak 09/06/08 **/
/** **/
/** Allows for Multiple Buildings with the Hide Units or See Invisible Tags **/
/*************************************************************************************************/
/** ---- Start Original Code ---- **
m_bHideUnits = false;
m_bSeeInvisible = false;
/** ---- End Original Code ---- **/[/COLOR]
m_iHideUnits = 0;
m_iSeeInvisible = 0;
[color="DarkOrchid"]/*************************************************************************************************/
/** Tweak END **/
/*************************************************************************************************/
[/COLOR]
Everything in Purple is ignored by the compiler (commented out)
Since using the characters: /* starts a comment of unlimited size, the code itself ignores everything else until you use the characters */. So if you look closely you will notice that at the end of each line I terminate the comment, EXCEPT the line which reads "Start Original Code." Since I do not have the final slash mark, the comment doesn't end, and those two lines are ignored by the compiler (it is as good as deleting them, the final DLL filesize will be no larger than normal if I transcribed all of Leo Tolstoy's "War and Peace" inside a comment block. So be verbose, make sure you remember what you did and why).
As I said though, I like this style because it is very flexible. Look at how little I have to change to undo this edit completely (marked in orange)
Code:
/*************************************************************************************************/
/** Xienwolf Tweak 09/06/08 **/
/** **/
/** Allows for Multiple Buildings with the Hide Units or See Invisible Tags **/
/*************************************************************************************************/
/** ---- Start Original Code ---- **[COLOR="#ff8c00"]/[/COLOR]
m_bHideUnits = false;
m_bSeeInvisible = false;
/** ---- End Original Code ---- [COLOR="#ff8c00"]**[/COLOR]
m_iHideUnits = 0;
m_iSeeInvisible = 0;
/*************************************************************************************************/
/** Tweak END **/
/*************************************************************************************************/
So, I added a single slash and removed one other slash. With that small change, the code goes back to seeing what was originally written, and I have my editted information still available for some day in the future when I decide that I want to fix whatever bug convinced me to remove these lines. I would of course change my comment to say when I have undone my edit here so that 3 years down the road when I stumble across this I don't wonder about my sanity (well... not any more than normal at least...)
The other thing which is useful is to keep a regular pattern to how you fill in your comments, this allows you to search much quicker. For instance, every edit that I make contains my name in it somewhere, but only once. This allows me to search for my name (which is quite unlikely to show up anywhere other than my changes) and instantly find EVERYTHING that I have EVER changed in the sourcecode (quite a hefty list now -- 1087 entries in 74 of the 188 total source files --, so quite useless of late. But I had to use it quite often early in my programming experience when bugs happened that I knew were my fault, but had no clue how to fix. I just searched for my name, swapped out the two slash marks to remove all my edits, and slowly added them back in one at a time. Took forever, but it worked)
The format I like to use for adding new XML tags (which require lots of editting in the same places for just "paperwork" instead of actually working code. You'll see...) is as follows:
Code:
/*************************************************************************************************/
/** New Tag Defs (VictoryInfos) 01/16/09 Xienwolf **/
/** **/
/** Initial Values **/
*************************************************************************************************/
/*************************************************************************************************/
/** New Tag Defs END **/
/*************************************************************************************************/