Dynamic Traits

Archid

Warlord
Joined
Oct 30, 2009
Messages
296
Location
North Wales, UK
This is an implementation of the Dynamic Traits mod described by Grey Fox here. The source code was never released and I wanted to try the concept out so I have reverse engineered the dll code from the description of the functionality on the original mod page. Obviously any errors in the dll are purely mine and nothing to do with Grey Fox.

In implementing the mod I removed all the python (apart from GUI screen changes) and implemented them via new XML files in the dll. This means that there is no requirement for all the buildings, improvements, etc. to be hard coded in various python files.

For a list of the functionality please read the original mod page as this mod should be the same, all that has changed is the way that it is implemented. I have also included all the show case changes form the original mod so you can compare how they are implemented and see how the new XML files fit together.

The core difference between the implementations are the TraitTriggerInfo definitions in the new CIV4TraitTriggerInfos.xml file> Each of these contains the definition of a set of changes to the trait counters contained in triggers that are fired by various events in the game. The triggers have a set of prereqs associated with them to determine when they should be fired and the associated trait changes made. The second part of the puzzle is a new enumeration type TraitHookType defined in the GlobalTypes file. This lists all the points where the triggers may be fired from.

Download here

All changes are marked with DynTraits

There is a documentation folder with a set of html files that detail all the XML file changes and what they do.

Revision History
=============
0.5 Fixed bug in CvGameTxtMgr where hovering over the flag for a player that had a trait that modified capital yields/commerce would cause a CTD
Fixed bug in CvPlayer where a trait may not be correctly decremented if both the bFloorZero and bNegative tags were set

0.4 Added missing trigger data to v0.3 fix
Added religion type as trigger Prereq for the Change Religion hook

0.3 Fixed bug in CvUnit where owner of a unit killed was not passed as an argument

0.2 Fixed bug in CvGlobals where incorrect loop counter used

0.1 Initial Release

Credits
=============
- Grey Fox for the original concept and the XML schema files that I used to work out what the mod was supposed to be doing from
 
The trait triggers work a bit like the event system in that you have the definition of the Trait in one file with another file (TraitTriggerInfos) defining when the trait counter is changed, and by how much. The events (Hooks) that can cause the counter to be changed are stored as enum values so are defined in /Assets/XML/GlobalTypes.xml.

Process in short is:

1 - Game runs along until it reaches a hook (e.g. one unit killing another) from the GlobalTypes.xml in the dll code
2 - All the TraitTriggersInfos that are associated with that hook are then processed
3 - Traits get their counters changed based on the info in the TraitTriggerInfo

I have only added the places where GreyFox had hooks to change the counters for now, so I need to expand it a bit to add some new ones in such as Improvements being built, etc. The way it is coded makes it very simple to add new hooks so those can be added almost at will.

I have moved the existing trait changes over to the new system where there are hook's in place for them so you have some examples. The easiest way is to look at the examples in the TraitTriggerInfos and work your way backwards from there.

Walking through a couple of simple examples:
a - When the player constructs any building increase the Industrious trait counter by +5
b - When the player constructs a religious shrine increase Spritual by 10%, but the change must be at least +5 and capped at +25 additionally increase Organised by +2

Spoiler :

The process is the same for both:
1 - Identify the hook and any available options you need from GlobalTtpe.xml file. In this case it is the TRAITHOOK_CONSTRUCT_BUILDING and we have the shrine option. The options will all have a corresponding prereq tag in the TraitTrigger file

2 - Identify the traits from the Trait file: TRAIT_INDUSTRIOUS, TRAIT_SPIRITUAL & TRAIT_ORGANIZED

3 - Create the trait triggers that links these together.
Each trigger has 2 main parts: The trait change section and the prereq section. You can combine multiple trait changes into a single trigger IF the prereqs match. In our case we have 2 different sets of prereqs: 'all buildings' and 'shrine only' so we need 2 triggers.

All Buildings
======================
Firstly we need to define a unique name for the trigger:
Code:
<Type>TRAITTRIGGER_ALL_BUILDINGS</Type>

The trait change section is all contained in a single tag <CounterChanges> to increment Industrious by 5 we would use:
Code:
<CounterChanges>
  <CounterChange>
    <TraitType>TRAIT_INDUSTRIOUS</TraitType>
    <iModifier>5</iModifier>
  </CounterChange>
</CounterChanges>
You then need to define under what conditions these changes are made.
You always need to define the hook, and optionally any prereqs. For the all buildings there are no addtional prereqs so we just need the hook:
Code:
<TraitHookType>TRAITHOOK_CONSTRUCT_BUILDING</TraitHookType>

Now we can put the complete all buildings TraitTrigger together:
Code:
<TraitTriggerInfo>
  <Type>TRAITTRIGGER_ALL_BUILDINGS</Type>
  <CounterChanges>
    <CounterChange>
      <TraitType>TRAIT_INDUSTRIOUS</TraitType>
      <iModifier>5</iModifier>
    </CounterChange>
  </CounterChanges>
  <TraitHookTypes>
    <TraitHookType>TRAITHOOK_CONSTRUCT_BUILDING</TraitHookType>
  </TraitHookTypes>
</TraitTriggerInfo>

Building a Shrine
============================
The second scenario is for when a shrine is built. Firstly define its unique name
Code:
<Type>TRAITTRIGGER_BUILDING_SHRINE</Type>

There are 2 traits that get modified in this scenario so we need 2 entries in the <CounterChanges> element. The first to say that Spiritual gets a 10% increase in the trait counter, but will get at least +5 and no more that 25; the second to give Organised a flat +2 to the counter
Code:
<CounterChanges>
  <CounterChange>
    <TraitType>TRAIT_SPIRITUAL</TraitType>
    <iPercentChange>10</iPercentChange>
    <iPercentChangeMin>5</iPercentChangeMin>
    <iPercentChangeMax>25</iPercentChangeMax>
  </CounterChange>
  <CounterChange>
    <TraitType>TRAIT_ORGANIZED</TraitType>
    <iModifier>2</iModifier>
  </CounterChange>
</CounterChanges>

We now need to define the hook, which is the same as before
Code:
<TraitHookType>TRAITHOOK_CONSTRUCT_BUILDING</TraitHookType>

In this scenario we also have a prereq condition (Shrine) so look for the assocated tag in the Trigger:
Code:
<bPrereqShrine>1</bPrereqShrine>

Putting it all together we get:

Code:
<TraitTriggerInfo>
  <Type>TRAITTRIGGER_BUILDING_SHRINE</Type>
  <CounterChanges>
    <CounterChange>
      <TraitType>TRAIT_SPIRITUAL</TraitType>
      <iPercentChange>10</iPercentChange>
      <iPercentChangeMin>5</iPercentChangeMin>
      <iPercentChangeMax>25</iPercentChangeMax>
    </CounterChange>
    <CounterChange>
      <TraitType>TRAIT_ORGANIZED</TraitType>
      <iModifier>2</iModifier>
    </CounterChange>
  </CounterChanges>
  <TraitHookTypes>
    <TraitHookType>TRAITHOOK_CONSTRUCT_BUILDING</TraitHookType>
  </TraitHookTypes>
  <bPrereqShrine>1</bPrereqShrine>
</TraitTriggerInfo>


When the game runs and any player constructs a building both these triggers will be processed for the player completing the building. The first trigger will always fire (make the defined trait counter changes) as it has no additional prereqs, but the second will only fire if the building is a shrine.
 
Certainly no mod related to Fallout. :p
 
This one is much more fully implemented, originally archid worked on a backward engineered version using rife as one of many sources, for FTTW.

I think Rife abandoned the majority of the original functionality of the dyn trait modcomp.

Archid has since rebuilt the whole source code from more or less scratch, using the original dyntrait functions as a plan and rebuilding the source code from nothing.

So it is a much larger implementation than what they had in rife. Also it is standalone with source code, so now anyone can merge it with their mods.

Not to mention other improvements like moving most of the python content to a DLL/Xml system, which is more or less superior in everyway. If you use a modified dll for your mod.
 
AFAIK Dynamic Traits was (at least partly) implemented in RifE...

As Lib says I originally started by looking at the RifE source, but given that it had a very limited implementation I decided to re-write it from scratch adding in the features such as trait classes, temporary traits, percentage based counter changes, aggregating trait sequence effects in the UI, etc.

I have also pulled it all into the dll, configured via XML files. There was a lot of additional maintenance overhead using the original python implementation where each building, improvement, etc. had to be hard-coded in Python to match the associated XML file and I hate hard-coding things as they always get out of sync.
 
Hi Archid,

I think one of the TraitTriggerInfo tags is not working.

<bFloorZero>1</bFloorZero>

In the <CounterChange> section.

If I am understaning it correctly, it is supposed to stop the overall score of a trait from going below zero, but when I tried adding something to reduce the score each turn of a trait, it went to -1 instead of staying at zero.

EDIT: Nope I was just using it wrong!

I have to combine it with bnegative and make it a positive number, then it seems to work. (Although to really test it I need to get to the point where it can lose numbers and check it still does!)
 
Hi Lib

I'm back from the dead now, though still only getting mails from the forum once in a blue moon!

I have looked at the code for this again and re-tested it using the isolated code attached to this thread and the <bNegative>1</bNegative> tag appears to be working for me. I looked at the FTTW code and the required stuff is in there as well.

My demo code shows this as it gives -1 to the Aggressive trait every round and the explorers & horselords every 4 rounds. Used in combination with <bFloorZero>1</bFloorZero> it will not reduce the total trait count below 0. Remember that <bNegative> is a boolean so should only ever have a value of 0 or 1.

Trait reduced by at least 1 every round, allowing trait to go negative (no bFloorZero):
Spoiler :
PHP:
<TraitTriggerInfo> <!-- Player Every Turn -->
	<Type>TRAITTRIGGER_TURN1</Type>
	<CounterChanges>
		<CounterChange>
			<TraitType>TRAIT_AGGRESSIVE</TraitType>
			<iPercentChange>2</iPercentChange>
			<iPercentChangeMin>1</iPercentChangeMin>
			<bNegative>1</bNegative>
		</CounterChange>
	</CounterChanges>
	<TraitHookTypes>
		<TraitHookType>TRAITHOOK_PLAYER_TURN</TraitHookType>
	</TraitHookTypes>
</TraitTriggerInfo>

Trait reduced by at least 5 every round, but never goes below 0:
Spoiler :
PHP:
<TraitTriggerInfo> <!-- Not Civic Slavery -->
	<Type>TRAITTRIGGER_TURN1_NOT_CIVIC_SLAVERY</Type>
	<CounterChanges>
		<CounterChange>
			<TraitType>TRAIT_CRUEL</TraitType>
			<iPercentChange>10</iPercentChange>
			<iPercentChangeMin>5</iPercentChangeMin>
			<bNegative>1</bNegative>
			<bFloorZero>1</bFloorZero>
		</CounterChange>
	</CounterChanges>
	<TraitHookTypes>
		<TraitHookType>TRAITHOOK_PLAYER_TURN</TraitHookType>
	</TraitHookTypes>
	<PrereqNotCivics>
		<CivicType>CIVIC_SLAVERY</CivicType>
	</PrereqNotCivics>
</TraitTriggerInfo>
 
Archid you are back! Hooray!

I got a bunch of different issues and bugs I would love your help to sort out!

Hmmm....Flitz reported the same when he tried to test it, but for me it just does not work.

It adds points instead of taking them away, but only adds them once it gets off of zero.

I also have a bunch of bugs in the trait tags (I think it might be from the civic crossover tags)

But some of them cause the game to crash (when mousing over the Flag) and others either don't show up their effects, or show up the wrong effects, or have the wrong effects! :crazyeye:

patchboy1000 <-- This Patch should contain some of the errors that cause the game to crash.

(It may or may not contain the negative not working bug, I cannot remember if at that point I removed the negative trait counters, as I added a new system to make sure that you could only have one active trait per civic type. As a work around till it could be fixed... or you appeared to show me how I screwed t up :D)
 
New version (0.5) uploaded that resolves a couple of issues

1 - Fixed CTD if a trait modifies capital yields/commerces and you mouseover the player flag
2 - Fixed bug where traits were not always decrementing properly

thx to Lib for finding and finding these :thumbsup:
 
Hey buddy,

I was wondering if I could suggest a possible addition to the concept.

A new box for the 'flag' Trait info.

I found when you have lots of Traits (About 6+) on my resolution. the Trait info from the 'flag mouse over' goes off the top of the screen.

Would it be possible to make something like a popup box with a scroll bar to display this info, when you click the flag or some other function, like a button next to the 'Trait Counter' screen button (Top Right) or a 'tab' inside that window.

Just the same information but in a scrollable type box/format so you can look at all your traits info even when you have lots and lots!
 
Me again!

We have discovered something odd happening with DynTraits in FTTW, it seems that on our normal and quick speed trait points don't get applied, also every now and then we get these wild negative numbers appearing for a traits points score (Like -74896943289) we have also seen them randomly disappear and reappear between turns (The wild numbers)
 
Top Bottom