RFC: A single source for default values (FOCS, python, stringtables, backend)

For what's not in 'Top Priority Game Design'. Post your ideas, visions, suggestions for the game, rules, modifications, etc.

Moderator: Oberlus

Message
Author
Ophiuchus
Programmer
Posts: 3433
Joined: Tue Sep 30, 2014 10:01 am
Location: Wall IV

RFC: A single source for default values (FOCS, python, stringtables, backend)

#1 Post by Ophiuchus »

How about we add a file (or files in directory tree) for having a single source of default game values so FOCS, AI, stringtables and backend can use it.

At the moment we often have to replicate values manually in all those places and keep consistent. For example i think many values in languages other than french and english are wrong or not even mentioned because we fear they could change. Also AI could rely on outdated values.

If we have a single place to take those values from the values are always "auto-magically" consistent.

That file format should only contain key/value pairs and could be put into files default/default.values or e.g. default/scripting/ship_hulls/ship_hulls.values.

The mechanism which comes closest are game rules, but i think it is UI-overkill to add a rule for each base value which might change in development.
Any code or patches in anything posted here is released under the CC and GPL licences in use for the FO project.

Look, ma... four combat bouts!

o01eg
Programmer
Posts: 2004
Joined: Sat Dec 10, 2011 5:46 am

Re: RFC: A single source for default values (FOCS, python, stringtables, backend)

#2 Post by o01eg »

Gentoo Linux x64, gcc-11.2, boost-1.78.0
Ubuntu Server 22.04 x64, gcc-12, boost-1.74.0
Welcome to the slow multiplayer game at freeorion-lt.dedyn.io.Version 2024-03-15.b3de094.
Donations're welcome:BTC:bc1q007qldm6eppqcukewtfkfcj0naut9njj7audnm

User avatar
Oberlus
Cosmic Dragon
Posts: 5715
Joined: Mon Apr 10, 2017 4:25 pm

Re: RFC: A single source for default values (FOCS, python, stringtables, backend)

#3 Post by Oberlus »

o01eg wrote: Sat Nov 16, 2019 11:35 am What about https://freeorion.org/forum/viewtopic.php?f=9&t=10215 ?
I'm totally in favor of that. For all the reasons listed there, and because I still don't understand the syntax of FOCS. Wiki and the such are helpful but not enough, at all, there is always places were all you (non FOC-expert) can do is trial and error until Geoff or someone else comes in rescue. If I have to learn a new language, Python would be more interesting than FOCS.

User avatar
Geoff the Medio
Programming, Design, Admin
Posts: 13587
Joined: Wed Oct 08, 2003 1:33 am
Location: Munich

Re: RFC: A single source for default values (FOCS, python, stringtables, backend)

#4 Post by Geoff the Medio »

Oberlus wrote: Sat Nov 16, 2019 11:50 am...because I still don't understand the syntax of FOCS. Wiki and the such are helpful but not enough, at all, there is always places were all you (non FOC-expert) can do is trial and error until Geoff or someone else comes in rescue. If I have to learn a new language, Python would be more interesting than FOCS.
I don't think replacing FOCS with Python-parsed structs would help much with needing help or learning Python in general. The hard-to-learn domain-specific issues of what stuff can be scripted wouldn't change, and very little Python code would be involved, as the "scripting" would still be mostly declarative definitions of parts, techs, species and such with their contained effects, conditions, and valuerefs. There may be advantages to Python-declared scripting vs. Boost-parsed scripting, but those aren't. (See the example in the linked post.)
Ophiuchus wrote: Sat Nov 16, 2019 9:51 am...single source of default game values so FOCS, AI, stringtables and backend can use it.
What default values are you referring to?

User avatar
Oberlus
Cosmic Dragon
Posts: 5715
Joined: Mon Apr 10, 2017 4:25 pm

Re: RFC: A single source for default values (FOCS, python, stringtables, backend)

#5 Post by Oberlus »

Geoff the Medio wrote: Sat Nov 16, 2019 1:52 pm What default values are you referring to?
Any value you can find in a FOCS file, like the base structure of a hull, the boost to a meter from a tech/building, etc.

User avatar
Geoff the Medio
Programming, Design, Admin
Posts: 13587
Joined: Wed Oct 08, 2003 1:33 am
Location: Munich

Re: RFC: A single source for default values (FOCS, python, stringtables, backend)

#6 Post by Geoff the Medio »

The issue in that case doesn't depend on what scripting language is used; switching to Python won't change anything.

What you want is either:
1) A way to look up a scripted value in another script, in a stringtable entry, or in the AI code
or
2) A way to define those values in a single place and reference the defined value in any of

(2) would could be awkward to use for things like part costs or hull structure, as it would essentially mean having a big table, or many small tables, of macro definitions, which can be inserted / referenced like normal stringtable or script macros into scripts or stringtables, rather than putting those values into the scripts themselves. This would mean the values wouldn't be defined where the content that uses them is defined. This can already be done, however, as you can #include files into other stringtable or FOCS files, and both can use macros lookups by [[KEY]].

(1) would require a way to look up scripted values by writing a little script to do so, and be able to do so within stringtable macros. It's already possible for some things in FOCS, like using the HullStructure complex value ref and passing the name of the hull ( https://github.com/freeorion/freeorion/ ... er.cpp#L47 ). But there's no way to write an equivalent FOCS script into a stringtable macro though, and have it be evaluated at runtime, and it would be a bit of work to allow it. Notably, it would be a run-time / lazy lookup, so that it can look up the data in the current game using the currently-applicable parsed content, which could change if the resources directory is changed or a game's rules are changed. Something similar is already done by having various parameters in stringtables like %1% which are replaced when the string is rendered in-game, based on the C++ code expecting a particular stringtable entry to have %1% and similar fields in it to be replaced. Scripting those substitutions in the stringtable entry itself would be more complicated and require some additional coding to support, but shouldn't be impossible... maybe something like:

[[FOCSVAL HullStructure name = "SH_COLONY_BASE"]]

Which would be replaced by whatever the stucture is of the colony base hull in the current game, evaluated when the string is being rendered.

User avatar
Oberlus
Cosmic Dragon
Posts: 5715
Joined: Mon Apr 10, 2017 4:25 pm

Re: RFC: A single source for default values (FOCS, python, stringtables, backend)

#7 Post by Oberlus »

Geoff the Medio wrote: Sat Nov 16, 2019 2:45 pmThe issue in that case doesn't depend on what scripting language is used; switching to Python won't change anything.
Indeed. My issues with FOCS syntax and preference for Python were properly addressed with your previous post :)

2) A way to define those values in a single place and reference the defined value in any of
(2) would could be awkward to use for things like part costs or hull structure, as it would essentially mean having a big table, or many small tables, of macro definitions, which can be inserted / referenced like normal stringtable or script macros into scripts or stringtables, rather than putting those values into the scripts themselves. This would mean the values wouldn't be defined where the content that uses them is defined. This can already be done, however, as you can #include files into other stringtable or FOCS files, and both can use macros lookups by [[KEY]].
I think that's what I'd prefer.

Ophiuchus
Programmer
Posts: 3433
Joined: Tue Sep 30, 2014 10:01 am
Location: Wall IV

Re: RFC: A single source for default values (FOCS, python, stringtables, backend)

#8 Post by Ophiuchus »

Geoff the Medio wrote: Sat Nov 16, 2019 2:45 pm 1) A way to look up a scripted value in another script, in a stringtable entry, or in the AI code
or
2) A way to define those values in a single place and reference the defined value in any of

(2) would could be awkward to use for things like part costs or hull structure, as it would essentially mean having a big table, or many small tables, of macro definitions, which can be inserted / referenced like normal stringtable or script macros into scripts or stringtables, rather than putting those values into the scripts themselves. This would mean the values wouldn't be defined where the content that uses them is defined. This can already be done, however, as you can #include files into other stringtable or FOCS files, and both can use macros lookups by [[KEY]].
A combination of both approaches would be best in my opinion. But standard things like part costs, hull structure etc are well enough addressed as you can simply experiment in the ship designer and have a look at the results and also the AI has access to such values.

So what is more pressing are things like organic hull growth effects and similar for which approach 2) is probably enough.
Any code or patches in anything posted here is released under the CC and GPL licences in use for the FO project.

Look, ma... four combat bouts!

User avatar
Oberlus
Cosmic Dragon
Posts: 5715
Joined: Mon Apr 10, 2017 4:25 pm

Re: RFC: A single source for default values (FOCS, python, stringtables, backend)

#9 Post by Oberlus »

I'm trying to do this.

I've done the following:

New file /default/scripting/techs/defense/defense_values.macros

Code: Select all

DEF_GARRISON_1_FLAT_BONUS
'''50 * [[TROOPS_PER_POP]]'''

DEF_GARRISON_2_POP_BONUS
'''2 * [[TROOPS_PER_POP]]'''

DEF_GARRISON_2_REG
'''5 * [[TROOPS_PER_POP]]'''

DEF_GARRISON_3_FLAT_BONUS
'''80 * [[TROOPS_PER_POP]]'''

DEF_GARRISON_3_REG
'''10 * [[TROOPS_PER_POP]]'''

DEF_GARRISON_4_POP_BONUS
'''2 * [[TROOPS_PER_POP]]'''

DEF_GARRISON_4_REG
'''15 * [[TROOPS_PER_POP]]'''

#include "/scripting/common/base_prod.macros"
Changes in /default/scripting/techs/defense/Garrison.focs.txt

Code: Select all

Tech
    name = "DEF_GARRISON_1"
    description = "DEF_GARRISON_1_DESC"
    short_description = "TROOPS_SHORT_DESC"
    category = "DEFENSE_CATEGORY"
    researchcost = 5 * [[TECH_COST_MULTIPLIER]]
    researchturns = 3
    tags = [ "PEDIA_DEFENSE_CATEGORY" ]
    prerequisites = "DEF_ROOT_DEFENSE"
    effectsgroups = [
        EffectsGroup
            scope = And [
                Planet
                OwnedBy empire = Source.Owner
            ]
            stackinggroup = "GARRISON_1_TROOPS_STACK"
            priority = [[LATE_PRIORITY]]
            effects = SetMaxTroops value = Value + [[DEF_GARRISON_1_FLAT_BONUS]] accountinglabel = "DEF_GARRISON_1"
    ]
    graphic = "icons/tech/troops.png"

Tech
    name = "DEF_GARRISON_2"
    description = "DEF_GARRISON_2_DESC"
    short_description = "TROOPS_SHORT_DESC"
    category = "DEFENSE_CATEGORY"
    researchcost = 15 * [[TECH_COST_MULTIPLIER]]
    researchturns = 5
    tags = [ "PEDIA_DEFENSE_CATEGORY" ]
    prerequisites = "DEF_GARRISON_1"
    effectsgroups = [
        EffectsGroup
            scope = And [
                Planet
                OwnedBy empire = Source.Owner
                (LocalCandidate.LastTurnAttackedByShip   < CurrentTurn)
            ]
            effects = SetTroops value = Value + [[DEF_GARRISON_2_REG]]

        EffectsGroup
            scope = And [
                Planet
                OwnedBy empire = Source.Owner
                Population low = 0.01
            ]
            stackinggroup = "GARRISON_2_TROOPS_STACK"
            priority = [[EARLY_PRIORITY]]
            effects = SetMaxTroops value = Value + Target.Population * [[DEF_GARRISON_2_POP_BONUS]] accountinglabel = "DEF_GARRISON_2"
    ]
    graphic = "icons/tech/troops.png"

Tech
    name = "DEF_GARRISON_3"
    description = "DEF_GARRISON_3_DESC"
    short_description = "TROOPS_SHORT_DESC"
    category = "DEFENSE_CATEGORY"
    researchcost = 50 * [[TECH_COST_MULTIPLIER]]
    researchturns = 7
    tags = [ "PEDIA_DEFENSE_CATEGORY" ]
    prerequisites = "DEF_GARRISON_2"
    effectsgroups = [
        EffectsGroup
            scope = And [
                Planet
                OwnedBy empire = Source.Owner
                (LocalCandidate.LastTurnAttackedByShip   < CurrentTurn)
            ]
            effects = SetTroops value = Value + [[DEF_GARRISON_3_REG]]

        EffectsGroup
            scope = And [
                Planet
                OwnedBy empire = Source.Owner
            ]
            stackinggroup = "GARRISON_3_TROOPS_STACK"
            priority = [[LATE_PRIORITY]]
            effects = SetMaxTroops value = Value + [[DEF_GARRISON_3_FLAT_BONUS]] accountinglabel = "DEF_GARRISON_3"
    ]
    graphic = "icons/tech/troops.png"

Tech
    name = "DEF_GARRISON_4"
    description = "DEF_GARRISON_4_DESC"
    short_description = "TROOPS_SHORT_DESC"
    category = "DEFENSE_CATEGORY"
    researchcost = 150 * [[TECH_COST_MULTIPLIER]]
    researchturns = 9
    tags = [ "PEDIA_DEFENSE_CATEGORY" ]
    prerequisites = "DEF_GARRISON_3"
    effectsgroups = [
        EffectsGroup
            scope = And [
                Planet
                OwnedBy empire = Source.Owner
                (LocalCandidate.LastTurnAttackedByShip   < CurrentTurn)
            ]
            effects = SetTroops value = Value + [[DEF_GARRISON_4_REG]]

        EffectsGroup
            scope = And [
                Planet
                OwnedBy empire = Source.Owner
                Population low = 0.01
            ]
            stackinggroup = "GARRISON_4_TROOPS_STACK"
            priority = [[EARLY_PRIORITY]]
            effects = SetMaxTroops value = Value + Target.Population * [[DEF_GARRISON_4_POP_BONUS]] accountinglabel = "DEF_GARRISON_4"
    ]
    graphic = "icons/tech/troops.png"

#include "../techs.macros"

#include "/scripting/techs/defense/defense_values.macros"

#include "/scripting/common/priorities.macros"
That is, add the end of the file #include "/scripting/common/priorities.macros"
And change the values for the macros in that included file.


Changes in /default/stringtables/en.txt:

Code: Select all

DEF_GARRISON_1_DESC
Increases max [[metertype METER_TROOPS]] on all planets by [[DEF_GARRISON_1_FLAT_BONUS]], unmodified by species traits.

DEF_GARRISON_2
Defensive Militia Training

DEF_GARRISON_2_DESC
Increases max [[metertype METER_TROOPS]] on all planets by [[DEF_GARRISON_2_POP_BONUS]] per [[metertype METER_POPULATION]] (modified by species defensive trait), and causes troops to regenerate by an additional [[DEF_GARRISON_2_REG]] per turn.

DEF_GARRISON_3
Planetary Fortification Network

DEF_GARRISON_3_DESC
Increases max [[metertype METER_TROOPS]] on all planets by [[DEF_GARRISON_3_FLAT_BONUS]] (unmodified by species traits) and causes troops to regenerate by an additional [[DEF_GARRISON_3_REG]] per turn in addition to that from [[DEF_GARRISON_2]].

DEF_GARRISON_4
Planetary Guard Brigades

DEF_GARRISON_4_DESC
Increases max [[metertype METER_TROOPS]] on all planets by [[DEF_GARRISON_4_POP_BONUS]] per [[metertype METER_POPULATION]] (modified by species defensive trait), and causes troops to regenerate by an additional [[DEF_GARRISON_4_REG]] per turn in addition to that from [[DEF_GARRISON_3]] and [[DEF_GARRISON_2]].

// At the end of the file after the other #include:
#include "../scripting/techs/defense/defense_values.macros"
That is, substitute the values for the macros and add the new macros files at the end of file.


It doesn't work. Specifically it breaks all referencing in all Pedia articles (and probably in other places). Examples:
The Pedia button in the splash screen now says "[[MAP_BTN_PEDIA]]".
The Pedia article for specials -> Abandoned Colony now shows "An old abandoned colony. Some of the [[metertype METER_CONSTRUCTION]] should still be useful." (that is, the macro/link for metertype METER_CONSTRUCTION is not working).

What I am doing wrong?

Ophiuchus
Programmer
Posts: 3433
Joined: Tue Sep 30, 2014 10:01 am
Location: Wall IV

Re: RFC: A single source for default values (FOCS, python, stringtables, backend)

#10 Post by Ophiuchus »

Oberlus wrote: Fri May 29, 2020 9:31 am What I am doing wrong?
Nothing, I think it is not supported. At least not for calculated macros.

You could try if simple string expansion for macros works already.

something like:
DEF_GARRISON_2_POP_BONUS
'''2'''


Of course what we need are calculated values, at least some support for arithmetics (+,-,*,rounding) including game rule lookups.
Any code or patches in anything posted here is released under the CC and GPL licences in use for the FO project.

Look, ma... four combat bouts!

User avatar
Geoff the Medio
Programming, Design, Admin
Posts: 13587
Joined: Wed Oct 08, 2003 1:33 am
Location: Munich

Re: RFC: A single source for default values (FOCS, python, stringtables, backend)

#11 Post by Geoff the Medio »

Ophiuchus wrote: Fri May 29, 2020 10:23 am
Oberlus wrote: Fri May 29, 2020 9:31 amWhat I am doing wrong?
Nothing, I think it is not supported. At least not for calculated macros.
Macros insert text into other text, including into stringtable entries. The issue is that there is no mechanism for a non-trival (ie. not plain text) FOCS expression in a stringtable entry to be evaluated and replaced with something else. Whether or not the expression is present due to being written explicitly or by macro substitution doesn't matter.

Ophiuchus
Programmer
Posts: 3433
Joined: Tue Sep 30, 2014 10:01 am
Location: Wall IV

Re: RFC: A single source for default values (FOCS, python, stringtables, backend)

#12 Post by Ophiuchus »

Geoff the Medio wrote: Fri May 29, 2020 11:37 am
Ophiuchus wrote: Fri May 29, 2020 10:23 am
Oberlus wrote: Fri May 29, 2020 9:31 amWhat I am doing wrong?
Nothing, I think it is not supported. At least not for calculated macros.
Macros insert text into other text, including into stringtable entries. The issue is that there is no mechanism for a non-trival (ie. not plain text) FOCS expression in a stringtable entry to be evaluated and replaced with something else. Whether or not the expression is present due to being written explicitly or by macro substitution doesn't matter.
If I read you correctly you would expect the following to work/be usable in stringtables?

MACRO_OUTER
'''[[MACRO_SPACE]]'''

MACRO_SPACE
''' '''
Any code or patches in anything posted here is released under the CC and GPL licences in use for the FO project.

Look, ma... four combat bouts!

User avatar
Geoff the Medio
Programming, Design, Admin
Posts: 13587
Joined: Wed Oct 08, 2003 1:33 am
Location: Munich

Re: RFC: A single source for default values (FOCS, python, stringtables, backend)

#13 Post by Geoff the Medio »

If I read you correctly you would expect the following to work/be usable in stringtables?

MACRO_OUTER
'''[[MACRO_SPACE]]'''

MACRO_SPACE
''' '''
yes

User avatar
Oberlus
Cosmic Dragon
Posts: 5715
Joined: Mon Apr 10, 2017 4:25 pm

Re: RFC: A single source for default values (FOCS, python, stringtables, backend)

#14 Post by Oberlus »

I tried it. Not sure if I got it right.

New file defense_values.macros

Code: Select all

DEF_GARRISON_1_FLAT_BONUS_ST
'''[[DEF_GARRISON_1_FLAT_BONUS]]''

DEF_GARRISON_1_FLAT_BONUS
'''50 * [[TROOPS_PER_POP]]'''

DEF_GARRISON_2_POP_BONUS_ST
'''[[DEF_GARRISON_2_POP_BONUS]]'''

DEF_GARRISON_2_POP_BONUS
'''2 * [[TROOPS_PER_POP]]'''

DEF_GARRISON_2_REG_ST
'''[[DEF_GARRISON_2_REG]]'''

DEF_GARRISON_2_REG
'''5 * [[TROOPS_PER_POP]]'''

DEF_GARRISON_3_FLAT_BONUS_ST
'''[[DEF_GARRISON_3_FLAT_BONUS]]'''

DEF_GARRISON_3_FLAT_BONUS
'''80 * [[TROOPS_PER_POP]]'''

DEF_GARRISON_3_REG_ST
'''[[DEF_GARRISON_3_REG]]'''

DEF_GARRISON_3_REG
'''10 * [[TROOPS_PER_POP]]'''

DEF_GARRISON_4_POP_BONUS_ST
'''[[DEF_GARRISON_4_POP_BONUS]]'''

DEF_GARRISON_4_POP_BONUS
'''2 * [[TROOPS_PER_POP]]'''

DEF_GARRISON_4_REG_ST
'''[[DEF_GARRISON_4_REG]]'''

DEF_GARRISON_4_REG
'''15 * [[TROOPS_PER_POP]]'''

#include "/scripting/common/base_prod.macros"
And the references to the macros in the stringtable changed to the "*_ST" ones

I also tried putting the "_ST" macros in second place.


The scrambled Pedia problem persists.

Also, there's and error at freeorion start:

Code: Select all

/home/lucas/Projects/FreeOrion/master-testing-build/default/scripting/techs/defense/Garrison.focs.txt:18:49: Parse error.  Expected ] here:
                Planet
                OwnedBy empire = Source.Owner
            ]
            stackinggroup = "GARRISON_1_TROOPS_STACK"
            priority = 110
            effects = SetMaxTroops value = Value + [[DEF_GARRISON_1_FLAT_BONUS]]
                                                 ^
            accountinglabel = "DEF_GARRISON_1"
    ]
    graphic = "icons/tech/troops.png"

Tech

User avatar
Geoff the Medio
Programming, Design, Admin
Posts: 13587
Joined: Wed Oct 08, 2003 1:33 am
Location: Munich

Re: RFC: A single source for default values (FOCS, python, stringtables, backend)

#15 Post by Geoff the Medio »

Oberlus wrote: Sat May 30, 2020 1:20 pmNew file defense_values.macros

Code: Select all

DEF_GARRISON_1_FLAT_BONUS_ST
'''[[DEF_GARRISON_1_FLAT_BONUS]]''

DEF_GARRISON_1_FLAT_BONUS
'''50 * [[TROOPS_PER_POP]]'''
I'm not sure what you're trying to do here, but it doesn't appear to be a simple text substitution with nested stringtable keys like

Code: Select all

MACRO_OUTER
'''[[MACRO_SPACE]]'''

MACRO_SPACE
''' ''' 
Wrapping stuff in another layer of macro doesn't stop it from being a FOCS expression, and it will still be treated as just text when put into the stringtable, which doesn't know anything about FOCS expressions. All a macro / key substitution in the stringtable does it substitute text in place of the macro / key. After that, if it's a math expression, the strintable and UI won't treat it any special way. There are a few things that some bits of the UI do recognize, like formatting markup <i>italic text</i> or content links, but FOCS isn't one of those.

There are probably error messages in the logs telling you what's wrong with the stringtable. My guess is the use of undefined key substitutions.

Post Reply