• We have updated our Community Code of Conduct. Please read through the new rules for the forum that are an integral part of Paradox Interactive’s User Agreement.

Limith

Modding for Myself
18 Badges
Apr 7, 2010
3.740
369
  • Darkest Hour
  • Deus Vult
  • East India Company
  • Europa Universalis III Complete
  • Divine Wind
  • Crusader Kings II
  • Heir to the Throne
  • Rome: Vae Victis
  • Rome Gold
  • Sword of the Stars
  • Victoria 2: Heart of Darkness
  • Victoria 2: A House Divided
  • Stellaris Sign-up
  • 500k Club
  • Victoria 2
  • Europa Universalis III Complete
  • Europa Universalis III Complete
  • Europa Universalis IV
I wrote a library for creating event files in Python designed for programmers. It doesn't do checking, so you may end up with invalid commands, but it does allow you to creatively generate complicated events. I will be developing this in my free time since it is required for some things in Darkest Hour Full. It essentially provides classes for various parts of a DH Event File which you can easily manipulate in Python and then print to file or stdout to be copied into your event file.

For examples on usage, you can scroll to the bottom of the Event.py file and look at the main function.

https://github.com/xhh2a/CCIP/blob/master/design/DH Core/org/darkesthour/Event.py

A somewhat simple example here which I was using to procedurally generate a bunch of commands from a text file input.
This example was for generating core/claim, since cores/claims are already defined for countries in revolt.txt and .eug scenarios, so
it was easy to copy+paste that into a text file, and then generate commands from that.

https://github.com/xhh2a/CCIP/blob/master/design/DH Core/org/darkesthour/main.py

More complicated example here which is being used to generate Unification of China events.

https://github.com/xhh2a/CCIP/blob/master/design/DH Core/org/darkesthour/concessionGen.py

To be implemented:
-System of scripts for elections ala AAR style
-Comments
-Verify support for Python 3 (should work afaik)

Changelog:
v0.1.1
Now features while loop 'macro' which implements while loops for commands in events.
v0.1
Works for DHF event syntax.

Examples:
In AAR, we have the great depression module which adds an IC penalty and money penalty. To recover from this, we use the code
Code:
	command = { trigger = { local_flag = gd_cashred_3 } type = free_money value = 3 }
command = { trigger = { local_flag = gd_cashred_9 } type = free_money value = 9 }
command = { trigger = { local_flag = gd_cashred_15 } type = free_money value = 15 }
command = { trigger = { local_flag = gd_cashred_21 } type = free_money value = 21 }
command = { trigger = { local_flag = gd_cashred_24 } type = free_money value = 24 }
command = { trigger = { local_flag = gd_cashred_30 } type = free_money value = 30 }
command = { trigger = { local_flag = gd_cashred_36 } type = free_money value = 36 }
command = { trigger = { local_flag = gd_cashred_45 } type = free_money value = 45 }
command = { trigger = { local_flag = gd_cashred_53 } type = free_money value = 53 }
command = { trigger = { local_flag = gd_cashred_60 } type = free_money value = 60 }
command = { trigger = { local_flag = gd_cashred_75 } type = free_money value = 75 }
command = { trigger = { local_flag = gd_cashred_90 } type = free_money value = 90 }
command = { trigger = { local_flag = gd_cashred_105 } type = free_money value = 105 }
command = { trigger = { local_flag = gd_cashred_120 } type = free_money value = 120 }
command = { type = local_clrflag which = gd_cashred_3 }
command = { type = local_clrflag which = gd_cashred_9 }
command = { type = local_clrflag which = gd_cashred_15 }
command = { type = local_clrflag which = gd_cashred_21 }
command = { type = local_clrflag which = gd_cashred_24 }
command = { type = local_clrflag which = gd_cashred_30 }
command = { type = local_clrflag which = gd_cashred_36 }
command = { type = local_clrflag which = gd_cashred_45 }
command = { type = local_clrflag which = gd_cashred_53 }
command = { type = local_clrflag which = gd_cashred_60 }
command = { type = local_clrflag which = gd_cashred_75 }
command = { type = local_clrflag which = gd_cashred_90 }
command = { type = local_clrflag which = gd_cashred_105 }
command = { type = local_clrflag which = gd_cashred_120 }

This is very long!

What does this look like via generation? We can write something similar via:
Code:
    for i in range(50):
        icmult = 5 * i
        c = Command('free_money', value = 5)
        c.newTriggerGroup().addCondition('local_flag = gd_crashrd_' + str(i*5))
        print(c)
        print(Command('local_clrflag', which = ('gd_crashrd_' + str(i*5)) ))

which results in
Code:
command = { trigger = { local_flag = gd_crashrd_0 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_0 }
command = { trigger = { local_flag = gd_crashrd_5 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_5 }
command = { trigger = { local_flag = gd_crashrd_10 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_10 }
command = { trigger = { local_flag = gd_crashrd_15 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_15 }
command = { trigger = { local_flag = gd_crashrd_20 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_20 }
command = { trigger = { local_flag = gd_crashrd_25 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_25 }
command = { trigger = { local_flag = gd_crashrd_30 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_30 }
command = { trigger = { local_flag = gd_crashrd_35 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_35 }
command = { trigger = { local_flag = gd_crashrd_40 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_40 }
command = { trigger = { local_flag = gd_crashrd_45 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_45 }
command = { trigger = { local_flag = gd_crashrd_50 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_50 }
command = { trigger = { local_flag = gd_crashrd_55 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_55 }
command = { trigger = { local_flag = gd_crashrd_60 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_60 }
command = { trigger = { local_flag = gd_crashrd_65 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_65 }
command = { trigger = { local_flag = gd_crashrd_70 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_70 }
command = { trigger = { local_flag = gd_crashrd_75 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_75 }
command = { trigger = { local_flag = gd_crashrd_80 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_80 }
command = { trigger = { local_flag = gd_crashrd_85 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_85 }
command = { trigger = { local_flag = gd_crashrd_90 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_90 }
command = { trigger = { local_flag = gd_crashrd_95 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_95 }
command = { trigger = { local_flag = gd_crashrd_100 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_100 }
command = { trigger = { local_flag = gd_crashrd_105 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_105 }
command = { trigger = { local_flag = gd_crashrd_110 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_110 }
command = { trigger = { local_flag = gd_crashrd_115 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_115 }
command = { trigger = { local_flag = gd_crashrd_120 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_120 }
command = { trigger = { local_flag = gd_crashrd_125 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_125 }
command = { trigger = { local_flag = gd_crashrd_130 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_130 }
command = { trigger = { local_flag = gd_crashrd_135 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_135 }
command = { trigger = { local_flag = gd_crashrd_140 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_140 }
command = { trigger = { local_flag = gd_crashrd_145 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_145 }
command = { trigger = { local_flag = gd_crashrd_150 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_150 }
command = { trigger = { local_flag = gd_crashrd_155 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_155 }
command = { trigger = { local_flag = gd_crashrd_160 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_160 }
command = { trigger = { local_flag = gd_crashrd_165 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_165 }
command = { trigger = { local_flag = gd_crashrd_170 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_170 }
command = { trigger = { local_flag = gd_crashrd_175 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_175 }
command = { trigger = { local_flag = gd_crashrd_180 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_180 }
command = { trigger = { local_flag = gd_crashrd_185 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_185 }
command = { trigger = { local_flag = gd_crashrd_190 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_190 }
command = { trigger = { local_flag = gd_crashrd_195 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_195 }
command = { trigger = { local_flag = gd_crashrd_200 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_200 }
command = { trigger = { local_flag = gd_crashrd_205 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_205 }
command = { trigger = { local_flag = gd_crashrd_210 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_210 }
command = { trigger = { local_flag = gd_crashrd_215 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_215 }
command = { trigger = { local_flag = gd_crashrd_220 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_220 }
command = { trigger = { local_flag = gd_crashrd_225 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_225 }
command = { trigger = { local_flag = gd_crashrd_230 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_230 }
command = { trigger = { local_flag = gd_crashrd_235 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_235 }
command = { trigger = { local_flag = gd_crashrd_240 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_240 }
command = { trigger = { local_flag = gd_crashrd_245 } type = free_money value = 5 }
command = { type = local_clrflag which = gd_crashrd_245 }

Not only is it easier in Python, but you get to have greater control and more intervals as well.

You can also implement "Smart" events by generating triggers for AI, so the AI picks the right choice. Why would a person declare war against another country if it is tiny and sure about to crushed, if they have the option not to?

Code:
    def _strengthCheck(values, top, method, multiplier=2):
                for icvalue in values:
                    wea = top.addLogic('and')
                    wea.addLogic('not').addAdvancedCondition('ic', country=tag, value = icvalue)
                    ino = wea.addLogic(method)
                    ino.addCondition('ic = ' + str(int(multiplier*icvalue)))
                    ino.addCondition('atwar = ' + str(tag))
    weakEnemyCheck = aiBehavior.addLogic('or')
    weakEnemyCheck.addLogic('not').addAdvancedCondition('ic', country=tag, value=3)
    _strengthCheck((10, 15), weakEnemyCheck, 'or')
    _strengthCheck((25, 50, 75, 90), weakEnemyCheck, 'and')
    _strengthCheck((100, 120, 140, 150), weakEnemyCheck, 'and', 2.5)
    _strengthCheck((175, 200), weakEnemyCheck, 'and', 3)
Example snippet that checks if an enemy is weaker than the country that is fired (this is NOT part of the library, just an example usage of the library)

Or, you can increase (or decrease) chances the AI picks something if there are good (or bad) relations (again example usage of library, not the library itself)
Code:
def _generateRel(rels, top):
                for rel in rels:
                    aiBehavior = top.addLogic('and')
                    aiBehavior.addAdvancedCondition('relation', which=tag, value=rel)
                    aiBehavior.addCondition('random = 1')
_generateRel((0, 50, 100, 150, 200), aiOr)
 
Last edited:

Limith

Modding for Myself
18 Badges
Apr 7, 2010
3.740
369
  • Darkest Hour
  • Deus Vult
  • East India Company
  • Europa Universalis III Complete
  • Divine Wind
  • Crusader Kings II
  • Heir to the Throne
  • Rome: Vae Victis
  • Rome Gold
  • Sword of the Stars
  • Victoria 2: Heart of Darkness
  • Victoria 2: A House Divided
  • Stellaris Sign-up
  • 500k Club
  • Victoria 2
  • Europa Universalis III Complete
  • Europa Universalis III Complete
  • Europa Universalis IV
http://www-inst.eecs.berkeley.edu/~selfpace/class/cs9h/
http://www.python.org/about/gettingstarted/
http://www.youtube.com/watch?v=54-wuFsPi0w
http://www.youtube.com/playlist?list=PL87898FD0A141069E&feature=view_all

In short you will need:
Python 2.7
Probably Eclipse and Pydev since you won't know how to compile it and eclipse makes things easy
The Event.py file

Code below in a python file in the same directory/package.
Code:
from __future__ import print_function
import sys
from Event import *
if __name__ == '__main__':
    ''''
    INSERT YOUR CODE HERE
    ''''

You will want to pick and choose what you want. For example, if you just want some commands, don't start with creating an Event File, then an Event, then an Action, etc. etc.
Just start with
a = Command(ARGUMENTS)

To get what you want to the console/stdout so you can copy it, do print(a)

If you wish to write to a file, use EventFile's write() method.

I will say the best way to learn what does what is to play around with the test code that Event provides, commenting out things one by and and then re commenting it ('''...''' is a block comment, anything in between is commented out, # is a line comment)
Code:
    '''Test Code'''
    testEvent = Event(name = '"Economic Recovery"', desc='"Our economy has recovered from the depression!"')
    firstAction = testEvent.newAction()
    firstAction.newCommand('dissent', value=5, name='ACTION_NAME_GREAT')
    firstWhile = firstAction.newWhile()
    firstWhile.setattr('iter', 40) #Pseudo-while loop
    firstWhile.newCommand('industrial_modifier', which='total', value=5)
    firstWhile.newCommand('local_variable', which='GREAT_DEPRESSION', when=1, value=-1)
    groupTrigger = firstWhile.newTriggerGroup()
    groupTrigger.addAdvancedCondition('local_variable', which='GREAT_DEPRESSION', when = 2, value = 0)


    '''
firstTrigger = testEvent.newTriggerGroup()
firstTrigger.addCondition('money = 50')
notTest = firstTrigger.addLogic('not')
notTest.addCondition('dissent = 30')
nestTest = firstTrigger.addLogic('not')
nestTest.addCondition('ai = no')
nestTest.addAdvancedCondition('alliance', ('country', 'USA'), ('country', 'CHI'))
innerTest = nestTest.addLogic('and')
duo = innerTest.addLogic('and')
duo.addAdvancedCondition('blah', ('abc', 'efg'))
innerTest.addCondition('flag = abcd')
firstTrigger.addAdvancedCondition(ctype='relation', which='USA', value=50)
'''
    '''
actionTrigger = firstAction.newTriggerGroup()
triggerAnd = actionTrigger.addLogic('and')
triggerAnd.addCondition('blah')
setattr(firstAction, '_ai_chance', 50)
actionTrigger.addCondition('testCondition = false')
firstAction.setattr('name', 'ACTION_NAME_OKAY')
firstCommand = firstAction.newCommand('trigger', which=133011025)
commandTrigger = firstCommand.newTriggerGroup(ttype='ignore')
commandTrigger.addCondition('a')
commandTrigger2 = firstCommand.newTriggerGroup(ttype='ignore')
commandTrigger2.addCondition('b')
commandTrigger2.addLogic('and').addCondition('c')
nt = commandTrigger2.addLogic('or')
nt2 = nt.addLogic('not')
nt.addAdvancedCondition('blah')
 
Last edited: