• 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.

ngppgn

Field Marshal
19 Badges
Jan 29, 2011
3.508
657
  • Crusader Kings III
  • Imperator: Rome
  • Imperator: Rome Deluxe Edition
  • Crusader Kings II: Jade Dragon
  • Europa Universalis IV
  • Crusader Kings II: Monks and Mystics
  • Hearts of Iron IV: Cadet
  • Stellaris Sign-up
  • Stellaris
  • Crusader Kings II: Horse Lords
  • Europa Universalis IV: Res Publica
  • Crusader Kings II
  • Heir to the Throne
  • Europa Universalis IV: Call to arms event
  • Europa Universalis IV: Conquest of Paradise
  • Divine Wind
  • Europa Universalis III: Chronicles
  • Europa Universalis III
  • Crusader Kings II: The Old Gods
FIrst, some backstory:

Cyclicaclly, I grow weary of CK2 (and other PDS games)' syntax. It is overly verbose in several ways:
  • The = sign is used as a mere "connective" without meaning in some cases ( add_trait = greedy ), and as ">=" in many others ( prestige = 100 ). More sensible languages would just suppress the firs use ( add_trait greedy or add_trait(greedy) ) and use the proper >= in the second.
  • When a function (condition or command) has more than one argument, all the arguments are named ( has_opinion_modifier = { who = ROOT modifier = some_opinion } vs. has_opinion_modifier(ROOT, some_modifier).
  • THe use of {,}, both for delimiting blocks and function arguments is confusing and makes things hard to read. Ideally, function arguments should be delimited by parenthesis or other elements.
  • There's always the issue with indentation: different coders have different styles, and this, coupled with the excessive amount of brackets, make other's code somewhat unpredictable.
Thus, I am thinking of creating a custom scripting language, together with an external tool to compile it into ck2script.

The main features I would like it to have are the following:
1: Indent-based blocks. Instead of separating blocks with brackets, I'll do it with the number of initia tab characters. So instead of
Code:
 OR = {
    has_opinion_modifier = { who = ROOT modifier = some_opinion }
    trait = quick[/INDENT]
}
You would write:
Code:
 OR:
    HasOpinionTowards Root some_opinion # you can see that equal signs, brackets and names for arguments are no longer used, making both writing and reading way easier
    Trait quick
2: Writing and reading code in a single line would be much easier. Instead of
Code:
 OR = { is_ruler = yes has_opinion_modifier = { who = ROOT modifier = some_opinion } trait = quick }
You would write:
Code:
OR: IsRuler; HasOpinionTowards Root some_opinion; Trait quick
#you can see that several simple conditions are separated by ';', the OR: encompases the whole line, only a single block (or, and, limit, etc.) can be used in a single line like this. If you need to use more lines you could write them like in the previous example.
3: Quite often you need to write several conditions or commands of the same type but with different values, and I want to make this easier, so instead of
Code:
 OR = { trait = genius trait = quick trait = brave trait = fair is_ruler = yes }
You would write:
Code:
OR: Trait genius, quick, brave, fair; IsRuler
# several instances of the same condition with different values are separated with ',' and you only write the values, not the name of the condition/command.
4: Usually in programming languages the equivalent of NOT doesn't requires to use brackets or parenthesis since it only affect the next expression that appears. I want to adopt this behaviour, and adopt the usual '!' sign to mean "not". So instead of
Code:
 OR = { NOT = { trait = genius } NOT = { trait = quick } trait = brave trait = fair is_ruler = yes }
You would write:
Code:
OR: Trait ! genius, ! quick, brave, fair; ! IsRuler
# Additionally note that conditions that only take yes or no in ck2script take no arguments in pyCK2, isRuler equals is_ruler = yes and ! IsRuler equals is_ruler = no.

5: CamelCase is used to reduce the number of heystrokes and also to differentiate elements (Conditions/commands/scopes start in uppercase, values strat in lowercase).

6: Several elements are rewritten for clarity or succintness. Instead of FROMFROMFROMFROM, you'll write char:FROM_4 instead of event_target: some_title_saved_as_global_even_target, you''l write title:global:som_target

7: this means the language is type-safe: you always know when you are in character, title, province, etc, scope, by forcing to annotate the few unsafe scopes like FROM, event_targets and quest_targets.

8: dealing with variables is much less cumbersome! Write num:my_variable *= 5 instead of multiply_variable = { which = my_variable value = 5 }

9: Chaining scope changes with a single indentation. Instead of
Code:
scope1 = {
  scope2 = {
    scope3 = {
      scope4 = {
        effects
      }
    }
  }
}
or
Code:
scope1 = { scope2 = { scope3 = { scope4 = {
  effects
}}}}
you can write
Code:
scope1: scope2: scope3: scope4:
  effects

10: Some common idioms will be abbreviated. For example, you can use AddTrait genius for add_trait = genius and AddTrait? genius for if = { limit = { not = { trait = genius } } } add_trait = genius } This "?-syntax" will be present for many commands that add or remove things like traits, modifiers, claims, etc. I plan on adding more as I come by common patterns. For example. I currently have a Exists <scope> that abbreviates <scope> = { always = yes } which is often used to test if a scope points to an actual object.

11: This is still very WIP, but I plan on scripted effects being able to take variables and scopes of different types as arguments, so you can do, e.g change_artifact_owner art:local:some_artifact char:local:current_owner char:local:receiver instaad of ck2script effects that only take "yes" as a possible value.

12: Syntax highlighting and autocompletions for pyCK2 on Sublime Text 3

13: In the long term, I want to translate all of the vanilla code to this pyCK2, so that it can be taken as baseline by modders who what to use the new language.

So, tell me what do you think of this initiative, wether you would be interested in using it, and any suggestions you may have to improve it.​
 

ngppgn

Field Marshal
19 Badges
Jan 29, 2011
3.508
657
  • Crusader Kings III
  • Imperator: Rome
  • Imperator: Rome Deluxe Edition
  • Crusader Kings II: Jade Dragon
  • Europa Universalis IV
  • Crusader Kings II: Monks and Mystics
  • Hearts of Iron IV: Cadet
  • Stellaris Sign-up
  • Stellaris
  • Crusader Kings II: Horse Lords
  • Europa Universalis IV: Res Publica
  • Crusader Kings II
  • Heir to the Throne
  • Europa Universalis IV: Call to arms event
  • Europa Universalis IV: Conquest of Paradise
  • Divine Wind
  • Europa Universalis III: Chronicles
  • Europa Universalis III
  • Crusader Kings II: The Old Gods
Sorry if this sounds mean. But this would work but from the examples given there is no real benefit other than having to type fewer braces.

Not mean at all, and I get your point. Like I tried to point out the main reason for doing this at all is making the code easier to read and write. Ideally we would want to write things like "num:a = num:b + num:c * num:d". I'd say that writing and reading that is much easier and faster than the equivalent in ck2script:

Code:
set_variable = { which = local_ which = c } # set a dummy variable to carry the result.
multiply_variable = { which = local_ which = d }
change_variable = { which = local_ which = b }
set_variable = { which = a which = local_ }
set_variable = { which = local_ value = 0 } # clear the dummy variable for use in future operations.

Now imagine we want to create a complex system that require lots of variable manipulations, and how cumberson that'd be to write in ck2script.

But yeah, making more compact and easily understandable code is the only selling point of this initiative. I can see how that advantage would be outweighted by the requirement to actually have to learn to use a new scripting language.

But like I said, it's very much a WIP, so if you know of any way some scripting task could be simplified with this, I'd gladly take a look to see if I can incorporate it to the language.

Oh, one tiny little thing I just added to my todo list. Make .gui object definitions refer to the position of the parent object they are nested in, or to the immediately previous item defined, so if you have a window and two icons within it, you could do:

Code:
#note, this is totally made-up pseudo-code
WindowType:
   Position 50 70
   Size 100 100
   ...
      IconType:
         Position: parent + 20 parent +10 # would evaluate to 70, 80
         ...
      IconType:
         Position: prev + 25 prev # would evaluate to 45, 80
This should make much easier to tweak GUI layout.
 

Idhrendur

Keeper of the Converters
107 Badges
Feb 27, 2009
11.438
3.135
  • Hearts of Iron IV: No Step Back
  • Hearts of Iron IV: By Blood Alone
  • Crusader Kings II
  • Victoria 3 Sign Up
  • Stellaris: Nemesis
  • Sengoku
  • Pillars of Eternity
  • Tyranny: Archon Edition
  • Europa Universalis IV
  • March of the Eagles
  • Victoria 2
  • 500k Club
  • Stellaris: Galaxy Edition
  • Hearts of Iron IV: Colonel
  • Shadowrun Returns
  • Imperator: Rome Deluxe Edition
  • Crusader Kings III: Royal Edition
  • Commander: Conquest of the Americas
  • Darkest Hour
I tentatively like this idea, though it wouldn't be helpful for any of my immediate projects (I think). As your followup examples show, it could have the potential for more expressively allowing some things that are difficult in the existing script. I'm also reminded of some of the fancy MTTH-manipulation stuff people have developed.

1. I am very much not fond of languages that use whitespace as meaningful for the language. When I have some tricky logic I'm implementing, I like being able to carefully use whitespace to clarify the logic, which becomes impossible (or at least unhelpfully difficult) when the whitespace has syntactic meaning.

So from your first example,
Code:
 OR:
    HasOpinionTowards Root some_opinion # you can see that equal signs, brackets and names for arguments are no longer used, making both writing and reading way easier
    Trait quick

I'd prefer
Code:
OR 
{
   HasOpinionTowards Root some_opinion; # you can see that equal signs, brackets and names for arguments are no longer used, making both writing and reading way easier
   Trait quick;
}

You still have a grammar simplification, but are free to use whitespace as you will. You could even do your second example if you wanted (note that you needed a delimiter anyways, so it's more straightforward to always use a delimiter instead of just sometimes), though I find that kind of single-line stuff more confusing than illuminating.

3. I find the way the OR gets reflected into the trait keyword a bit weird. Sure, in that example it's not so bad, but in the case of more complex conditions (say, a sub-condition that has an AND), the lack of explicitness might get confusing. But it might also be fine. Maybe if the list of possible traits was contained by a grammatical marker, such as square brackets?

Code:
OR
{
   Trait [genius, quick, brave, fair];
   IsRuler;
}

Then you could have the more complex conditions like so:
Code:
OR
{
   Trait
   [
      genius, 
      AND {
         quick, brave
      },
      fair
   ];
   IsRuler;
}
Though maybe in that example that's not a great way to do it.

4. Agreed.
5. I prefer such things to be conventions rather than enforced by the language, for what it's worth. And with a plugin for the editor, that can be strongly encouraged.
6. I think that's probably good, but I'd need some more concrete examples to be sure if I was fond of the particular grammar you chose or not.
7. Likewise
8. This kind of simplification is where the real power might lie. For other paradox games that don't support the multiply_variable element, you could do a lot to simplify the much more complex constructs I've seen references to that people have to make (see also all the things that want to be loops or switch statements that can't be).
9. That made me sad. Also, better to create functionality that would allow people to never need that many levels of nesting. Simple functions, perhaps?
10. In that example, is there an ultimate functional difference between AddTrait genius and AddTrait? genius? In gameplay terms at least? Maybe there's just a beterr example I can't think of for that case. Also, I'm not inclined to like punctuation for keywords, and would prefer something like AddTraitIfAbsent genius.
11. If I'm understanding you right, that's something that can't be directly expressed in Paradox script, right? It'd instead be some mess of code to express the same thing? That's cool, and exactly the kind of selling point you want for a project like this!
12. Also cool (even if I haven't made the jump to Sublime Text yet).
13. That's a hefty project, but would clarify the use cases, strengths, and weaknesses of your grammar. Just don't neglect the other games when you do so!
 

loup99

Godogost of Armorica
78 Badges
Jan 22, 2013
16.589
6.390
  • Crusader Kings III
  • Europa Universalis IV
  • Warlock 2: The Exiled
  • 500k Club
  • Pride of Nations
  • Stellaris
  • Hearts of Iron IV: Cadet
  • Crusader Kings Complete
  • Imperator: Rome Deluxe Edition
  • Victoria 2
  • Arsenal of Democracy
  • Cities in Motion
  • Crusader Kings II
  • Darkest Hour
  • Europa Universalis III: Chronicles
  • For The Glory
  • Hearts of Iron III
  • March of the Eagles
  • Rome Gold
  • Sengoku
  • Victoria 2: A House Divided
  • Victoria: Revolutions
  • Cities: Skylines
  • Europa Universalis IV: Pre-order
  • The = sign is used as a mere "connective" without meaning in some cases ( add_trait = greedy ), and as ">=" in many others ( prestige = 100 ). More sensible languages would just suppress the firs use ( add_trait greedy or add_trait(greedy) ) and use the proper >= in the second.
This is the one bit I agree with personally, although I wouldn't go as far as to suppress the first one, only the latter (meaning "=" would never be ">=", because that is the one thing I don't think makes any sense).

Otherwise I personally like the full names (far more clear to look at a glance and more difficult to make mistakes) and usage of brackets (removing them hurts clarity), even though I can see the concern with identation that you raise.
 

ngppgn

Field Marshal
19 Badges
Jan 29, 2011
3.508
657
  • Crusader Kings III
  • Imperator: Rome
  • Imperator: Rome Deluxe Edition
  • Crusader Kings II: Jade Dragon
  • Europa Universalis IV
  • Crusader Kings II: Monks and Mystics
  • Hearts of Iron IV: Cadet
  • Stellaris Sign-up
  • Stellaris
  • Crusader Kings II: Horse Lords
  • Europa Universalis IV: Res Publica
  • Crusader Kings II
  • Heir to the Throne
  • Europa Universalis IV: Call to arms event
  • Europa Universalis IV: Conquest of Paradise
  • Divine Wind
  • Europa Universalis III: Chronicles
  • Europa Universalis III
  • Crusader Kings II: The Old Gods
I tentatively like this idea, though it wouldn't be helpful for any of my immediate projects (I think). As your followup examples show, it could have the potential for more expressively allowing some things that are difficult in the existing script. I'm also reminded of some of the fancy MTTH-manipulation stuff people have developed.

1. I am very much not fond of languages that use whitespace as meaningful for the language. When I have some tricky logic I'm implementing, I like being able to carefully use whitespace to clarify the logic, which becomes impossible (or at least unhelpfully difficult) when the whitespace has syntactic meaning.

So from your first example,
Code:
 OR:
    HasOpinionTowards Root some_opinion # you can see that equal signs, brackets and names for arguments are no longer used, making both writing and reading way easier
    Trait quick

I'd prefer
Code:
OR
{
   HasOpinionTowards Root some_opinion; # you can see that equal signs, brackets and names for arguments are no longer used, making both writing and reading way easier
   Trait quick;
}

You still have a grammar simplification, but are free to use whitespace as you will. You could even do your second example if you wanted (note that you needed a delimiter anyways, so it's more straightforward to always use a delimiter instead of just sometimes), though I find that kind of single-line stuff more confusing than illuminating.

3. I find the way the OR gets reflected into the trait keyword a bit weird. Sure, in that example it's not so bad, but in the case of more complex conditions (say, a sub-condition that has an AND), the lack of explicitness might get confusing. But it might also be fine. Maybe if the list of possible traits was contained by a grammatical marker, such as square brackets?

Code:
OR
{
   Trait [genius, quick, brave, fair];
   IsRuler;
}

Then you could have the more complex conditions like so:
Code:
OR
{
   Trait
   [
      genius,
      AND {
         quick, brave
      },
      fair
   ];
   IsRuler;
}
Though maybe in that example that's not a great way to do it.

4. Agreed.
5. I prefer such things to be conventions rather than enforced by the language, for what it's worth. And with a plugin for the editor, that can be strongly encouraged.
6. I think that's probably good, but I'd need some more concrete examples to be sure if I was fond of the particular grammar you chose or not.
7. Likewise
8. This kind of simplification is where the real power might lie. For other paradox games that don't support the multiply_variable element, you could do a lot to simplify the much more complex constructs I've seen references to that people have to make (see also all the things that want to be loops or switch statements that can't be).
9. That made me sad. Also, better to create functionality that would allow people to never need that many levels of nesting. Simple functions, perhaps?
10. In that example, is there an ultimate functional difference between AddTrait genius and AddTrait? genius? In gameplay terms at least? Maybe there's just a beterr example I can't think of for that case. Also, I'm not inclined to like punctuation for keywords, and would prefer something like AddTraitIfAbsent genius.
11. If I'm understanding you right, that's something that can't be directly expressed in Paradox script, right? It'd instead be some mess of code to express the same thing? That's cool, and exactly the kind of selling point you want for a project like this!
12. Also cool (even if I haven't made the jump to Sublime Text yet).
13. That's a hefty project, but would clarify the use cases, strengths, and weaknesses of your grammar. Just don't neglect the other games when you do so!

Thank you very much for the thorough answer!

1- I see how many would prefer to have non-significant whitespace: at the end of the day, which kind of signals coneys better the intention of the programmer is more or less subjective. Now you say that you prefer to freely use whitespace to better convey the logic of your code. May I ask, out of curiosity, of an example where you use whitespace to convey your logic in a way that is not conformant to the "more indentation means more nesting" pattern? The reasoning I used to adopt an inden-based syntax was that in the common practice, indenting more each time we nest brackets seems to be the common practice in the creat majority of ck2 scripts I've seen.

Now, I could do two versions of the pre-processor, one that is indent-based and one that is bracket-based, if there were enough demand, though that'd be low prio for me, and at that point, I'm not sure the motivations that brought forth this project would still hold.

3- That's an interesting idea, though I'm not sure I like it. In my approach, you can alway do
Code:
OR:
  Trait genius
  AND:
     Trait quick
     Trait brave
   Trait fair
   IsRuler

The ; in this language is only used to separate two expressions in the same line, otherwise it's absolutely optional. So, you can do:
Code:
OR:
  Trait genius
  AND:
     Trait quick; Trait brave
  Trait fair; IsRuler
If you feel like making your coude a bit more compact, but this is totally optional.

Now, the rationale would continue: if you have a single line inside a block, like the onle line inside the AND block, if you so prefer you could compact it to "AND: Trait quick; Trait brave", but if this feels too crowded, then you aren't at all forced to do that. Furthermore, the "Trait quick, brave" notation comes from comparing it to natural language. Informally, you would have expressed the AND block saying "Must have both the traits quick and brave". I wanted an expression that could map more or less seamlessly to the english expression while being as succint as possible, thus the AND: mapping to "Must have both", the "Trait" heywork being mentioned only once, and the trait values being separated by commas.

In the same spirit, "Must be a ruler, have some_opinion towards ROOT and have the trait quick" would map to "AND: IsRuler; HasOpinionTowards ROOT; Trait quick", but this compactation (is that a word?) is again optional.

5- Could you explain what do you mean with the plugin part? Hm, I'll probably end up making the language case-insensitive but I'm not sure at this point.

6- Of course. I'm in the process of compiling a list of all commands, conditions and scopes, along with their translation to pyCK2. I'll post it when I've completed it, so I can get input on it.

7- This mostly mean that instead of, e.g. FROM you need to write char:FROM. Upside: others, specially newcomers would be a bit less confused as to what are FROM, PREV, etc. Downside, you need to write a little more even in cases where it should be ovbious, e.g. PREV. This has two reasons: limitation of the syntax definition for sublime (I want the text background to give a hint of whether we are in char, prov or title scope), and to ban mistakes such as saving a character as an event target and then using province commands on it.

8- Wait.... There ARE pds games where variables can't be multiplied? Wow, that's... awkward and unexpected. But I councur, besides the awful number of brackets you end up writing, the most cumbersome part of ck2script is doing even moderately complex arithmetic. I can't even begin to fathom not having multiplication or substraction...

9- Well, sometimes you simply need to do that many scope switches. Say you want to test that no bordering realm has a province with a city holding which has a certain holding modifier. More on "simple functions" in the later points.

10- In most cases, is mostly cosmetic. If you use add_trait = genius in an effect that generates a tooltip (say, an event option) the tooltip will mention gaining the trait even if you already have it. So, basically, this is a way to tidy up your effect tooltips if you so desire, which is why I felt like decorating the existing commands with a ? was a more elegant and efficient solution than duplicating the commands.

Now there are a couple of cases where guarding the command in an if-clause would make a difference in the game state: flags and modifiers (maybe other things, like being in a society, but I'm not sure about that) come with a timer, which then you can test (e.g. with the had_flag = { flag = x days = n } condition). Now it you set_character_flag = x when you already had it set, you will be resetting the timer. Thus, in these cases I feel like "duplicating" these commands would be justified. I'm just coming up with concise and descripting names for them. Maybe SetOrResetFlag for the unguarded version and SetFlag for the guarded one?

11- Here's the tricky part. Now, scripted_triggers only can take a yes/no value. Since variables and event targets can't be modified inside conditions, it's impossible to create new conditions that take arguments. What I can do, (and intend to when the main framework is up and running) is letting the used define their own "condition macros". The difference between a macro and a function is that a function is referenced whenever used, but a macro is just substituted in each time it is used (thus is less efficient memory footprint-wise). I could also alow for macros that encapsulate several scope changes too. The problem with this would be that PREV, PREVPREV (or PREV_2 in pyCK2) and so on could not be feeded as arguments, since they wouldn't behave as expected in the expanded code.

Now, scripted effects are a different matter entirely. Since in effects we can set and modifiy variables and event tergets, we can simulate functions that take arguments by setting dummy event targets and variables before using a scripted effect, and then using them inside the scripted effect. What pyCK2 would do is streamline and make clearer the process by outfitting these dummy variables and event targets as formal parameters.

So instead of defining:
Code:
#in common/scripted_effects
my_function_like_effect = {
  # uses variable _num_arg1
  # uses event target _char_arg2
  event_target:_char_arg2 = { change_variable = { which = some_local_variable which = _num_arg_1 }
}
and use it like this:
Code:
#in some effect block, e.g. an event option.
 set_variable = { which = _num_arg1 value = 5 }
 FROM = { save_event_target_as = _char_arg2 }
 my_function_like_effect = yes
you would do:
Code:
#in common/scripted_effects
MyFunction( num arg1; char arg2):
  # uses num:arg1
  # uses char:arg2 
  char:arg2: some_local_variable += num:arg1
}
and use it like this:
Code:
#in some effect block, e.g. an event option.
 MyFunction 5 char:FROM;
By the way, the syntax for this is pretty much a quick sketch, I'm pretty unsatisfied with it. I'm dissatisfied with the fact that I'm using : both to decorate block openers such as OR: or AnyProvince: and to separate type decorations such as num:arg1 and char:FROM. I'll see if I can come up with a better alternative; suggestions are well, received.

Note/small rambling.: EUIV is introducing what they called "meta-scripted triggers and effects" which are basically macros that can take any kind of string as argument. This would be more powerful (but also less safe) that what I indent to provide in pyCK2. If that gets backported to ck2 I'll have to seriously re-think the project, since it is built on the presumption that everything is statically strongly type (i.e. the application that translates pyCK2 to actual ck2script know at all times in what scopes is and should be each command, condition and scope change. Ck2 is already diverging from this paradigm (some scope changes like any_quest_target, event_target:x and "dynamic" scopes such as FROM or PREV are already difficult to treat ( I need the coder to explicitly tell me what kind of entity they are), but that feature could make it basically impossible to predict, unless it was strongly restricted, which would be conterproductive in other ways.


This is the one bit I agree with personally, although I wouldn't go as far as to suppress the first one, only the latter (meaning "=" would never be ">=", because that is the one thing I don't think makes any sense).

Otherwise I personally like the full names (far more clear to look at a glance and more difficult to make mistakes) and usage of brackets (removing them hurts clarity), even though I can see the concern with identation that you raise.

Thanks for the input! When you say removing brackets hurts clarity, do you mean for blocks (the ones I'm replacing with indentation) or simple "functions" (the ones I'm replacing with semicolons)?

Edit: posted before finished writing by error. Finishing now...
 
Last edited:

loup99

Godogost of Armorica
78 Badges
Jan 22, 2013
16.589
6.390
  • Crusader Kings III
  • Europa Universalis IV
  • Warlock 2: The Exiled
  • 500k Club
  • Pride of Nations
  • Stellaris
  • Hearts of Iron IV: Cadet
  • Crusader Kings Complete
  • Imperator: Rome Deluxe Edition
  • Victoria 2
  • Arsenal of Democracy
  • Cities in Motion
  • Crusader Kings II
  • Darkest Hour
  • Europa Universalis III: Chronicles
  • For The Glory
  • Hearts of Iron III
  • March of the Eagles
  • Rome Gold
  • Sengoku
  • Victoria 2: A House Divided
  • Victoria: Revolutions
  • Cities: Skylines
  • Europa Universalis IV: Pre-order
Thanks for the input! When you say removing brackets hurts clarity, do you mean for blocks (the ones I'm replacing with indentation) or simple "functions" (the ones I'm replacing with semicolons)?
For both actually, because in both cases a bracket is an easy way of checking where the blocks respectively functions end.
 

Idhrendur

Keeper of the Converters
107 Badges
Feb 27, 2009
11.438
3.135
  • Hearts of Iron IV: No Step Back
  • Hearts of Iron IV: By Blood Alone
  • Crusader Kings II
  • Victoria 3 Sign Up
  • Stellaris: Nemesis
  • Sengoku
  • Pillars of Eternity
  • Tyranny: Archon Edition
  • Europa Universalis IV
  • March of the Eagles
  • Victoria 2
  • 500k Club
  • Stellaris: Galaxy Edition
  • Hearts of Iron IV: Colonel
  • Shadowrun Returns
  • Imperator: Rome Deluxe Edition
  • Crusader Kings III: Royal Edition
  • Commander: Conquest of the Americas
  • Darkest Hour
1. Sure thing! In general I do conform to indentations showing the level of nesting, but I make exceptions for complex conditionals (also, IDEs and I disagree about the nature of nesting in switch statements and setting the public/protected/private properties in classes, but that wouldn't apply here. An actual example might be:
Code:
if ( 
      (techGroup != "western") &&
      (techGroup != "high_american") && 
      (techGroup != "eastern") && 
      (techGroup != "ottoman")
)

These days I try to move that into a function instead, but that's a whole language feature itself.

3. That works!
5. You mentioned a syntax highlighting in Sublime Text. I'd prefer to see certain forms of casing corresponding to certain language structures enforced there, instead of in the language itself. That said, I do prefer case sensitivity.
6. I'm looking forward to it!
7. Well, those confuse me all the time, so I'm in favor of forcing more clarity.
8. Vic2, I believe. I haven't gotten into that level of modding for any Pdx game, but I understand Vic2 is pretty painful. HoI3 at least had most of the heavy logic moved into Lua files.
9. And I start to see the benefit of removing brackets.
10. Ah, I see. I think keywords of those types would be good. Not too long, but clear in their intent.
11. Okay, yeah, that's exactly the kind of thing that would be useful to have!
 

ngppgn

Field Marshal
19 Badges
Jan 29, 2011
3.508
657
  • Crusader Kings III
  • Imperator: Rome
  • Imperator: Rome Deluxe Edition
  • Crusader Kings II: Jade Dragon
  • Europa Universalis IV
  • Crusader Kings II: Monks and Mystics
  • Hearts of Iron IV: Cadet
  • Stellaris Sign-up
  • Stellaris
  • Crusader Kings II: Horse Lords
  • Europa Universalis IV: Res Publica
  • Crusader Kings II
  • Heir to the Throne
  • Europa Universalis IV: Call to arms event
  • Europa Universalis IV: Conquest of Paradise
  • Divine Wind
  • Europa Universalis III: Chronicles
  • Europa Universalis III
  • Crusader Kings II: The Old Gods
Making some unested progress (I need to get my hands on 2.8 to actually test them since they heavily rely on the new local variables).

So, ideally, I would like to write simply SocietyCurrency *= 5 when I want to multiply the current scope's society_currency by 5.

Now, if we had a set_society_currency command, the ck2script equivalente would look like this instead:
Code:
export_to_variable = { which = local__ value = society_currency }
set_society_currency = 0
multiply_variable = { which = local_a value = 5 }
change_society_currency = local_a
set_variable = { which = local_a value = 0 }

But guess what we DON'T have set_society_currency, so we instead need to write:
Code:
export_to_variable = { which = local__ value = society_currency }
set_variable = { which = local__b which = local_a }
multiply_variable = { which = local__b value = -1 }
change_society_currency = local__b
set_variable = { which = local__b value = 0 }
multiply_variable = { which = local_a value = 5 }
change_society_currency = local_a
set_variable = { which = local_a value = 0 }

So, I'd want to type 12 characters, but instead I need to write 386, more than 30x more!

Right now, I have things so that you can do simple assignement and modifications one after another, like this:
Code:
Prestige = 100; Prestige += n:var1; Prestige *= n:var2
where n:var1 and n:var2 is the current, WIP, syntax for variables.

The goal, though, is being able to write
Code:
Prestige = n:var2 * (n:var1 + 100)

Which would be equivalent, but much more fluid to write and read. However this requires for me to learn how to implement an operator precedence parser, which is what I'll start to do next week (this week is for playing some Jade Dragon once it arrives).
 

Idhrendur

Keeper of the Converters
107 Badges
Feb 27, 2009
11.438
3.135
  • Hearts of Iron IV: No Step Back
  • Hearts of Iron IV: By Blood Alone
  • Crusader Kings II
  • Victoria 3 Sign Up
  • Stellaris: Nemesis
  • Sengoku
  • Pillars of Eternity
  • Tyranny: Archon Edition
  • Europa Universalis IV
  • March of the Eagles
  • Victoria 2
  • 500k Club
  • Stellaris: Galaxy Edition
  • Hearts of Iron IV: Colonel
  • Shadowrun Returns
  • Imperator: Rome Deluxe Edition
  • Crusader Kings III: Royal Edition
  • Commander: Conquest of the Americas
  • Darkest Hour
operator precedence parser

From what I recall from my school days, that's a lot easier if you use postfix notation. Not that such a thing fits the end goal. Best of luck!
 

Romulien

Lt. General
19 Badges
Jul 2, 2013
1.404
308
  • Crusader Kings II
  • Major Wiki Contributor
So, tell me what do you think of this initiative, wether you would be interested in using it, and any suggestions you may have to improve it.

I understand the intent and bear the pain of CK2 syntax limitations too, but I don't think this is viable.
That'd require modders to learn the 2 completely different syntaxes, with their own caveats (and bugs), and because the in-game error logs would still point to syntax errors in the old syntax, I would quickly become mad !

However I've seen this working well when the meta-language is a superset of the base language (ex: typescript vs javascript, or less vs css), so you don't have to rewrite everything to start using it, by keeping the base syntax, and adding new language features (ex: new '+' operator) that get replace after processing into the boilerplate code (add_variable = { ... } ). But this probably means implementing a parser for CK2 base language (before enriching it), and that's a tough task... There's also the problem to easily correlate line numbers from error.log or the validator in built file, with line number in the original file.
 

ngppgn

Field Marshal
19 Badges
Jan 29, 2011
3.508
657
  • Crusader Kings III
  • Imperator: Rome
  • Imperator: Rome Deluxe Edition
  • Crusader Kings II: Jade Dragon
  • Europa Universalis IV
  • Crusader Kings II: Monks and Mystics
  • Hearts of Iron IV: Cadet
  • Stellaris Sign-up
  • Stellaris
  • Crusader Kings II: Horse Lords
  • Europa Universalis IV: Res Publica
  • Crusader Kings II
  • Heir to the Throne
  • Europa Universalis IV: Call to arms event
  • Europa Universalis IV: Conquest of Paradise
  • Divine Wind
  • Europa Universalis III: Chronicles
  • Europa Universalis III
  • Crusader Kings II: The Old Gods
I understand the intent and bear the pain of CK2 syntax limitations too, but I don't think this is viable.
That'd require modders to learn the 2 completely different syntaxes, with their own caveats (and bugs), and because the in-game error logs would still point to syntax errors in the old syntax, I would quickly become mad !

However I've seen this working well when the meta-language is a superset of the base language (ex: typescript vs javascript, or less vs css), so you don't have to rewrite everything to start using it, by keeping the base syntax, and adding new language features (ex: new '+' operator) that get replace after processing into the boilerplate code (add_variable = { ... } ). But this probably means implementing a parser for CK2 base language (before enriching it), and that's a tough task... There's also the problem to easily correlate line numbers from error.log or the validator in built file, with line number in the original file.

I appreciate the concerns, and yes, learning the new syntax is a ver major obstacle. If the metalanguage language were to be a superset of ck2script that'd be much alleviated, if I bring this project to good shape, I might consider also doig that.

Relating line numbers is something i have sorted in concept: since lines in pyCK2 are more or less logical lines it is easy to add a comment in the output code #here starts line 123 just before the output is written, lis linke
Code:
#here starts line 123 with contents 'xyz'
<outputted code>
<more outputted code>
[...]
or
Code:
<outputted code> #here starts line 123 with contents 'xyz'
<more outputted code>
[...]
When hunting bugs, you'd ideally be browsing both the pyCK2 and the output code in parallel,
so would those annotations do the trick for you?

The issue of debugging script is indeed a tough one. Luckily, the text parser in sublime allows me to catch any syntax error (the "parsing error" of the validator") and quite a fiew "value of unexpected type" error. (e.g. since you're forced to explicitly write wether an event target is a char, prov, title, artifact, etc. it's way less likely that you supply a province event target to a trigger that expected a title, and this is caught as you are writing).

If I get my way in the long term, I will translate all the base game script to pyCK2 and maintain a database of all identifiers too, so as long as the user saves whenever he define a new entity (e.g. an event), any calls to undefined identifiers would also be caught, as long as he is not relying on a third party mod.

Eventually, to provide full bug-hunting services I'd need to actually be able to parse the base game and any mod, anyway... But by then maybe CK3 will be already out :D
 
Last edited: