Menu

CivEffect

Nightinggale
Attachments
CivEffect.png (32007 bytes)

CivEffect

CivEffects is a concept where multiple XML files share a number of tags, which then have the same effect ingame. The effects usually stack and it doesn't matter precisely which XML file the effects originates from.

implementation

The DLL handles CivEffects using a class hierarchy. However vanilla isn't using class inheritance much and it is possible to mod vanilla with little or no knowledge of how classes can inherit each other. To make this page readable to as many modders as possible, the following will contain the design as well as explaining important parts of the underlying C++.

Note: filenames are subject to change. Some of them have been named before the name CivEffect appeared.

The classes are defined in CvInfoCivic.h

vCivEffectInfo

This is the most important class of everyting in this file. It contains all the tags, which makes up what a CivEffect is (almost 100 different tags).

CvCivEffectGiftInfo

This is a shared class, which tells what the player will get for obtaining this CivEffect. Some are for the first ever to gain the CivEffect and some are for just gaining it.
Note: the actual implementation to provide the gifts haven't been written yet.

Other classes

There are other classes like CvCivicInfo and CvTechInfo. Those will tell specific details for that particular class, such as tech category and techtree placesment or CivicOptionType.

class inheritance structure

CivEffect
Note: this graph is concept, will be outdated and might not fit the actual code 100%.

The idea around CivEffects is that the get*Info functions are made to return const pointers (not references as the compiler will not complain about missing &, which causes a bug, but it will complain about inforrect const pointer). If a function takes a CivEffectInfo pointer as argument, it can take CivEffectInfo or any class coming from CivEffectInfo. This is used for code like a playering gaining a CivEffect where the function itself is unaware of which XML file the CivEffect comes from and it really doesn't matter.

CivEffects are defined in JIT_ARRAY_TYPES in CvEnums.h
The concept is simple. Anything before NUM_CIVEFFECT_TYPES is threated as a CivEffect. Some functions relies entirely on this enum and will not need updating when more CivEffect files are added. Some functions will need updating, but a general design rule is that they assert if they aren't updated, making it easier to add more files later.

There is a "fictional" JIT type called JIT_ARRAY_CIVEFFECT. CvGlobals generates this based purely on NUM_CIVEFFECT_TYPES and the XML files used by the "real" CivEffects.

The savegame conversion code (for adding/removing XML elements) works on all files in CivEffects XML dir. JIT_ARRAY_CIVEFFECT is once again generated by the DLL based on the actual files.

CvCivEffectInfo is aware of it's own ID in the file it comes from and in JIT_ARRAY_CIVEFFECT and both can be accessed using get functions. The yet to be implemented idea is that there will not be python access code for each tag in each class. Instead if you say need a tag from CivEffect when using a CvTechInfo in python, you ask the techInfo for the CivEffectID and then ask for the CivEffectInfo with that ID. That way new tags will only have to be added to a single python class and then all classes can use it. Taking this concept one step further, we can add functions to write the effect of all CivEffect tags using only the CivEffectID.

Timed CivEffects

hasCivEffect is a short, meaning it can be set to a number. doCivEffects(), called from CvPlayer::doTurn(), will decrease the number if it is more than 0. This mean a CivEffect can be set to 3 and it will automatically disable itself after 3 turns.
Applying a CivEffect permanently can be done by setting it to -1 or any other number below 0.

CvPlayerCivic.cpp

CvPlayer caches the combined values of all tags from all CivEffects currently owned by the player. This will avoid a lot of looping, which could be time consuming as the number of CivEffects is increasing. This takes place at the top of CvPlayerCivic.cpp.

This is followed by reset() and then code to add/remove CivEffects. All CivEffect ownerships are stored in JIT arrays using shorts. This allows a generic add/remove function, which updates the JIT array in the argument as well as add/remove the CivEffect from the cache. This mean functions like CvPlayer::setPerk() is just a frontend to generic code, which handles storing and cache update. Each XML file should have frontend set functions like this. The generic code also updates if the code has ever been researched and gift giving.

CvPlayer::rebuildCache()

Function, which is executed at game start only. It is intended to be able to be triggered by debug code (such as magically invent all techs), but so far only game start is using it. It clears the cache and then loops all files to enable whatever CivEffect the player has.
Calling this function at game start means the CivEffect cache will not have to be saved, which in turn mean savegames will not get corrupted by XML changes (or at least not as easily)