forked from The-Grand-Combination/The-Grand-Combo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
TGC - Best Practices.txt
162 lines (135 loc) · 16.1 KB
/
TGC - Best Practices.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
This file is to document Best Practices when modding The Grand Combo Mod for Victoria 2.
## Tools and Utilities (Recommended) ##
Audax Validator: https://forum.paradoxplaza.com/forum/threads/a-validator-for-victoria-ii.490803/
Clausewitz Positions Editor: https://sourceforge.net/projects/eug/
Clausewitz Scenario Editor: https://sourceforge.net/projects/eug/
## General Text Editing Best Practices ##
- *VERY IMPORTANT* Make sure all files are saved in Windows-1252 (or ANSI) character encoding. Many modern programs will save in UTF-8, which will result in odd characters. Reference for which characters can be displayed by Victoria II: https://en.wikipedia.org/wiki/Windows-1252
- Comment *every* item with at minimum the localisations of the item, so future modders know what is what.
- Write in British English
- Use Spell and Grammar Checks
- Decision, modifiers, goods, items, etc. code should be in all lower case.
- Organize the content txt files in alphabetical order, when it makes sense to do so.
- Exception: Organize decisions and event chains together when they are related.
- Events/Decisions deemed as ahistorical/fantasy add 'NOT = { has_global_flag = extra_flavour_disabled }' to trigger/potential
- Events/Decisions deemed as Colonial Railroading add 'NOT = { has_global_flag = colonial_railroading_disabled }' to trigger/potential
- Where possible in scripts refer to any_owned in regions to reduce reliance on specific province IDs (which change often during map reworks)
- Any microstate TAGs added should also be added to the option_disable_microstates decision in Setup.txt
## Templates ##
- Templates for /common/country, /history/country, and history/provinces are available in TGC - templates.zip, please use to build and update countries and provinces!
## Conditions Best Practices ##
- This applies to both potential in decisions and trigger in events. The effect of allow on performance is irrelevant, so prioritize readability when writing it.
- First or first few conditions should be the ones that will most reduce the set of possible countries/provinces, if possible, just to one.
- For countries, these are conditions like tag, owns, controls, is_our_vassal, is_sphere_leader_of, capital, etc. that can only have one result
- For provinces, the only condition like this is province_id
- In both situations, flags or modifiers that will only be present in one or a few at any time are also usable here.
- DO NOT use primary_culture unless you are sure that the event requires that. Using primary_culture instead of tag will both catch more countries than is necessary and may allow the trigger to be true when it shouldn't.
- Once the trigger is scoped down to a single digit number of countries/provinces, condition order becomes irrelevant and you should prioritize code readability.
- If the above is not possible due to logic (event/decision is more generic), try to scope down the trigger as much as you can first.
- Good country conditions are those which will only be true for a limited number of countries, for example, in_sphere, vassal_of, substate_of, is_greater_power, is_secondary_power, rank (for small numbers), is_core (of a province), neighbour, primary_culture, accepted_culture, war_with, truce_with, ai = no...
- Okay conditions are those which will be true for some subset of all countries, for example, government, ideology, political/social_reform, is_vassal, is_substate, is_independant, is_disarmed, is_mobilized, ruling party policies, has_country_flag
- Conditions to avoid putting early in the conditions list are those that will be true for a large subset of all countries and are unlikely to change, such as exists (this is almost never useful outside of random_country), civilized, ai = yes, technology, invention, war
- Avoid unnecessary conditions (conditions that will always be true, given previous conditions) to reduce unnecessary checking and improve performance. For example, checking if a country exists after checking whether it owns a certain province, or checking if it's a greater power after checking if it's the sphere leader of a certain country.
- Avoid checking for the same thing in multiple places in a AND/OR tree.
- NOT = { OR = { ... } } is redundant and will be false as soon as one of the inner conditions is satisfied, same as just NOT = { ... }. NOT = { AND = { ... } } requires all of the conditions to be satisfied to become false.
- exists = yes is redundant if owns, is_greater_power, is_secondary_power, war_with, has_country_modifier, and anything else that cannot be true if the country doesn't exist.
- Despite the above, checking for a country's administrative, education, or military spending without determining that the country exists will crash the game, so if none of the above alternatives can apply, use exists = yes
- Use region instead of state_id to check for state since region names changing will break this but a province changing state will silently do the wrong thing. Only use state_id to check whether two provinces are in the same state.
- Using a province condition inside a state trigger scope will return true if any province in that state satisfies the condition. Note that the Validator will complain about this.
## Effects Best Practices #
- Prioritize readability.
- Prestige and infamy effects should go first.
- Don't use random_list for good stuff, only for bad stuff.
- Avoid using any_greater_power as it will display the individual effect up to 8 times, almost certainly using up all the available display space.
- The limit = { ... } command works with explicit scopes (state names, pop types...) as well as implicit ones (any_owned, any_pop...).
- Use explicit pop type/strata scopes instead of any_pop with limit.
- If effects are long, use grouping and indentation for code readability.
- If an effect will only potentially affect a limited number of countries/provinces, use random_country/random_owned instead of any_country/any_owned to display the exact effect.
- Use all_core rather than state scopes where applicable to prevent side effects of assuming where a country will have cores.
- If part of an effect is potentially not going to have an effect, use random_owned to not display it if this is the case (if not a great power, no need to display influence gains, if they don't have a core somewhere no need to display removing it)
- What random_owned and random_country display is determined before effect execution, but what they do is determined at that point in the execution - if at the beginning of an event you don't own province 232, random_owned = { limit = { province_id = 232 } ... } will not display. However, if by the time it comes to that line you do (from a previous effect), the effect from inside random_owned will still be executed.
- If an effect gives infamy or takes money, make sure the AI won't bankrupt itself or drive itself over the infamy limit.
## Event Best Practices ##
- Use the most appropriate file in the mod/TGC/events/ folder. As a general rule, self-contained mechanics go into their own files, common events go into common files and country/region specific events go into specific files.
- Use localisation for event text rather than text in the code.
- Event Localizations should be placed in the appropriate files. Each event localization file (that doesn't only hold localizations from a self-contained mechanic) has a number in it, representing the lower bound of ids to go into that file (with the upper bound being the next file). Place the localizations in that file, sorted by id (for easier indexing) and in the order of DESC, NAME, OPTA... (for easier readability). If your editor or some other tool sorts these, make sure that this functionality is turned off so as not to cause trouble (ideally, check the git diff for all files before committing anything).
- Write the title and a short one-line description of the event and options (if more than one) if not obvious (look at examples)
- For event chains, try to use consecutive numbers or at least numbers in a certain range for ids rather than just random 20 digit numbers.
- Use the following formats for localising your events:
title = "EVTNAME#########"
desc = "EVTDESC#########"
option A = EVTOPTA##########"
option B = EVTOPTB##########", etc.
- It's okay to reuse localizations from events in the same group, but don't reuse localizations from unrelated events.
- Event components should always come in the following order (optional in brackets):
- Id, Title, Description, Picture, (Major)
- Trigger, Mean Time To Happen, (Fire Only Once), (Allow Multiple Instances) / Is Triggered Only
- (Immediate), Options
- In Options, maintain one blank row between name, effect and ai_chance for readability
- Avoid unnecessary attributes (ai_chance for events with only one option, both mean_time_to_happen and is_triggered_only, major and picture) to reduce clutter.
- Keep events in each file grouped with indentation under a title where applicable, and in logical or chronological order where possible.
- Events with is_triggered_only = yes don't affect performance, so don't be cheap on notification events for countries that are affected.
- Use Audax Validator after any edits
## Event Tips ##
- Note that country_event = { id = X days = Y } won't work with FROM.
- Options that don't have ai_chance set are equally likely. I'm not sure what the behavior is if one of the options has ai_chance set but another doesn't.
- If two events have the same trigger but only one should fire, use immediate instead of option to set the flag preventing the events from firing.
## Decision Best Practices ##
- Use the decison template in the Templates folder
- Use the most appropriate file in the mod/TGC/decisions/ folder. As a general rule, self-contained mechanics go into their own files, common decisions go into common files and country/region specific decisions go into specific files.
- Write a short one-line description above each decision, for example roughly what it does and where it fits in with other decisions (look at examples)
- Decision names should be snake case, something_like_this, and lowercase so that if someone happens to sort a localization file they don't reorder it and create merge conflicts for everyone else.
- Decision components should always be structured like this:
- picture
- potential
- empty row
- allow
- empty row
- effect
- empty row
- ai_will_do
- Keep decisions in each file grouped with indentation under a title where applicable, and in logical or chronological order where possible.
- Use Audax Validator after any edits
- Localize all flags that appear in allow and will be displayed to the user (note: global flags can't be localized for some reason.)
- Avoid duplicating code where possible. One decision is better than two, if they would have the same localization, conditions and same / conditionally same effect.
- Give descriptions descriptive names - memory is cheap, developer attention is expensive.
- (work in progress) ai cleanup decisions should have names starting with ai_ and have localizations in a separate file from the regular decisions.
## Decision Tips ##
- The AI will take the decision if the ai_will_do factor is 1 or greater.
- If a decision triggers an event and is meant to be taken once, set the flag which blocks it from being clickable in the decision effect rather than the event effect, to prevent it being clickable for the rest of the day.
## Formatting Best Practices ##
- Write free text comments with one space after the # sign for easier readability. #Description, #DEVNOTE etc are fine, however.
- When an object (something in brackets) contains one element (e.g. NOT = { exists = GER }) or can only contain a limited number of elements (e.g. relations = { who = FROM value = 10 }) write them inline.
- If you have a few similar lines of limited length in succession, write them inline each, for example:
scaled_consciousness = { ideology = conservative factor = 2 }
scaled_militancy = { ideology = conservative factor = 2 }
scaled_consciousness = { ideology = reactionary factor = 2 }
scaled_militancy = { ideology = reactionary factor = 2 }
takes 4 lines whereas expanding that would hamper readability by taking up 16.
- Write descriptions next to non-obvious literals (regions, province ids, modifier durations) - not everybody should have to look up that province 232 is New York and 1095 days is 3 years
## General Best Practices ##
- Whenever changing something, assume that it was made like it is with good reason, and understand that reason before changing it. Changing stuff without checking how it interacts with other stuff is why bugs happen.
- Give flags descriptive names - memory is cheap, developer attention is expensive. Ideally, a flag would have a (who_)did_what or (this_is_)what format for easy understanding, e.g. offered_treaty_of_guadalupe_hidalgo or slave_trader.
- Use THIS and FROM instead of tags where appropriate. Note that remove_core doesn't work with FROM.
- If you have tested that a piece of code works, but the Validator keeps complaining about it, you can put the following line before it to reduce noise: # Audax Validator "." Ignore_NEXT
- If the event/decision makes an assumption, make sure to check for that assumption.
- For example, if the primary effect is to send an event to Mexico, you should check if Mexico exists in the prerequisite conditions. If sending an event to Mexico is a secondary effect, however, such as an event for their reaction for something you did, use random_country instead.
- If the effect does something to a set of provinces (say, builds railroads), either check to see that you own all of the provinces or limit the effect to those you own, or whether it makes sense for the event/decision to have an effect outside your country.
- Before adding an event/decision, check to see whether what you're trying to accomplish is already done somewhere else similarly. E.g. don't make a non-specific "accept natives" decision for Mexico, since Native Integration already exists. Rather, you can write something specific that would lead to the acceptance of a native culture
- Generic is better than specific, but a collection of special cases is not generic.
## Files Best Practices ##
- Discuss with the lead developer(s) any additions or changes to common / inventions / poptypes / technologies / units files.
- Don't forget to check what character set and line endings your editor is set to. If you make a mistake and mangle the files your commits will be reverted.
- Don't use Excel to edit localization files - this causes issues with quotation marks, line endings and typesets.
- We recommend using VS Code or Atom (and they both have addons for git integration).
- Don't bundle together nontrivial changes that don't need to be bundled together.
- For larger changes create a branch and pull request to monitor the difference between your branch and the main branch, rather than just committing.
- Give files descriptive names - memory is cheap, developer attention is expensive.
- Event localizations should generally go to the event files with the appropriate id range, in ascending id order, then going DESC, NAME, OPTA, OPTB etc. Exceptions can be made for self-contained mechanics with a lot of events (e.g. leader events).
- Decisions localizations should generally go into 00_decisions.csv. Self-contained mechanics with a lot of decisions (e.g. returning cores) can go into their own files.
- If you have time to research, make sure your localizations are well written. We want our mod to look good, don't we?
## Map Best Practices ##
- Discuss with Hammonia (@Obstination#6820 on Discord) or lead developer(s) any province additions or changes. Ideally, we would like not to have to make any map boundary changes or additions after the next major update (0.2).
- Province localisation files for provinces should only have place names that existed in 1836. If this is not possible, try to keep names from 1840 or earlier.
- Use the current or 1936 names for provinces in the definition.csv. This is helpful for renaming decisions.
- When changing the map make sure to account for any code that used the changed provinces / states and fix it to account for the changes or new provinces. This includes renaming decisions as well as other content.