Excruciating FOCS doubts

Creation, discussion, and balancing of game content such as techs, buildings, ship parts.

Moderators: Oberlus, Committer

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

Re: Excruciating FOCS doubts

#76 Post by Oberlus »

LienRag, maybe you could google what is a ValueRef (reference to a value), and look at the Eval() function of FreeOrion's C++ code.
You can't expect FreeOrion developers or forum users to teach you programming basics. That's on you, but there are plenty of resources on Internet available to you.

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

Re: Excruciating FOCS doubts

#77 Post by Geoff the Medio »

LienRag wrote: Thu May 20, 2021 6:48 pm
Geoff the Medio wrote: Wed May 19, 2021 10:42 pm Within the script for the condition, you can refer to the RootCandidate object, which is an object that the outer condition is considering matching (ie. one of the ships). You can also refer to the LocalCandidate object, which changes depending where you refer to it. If in the outer condition part of the script, it will be the same as the RootCandidate. Within the inner condition (matching planets) part of the script, it will be the object that the inner condition is considering matching.
...this part would probably need more explaining, with examples and probably a diagram (of a few ones).
Consider:

Code: Select all

    scope = And [
            Ship
            EmpireHasAdoptedPolicy empire = LocalCandidate.Owner name = "PLC_ALLIED_REPAIR"
            
            WithinStarlaneJumps jumps = RootCandidate.Fuel condition = And [
                Planet
                OwnedBy empire = Source.Owner
                Species name = RootCandidate.Species
                Population low = 1 high = LocalCandidate.TargetPopulation - 1
            ]
        ]
Conditions are tests applied to each candidate object. The candidate objects for a scope condition like this are all objects in the universe, each of which is tested.

The "top level" or "outer" condition is and And condition, which matches objects only if the object matches all of its subconditions. The subconditions are tested in order, so in this example, only objects that are ships have their owner's adopted policies checked, and only those that pass that have their jump distances to planets checked.

The WithinStarlaneJumps condition has another layer of an inner or subcondition, which is also an And condition with several parts that are tested in order. But the objects that are tested or match the inner And are not the same objects that are tested or match the outer-most condition or the WithinStarlaneJumps condition.


RootCandidate always refers to an object being tested by the And condition because it is the outermost condition. When the tested root candidate object changes, so will the object that RootCandidate refers to.

LocalCandidate refers to the object being matched by the inner-most condition at the place it is written.

In jumps = RootCandidate.Fuel or empire = LocalCandidate.Owner, the root candidate and the local candidate are the same object, so those object reference could be switched with no change in the results.

Within Species name = RootCandidate.Species, the root candidate and local candidate are different objects. RootCandidate still refers to a ship being tested by the outer And and WithinStarlaneJumps conditions, but in that part of the script, LocalCandidate refers to a planet being tested by the inner And condition. RootCandidate will change for each outer condition candidate that is tested, while LocalCandidate will change for each inner condition candidate that is tested.

In order to evaluate whether the root candidate is matched by the WithinStarlaneJumps condition, a separate test on an independent set of candidate objects is evaluated. When the engine reaches the WithinStarlaneJumps condition, it first evaluates the inner condition, and then uses that result of the inner condition to run the test on the object it is actually matching. In this case, first it has to determine which planets are matched by the inner condition, and then it can check whether the ship it is testing is within some distance of one of those planets.
Secondly, the first assignment (effects = something) is logically not the same thing than the second (something = value + 40)¹; in a way they're nested assignments if I understand correctly.
Based on this and your earlier example of how you thought a Python-scripted condition would be written, you're thinking of these scripts as if they are procedural code, with a series of commands that are executed in order like an interpreted Python program. This is not the right mental model. Rather, these scripts are defining an expression tree or data structure that tells the program what the result should be.

It's the difference between "create a condition that matches the terran planets with no population" and

Code: Select all

def TerranUnpopulated(candidates):
matches = []
for candidate in candidates:
    if IsPlanet(candidate):
        if candidate.population > 0:
            matches.append(candidate)
return matches
Another way to think of it is that in Python you might have a line of code like

Code: Select all

a = 5 + 10
whereas in FOCS a similar behaviour might be expressed like as an Effect script like

Code: Select all

VaribleAssignment name = "a" value = (PerformMathOperation operator = Plus lhs = 5 rhs = 10)
where the = means not "perform an assignment" but rather "the parameter to the left has the value given by the expression to the right". Except for brevity, FOCS actually has a somehwat more compact syntax for many operations, and so for a simple + operation, it would instead be written more like

Code: Select all

VaribleAssignment name = "a"  value = 5 + 10
and in many cases there are simpler dedicated symbols for the assign to A effect, so it would look like

Code: Select all

AssignToA value = 5 + 10
When the FOCS parser sees that, it doens't execute it immediately. Rather, it creates a data structure representing that expression, and when the engine later decides to run that effect on an object, it traverses the data structure and calls a series of functions that evaluate the expression and modify the object according to the results of the traversal and evaluation.

But again, a key conceptual problem might be that "value = 5 + 10" is not an assignment. Rather, "AssignToA" creates an assignment effect, and "value = 5 + 10" specifies how to calculate what to assign to A when the effect is executed.

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

Re: Excruciating FOCS doubts

#78 Post by Ophiuchus »

LienRag wrote: Thu May 20, 2021 7:01 pm
Ophiuchus wrote: Thu May 20, 2021 12:09 pm Maybe it helps to remember that conditions, effects, valuerefs (which could look like object properties to you) are evaluated at runtime on the server. This is done as Eval() calls on cpp objects and never via python. If the python scripting will allow more to do than the current FOCS that will still spit out that c structures in the end, subject to the way the server evaluates those - and python has no direct access to runtime object.
if the FreeOrion team wants to have user-generated content, it certainly shouldn't need mastery of C++.
Yes, agreed. Documentation and IDE support could be a solution here.

Anyway, the point was that you need to understand how evaluation works conceptually in order to grok scripting.

That there are four basic different kinds of things you can actually script, simple values (e.g. buildturns), conditions (e.g. scope), effects (in a effect group), and valuerefs (calculations). These are used to construct the bigger structures (e.g. a type of ship hull). And that the evaluation happens on this structures on the server and never inside the scripting language. The only processing happening before such structures get created is macro expansion (i.e. substituting characters/text snippets), so also a simple calculation of e.g. 1+1 happens later at runtime in c++.

Conditions work similar to select clauses in SQL, not like working on objects on python. At runtime, when a condition is evaluated it gets passed a set of objects (in scope that is usually the whole universe and in combatTargets it is the objects in the combat in that system that turn). You can then filter that set to have only the objects you want to base your effects on. Each candidate which is left in the topmost condition in a scope become the Target for effect evaluation.
LienRag wrote: Wed May 19, 2021 10:13 pm it means that a FOCS condition may test for building, field, fighter, fleet, planet, ship and/or system.
Yes, also. More importantly, the result of a condition is a set of such objects (and nothing else). Also Source, Target, *Candidate is such an object.
There is no object for e.g. a ship part. That is why there is an effect changing meters of a part of a given ship instead of an effect changing the meter of a given ship part. Also the way it is done means that all parts of the same part name share the meters (e.g. you cant modify the damage of multiple mass drivers in a ship separately).

The result of a valueref can also be an integer, a float, a string, a PlanetType,.. value and it can be used as input for a condition or an effect.
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
LienRag
Cosmic Dragon
Posts: 2148
Joined: Fri May 17, 2019 5:03 pm

Re: Excruciating FOCS doubts

#79 Post by LienRag »

OK, thanks for your replies.
I will need some time to digest all that...

User avatar
LienRag
Cosmic Dragon
Posts: 2148
Joined: Fri May 17, 2019 5:03 pm

Re: Excruciating FOCS doubts

#80 Post by LienRag »

Apart from that, I'm not sure to understand the FOCS code of the Ancient Ruins ?

The various possible results of Excavation are, for the first three, coded that way :

Code: Select all

        EffectsGroup
            scope = Source
            activation = And [
                Random probability = .2
                OwnerHasTech name = "LRN_XENOARCH"
            ]
            stackinggroup = "ANCIENT_RUINS_TECH_UNLOCK"
            effects = [
                CreateShip designname = "SD_DRAGON_TOOTH" empire = Source.Owner species = Source.Species
                GenerateSitRepMessage
                    message = "EFFECT_ANCIENT_SHIP"
                    label = "EFFECT_ANCIENT_SHIP_LABEL"
                    icon = "icons/specials_huge/ancient_ruins_excavated.png"
                    parameters = [
                        tag = "planet" data = Source.ID
                        tag = "predefinedshipdesign" data = "SD_DRAGON_TOOTH"
                    ]
                    empire = Source.Owner
                GenerateSitRepMessage
                    message = "EFFECT_ANCIENT_SHIP_RUMORS"
                    label = "EFFECT_ANCIENT_SHIP_RUMORS_LABEL"
                    icon = "icons/specials_huge/ancient_ruins_excavated.png"
                    parameters = [
                        tag = "predefinedshipdesign" data = "SD_DRAGON_TOOTH"
                    ]
            ]

        EffectsGroup
            scope = Source
            activation = And [
                Random probability = 0.25
                OwnerHasTech name = "LRN_XENOARCH"
            ]
            stackinggroup = "ANCIENT_RUINS_TECH_UNLOCK"
            effects = [
                CreateBuilding type = "BLD_NEUTRONIUM_SYNTH"
                GenerateSitRepMessage
                    message = "EFFECT_ANCIENT_BUILDING"
                    label = "EFFECT_ANCIENT_BUILDING_LABEL"
                    icon = "icons/specials_huge/ancient_ruins_excavated.png"
                    parameters = [
                        tag = "planet" data = Source.ID
                        tag = "buildingtype" data = "BLD_NEUTRONIUM_SYNTH"
                    ]
                    empire = Source.Owner
                GenerateSitRepMessage
                    message = "EFFECT_ANCIENT_BUILDING_RUMORS"
                    label = "EFFECT_ANCIENT_BUILDING_RUMORS_LABEL"
                    icon = "icons/specials_huge/ancient_ruins_excavated.png"
                    parameters = [
                        tag = "buildingtype" data = "BLD_NEUTRONIUM_SYNTH"
                    ]
            ]

        EffectsGroup
            scope = Source
            activation = And [
                Random probability = 0.50
                NotOwnerHasTech name = "SHP_WEAPON_4_1"
                OwnerHasTech name = "LRN_XENOARCH"
            ]
            stackinggroup = "ANCIENT_RUINS_TECH_UNLOCK"
            effects = [
                GiveEmpireTech name = "SHP_WEAPON_4_1" empire = Target.Owner
                GenerateSitRepMessage
                    message = "EFFECT_ANCIENT_TECH"
                    label = "EFFECT_ANCIENT_TECH_LABEL"
                    icon = "icons/specials_huge/ancient_ruins_excavated.png"
                    parameters = [
                        tag = "planet" data = Source.ID
                        tag = "tech" data = "SHP_WEAPON_4_1"
                    ]
                    empire = Source.Owner
                GenerateSitRepMessage
                    message = "EFFECT_ANCIENT_TECH_RUMORS"
                    label = "EFFECT_ANCIENT_TECH_RUMORS_LABEL"
                    icon = "icons/specials_huge/ancient_ruins_excavated.png"
                    parameters = [
                        tag = "tech" data = "SHP_WEAPON_4_1"
                    ]
            ]
Then the two others are coded that way :

Code: Select all

        EffectsGroup
            scope = Source
            activation = And [
                Not OwnerHasTech name = "SHP_MULTISPEC_SHIELD"
                OwnerHasTech name = "LRN_XENOARCH"
            ]
            stackinggroup = "ANCIENT_RUINS_TECH_UNLOCK"
            effects = [
                GiveEmpireTech name = "SHP_MULTISPEC_SHIELD" empire = Target.Owner
                GenerateSitRepMessage
                    message = "EFFECT_ANCIENT_TECH"
                    label = "EFFECT_ANCIENT_TECH_LABEL"
                    icon = "icons/specials_huge/ancient_ruins_excavated.png"
                    parameters = [
                        tag = "planet" data = Source.ID
                        tag = "tech" data = "SHP_MULTISPEC_SHIELD"
                    ]
                    empire = Source.Owner
                GenerateSitRepMessage
                    message = "EFFECT_ANCIENT_TECH_RUMORS"
                    label = "EFFECT_ANCIENT_TECH_RUMORS_LABEL"
                    icon = "icons/specials_huge/ancient_ruins_excavated.png"
                    parameters = [
                        tag = "tech" data = "SHP_MULTISPEC_SHIELD"
                    ]
            ]

        EffectsGroup
            scope = Source
            activation = And [
                Not OwnerHasTech name = "SHP_KRILL_SPAWN"
                OwnerHasTech name = "LRN_XENOARCH"
            ]
            stackinggroup = "ANCIENT_RUINS_TECH_UNLOCK"
            effects = [
                GiveEmpireTech name = "SHP_KRILL_SPAWN" empire = Target.Owner
                GenerateSitRepMessage
                    message = "EFFECT_ANCIENT_TECH"
                    label = "EFFECT_ANCIENT_TECH_LABEL"
                    icon = "icons/specials_huge/ancient_ruins_excavated.png"
                    parameters = [
                        tag = "planet" data = Source.ID
                        tag = "tech" data = "SHP_KRILL_SPAWN"
                    ]
                    empire = Source.Owner
                GenerateSitRepMessage
                    message = "EFFECT_ANCIENT_TECH_RUMORS"
                    label = "EFFECT_ANCIENT_TECH_RUMORS_LABEL"
                    icon = "icons/specials_huge/ancient_ruins_excavated.png"
                    parameters = [
                        tag = "tech" data = "SHP_KRILL_SPAWN"
                    ]
            ]
Note the lack of "Activation = random probability = 0.n "

And the choice of Extinct Species is coded that way :

Code: Select all

        // Find extinct species
        EffectsGroup
            scope = Source
            activation = And [
                Random probability = 0.75
                OwnerHasTech name = "LRN_XENOARCH"
            ]
            effects = [
                If condition = Random probability = 0.33
                    effects = [ 
                        AddSpecial name = "EXTINCT_BANFORO_SPECIAL"
                        GenerateSitRepMessage
                            message = "EFFECT_ANCIENT_EXTINCT_SPECIES"
                            label = "EFFECT_ANCIENT_EXTINCT_SPECIES_LABEL"
                            icon = "icons/specials_huge/extinct_banforo.png"
                            parameters = [
                                tag = "planet" data = Source.ID
                                tag = "species" data = "SP_BANFORO"
                            ]
                            empire = Source.Owner
                         GenerateSitRepMessage
                            message = "EFFECT_ANCIENT_EXTINCT_SPECIES_RUMORS"
                            label = "EFFECT_ANCIENT_EXTINCT_SPECIES_RUMORS_LABEL"
                            icon = "icons/specials_huge/extinct_banforo.png"
                            parameters = [
                                tag = "species" data = "SP_BANFORO"
                            ]
                    ]
                else = If condition = Random probability = 0.5
                    effects = [ 
                        AddSpecial name = "EXTINCT_KILANDOW_SPECIAL"
                        GenerateSitRepMessage
                            message = "EFFECT_ANCIENT_EXTINCT_SPECIES"
                            label = "EFFECT_ANCIENT_EXTINCT_SPECIES_LABEL"
                            icon = "icons/specials_huge/extinct_kilandow.png"
                            parameters = [
                                tag = "planet" data = Source.ID
                                tag = "species" data = "SP_KILANDOW"
                            ]
                            empire = Source.Owner
                         GenerateSitRepMessage
                            message = "EFFECT_ANCIENT_EXTINCT_SPECIES_RUMORS"
                            label = "EFFECT_ANCIENT_EXTINCT_SPECIES_RUMORS_LABEL"
                            icon = "icons/specials_huge/extinct_kilandow.png"
                            parameters = [
                                tag = "species" data = "SP_KILANDOW"
                            ]
                    ]
                    else = [
                        AddSpecial name = "EXTINCT_MISIORLA_SPECIAL"
                        GenerateSitRepMessage
                            message = "EFFECT_ANCIENT_EXTINCT_SPECIES"
                            label = "EFFECT_ANCIENT_EXTINCT_SPECIES_LABEL"
                            icon = "icons/specials_huge/extinct_misiorla.png"
                            parameters = [
                                tag = "planet" data = Source.ID
                                tag = "species" data = "SP_MISIORLA"
                            ]
                            empire = Source.Owner
                        GenerateSitRepMessage
                            message = "EFFECT_ANCIENT_EXTINCT_SPECIES_RUMORS"
                            label = "EFFECT_ANCIENT_EXTINCT_SPECIES_RUMORS_LABEL"
                            icon = "icons/specials_huge/extinct_misiorla.png"
                            parameters = [
                                tag = "species" data = "SP_MISIORLA"
                            ]
                     ]
            ]
So, for Extinct Species, we have a 75% chance of getting any Extinct Species at all.
Then depending on a "dice roll", we have a one on three chance to get Banforo. Then we have a coin toss that decides whether we get Kilandow or Misioria. Since we have a coin toss on the 67% probability left, it means the three Extinct Species are equiprobable.

Also, there are no conditions for these opportunities (except of course Xenoarcheology). Which means that a player can discover many times Banforo remains, for example.


For the other goodies, the choice between them is made differently.
If I understand correctly, the reason why the "if-else" structure is not necessary there is because of the stackinggroup "ANCIENT_RUINS_TECH_UNLOCK" ?

For these goodies, we have 20 % probability to get a Dragon Tooth.
Then a 25 % probability to get a Neutronium Synthetizer.
Then a 50 % probability to get Death Rays.
Then a 100 % probability to get Multi-Spectral Shields.
Then a 100 % probability to get a Krill Spawner.

In the FOCS scripting detail it's written that "Multiple effects scripted into the same item will be evaluated in the order in which they appear. "

So, for the first Ancient Ruin excavation, there is a 20 % chance to get a Dragon Tooth, a 20 % (0,25*0,80) chance to get Neutronium Synthetizer, a 30 % (0,5*0,6) chance to get Death Rays, a 30 % chance to get MSS, and 0% chance to get Krill Spawner.

Am I correct ?
Why allow Krill Spawners only if MSS has already been discovered ?
Also, I don't want to bother calculating the matrix of probabilities for second excavations depending on what has been discovered in the first one, but it's clear that DT chance doesn't change while MSS chances rise with each discovery.
Is that intended ? Why ?

User avatar
LienRag
Cosmic Dragon
Posts: 2148
Joined: Fri May 17, 2019 5:03 pm

Re: Excruciating FOCS doubts

#81 Post by LienRag »

On an unrelated topic, why is the code for the Luxuries macro indicates "Planet = not Source" for the Stability bonus part ?

Code: Select all

SPECIAL_INFLUENCE_RESOURCE_EXPORT
'''
        // influence specials on a planet set to influence focus generate influence on that planet, regardless of species
        EffectsGroup
            scope = Source
            activation = And [
                OwnedBy affiliation = AnyEmpire
                Focus type = "FOCUS_INFLUENCE"
            ]
            effects =
                SetTargetInfluence value = Value + 3

        // stability bonus to connected planets that like this special when running capital markets
        EffectsGroup
            scope = And [
                Planet
                Not Source
                Population low = 0.001
                (SpeciesContentOpinion species = LocalCandidate.Species name = ThisSpecial > 0)
                ResourceSupplyConnected empire = Source.Owner condition = Source
                // TODO: check for other empires with border checkpoints or free trade or somesuch...
            ]
            activation = And [
                OwnedBy affiliation = AnyEmpire
                Focus type = "FOCUS_INFLUENCE"
                EmpireHasAdoptedPolicy empire = Source.Owner name = "PLC_CAPITAL_MARKETS"
            ]
            stackinggroup = "@1@_STACK"
            accountinglabel = "@1@_IMPORTS"
            effects = SetTargetHappiness value = Value + 1
'''
Also I think that I finally understand this line¹ (partially thanks to previous explanations about SQL anology) : (SpeciesContentOpinion species = LocalCandidate.Species name = ThisSpecial > 0)

But how do you expect such a syntax to be understandable by a laygamer ?



¹ I mean, I don't know what SpeciesContentOpinion is, but that is a problem of documentation, not syntax.

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

Re: Excruciating FOCS doubts

#82 Post by Oberlus »

LienRag wrote: Wed May 26, 2021 6:06 pm"Planet = not Source" for the Stability bonus part ?
It's

Code: Select all

Planet
Not Source
That mean: that is a planet, that is not source. Source already has the bonus from the luxury special in the planet.

Also I think that I finally understand this line¹ (partially thanks to previous explanations about SQL anology) : (SpeciesContentOpinion species = LocalCandidate.Species name = ThisSpecial > 0)

But how do you expect such a syntax to be understandable by a laygamer ?
Maybe they don't expect such thing.

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

Re: Excruciating FOCS doubts

#83 Post by Geoff the Medio »

Oberlus wrote: Wed May 26, 2021 6:11 pm
Also I think that I finally understand this line¹ (partially thanks to previous explanations about SQL anology) : (SpeciesContentOpinion species = LocalCandidate.Species name = ThisSpecial > 0)

But how do you expect such a syntax to be understandable by a laygamer ?
Maybe they don't expect such thing.
There are several levels of how to answer that...

1) Regardless of the syntax of how it's specified, be that FOCS or Python or C++, making complicated nested logic for how game content functions is essentially scripting or programming an algorithm. That's something some people can do fairly easily, some people can learn to do with some difficulty, and some people can't or won't do.

2) If you understand how FOCS effects and conditions are structured, the syntax of that line shouldn't be difficult to understand, and from the names of the stuff used in the script, the gameplay relevance should be reasonably clear or easy to guess for most of it.

3) There's a comment right before that in the macro that specifies what this bit of script is doing: // stability bonus to connected planets that like this special when running capital markets. Indeed, that line is checking what the opinion of a species is about the special to which this macro is added. If it's > 0, they like it. If it's < 0, they dislike it.

User avatar
LienRag
Cosmic Dragon
Posts: 2148
Joined: Fri May 17, 2019 5:03 pm

Re: Excruciating FOCS doubts

#84 Post by LienRag »

Oberlus wrote: Wed May 26, 2021 6:11 pm It's

Code: Select all

Planet
Not Source
That mean: that is a planet, that is not source. Source already has the bonus from the luxury special in the planet.
Oh, OK, makes sense, thanks.

wobbly
Cosmic Dragon
Posts: 1880
Joined: Thu Oct 10, 2013 6:48 pm

Re: Excruciating FOCS doubts

#85 Post by wobbly »

LienRag wrote: Wed May 26, 2021 6:06 pm Also I think that I finally understand this line¹ (partially thanks to previous explanations about SQL anology) : (SpeciesContentOpinion species = LocalCandidate.Species name = ThisSpecial > 0)

But how do you expect such a syntax to be understandable by a laygamer ?



¹ I mean, I don't know what SpeciesContentOpinion is, but that is a problem of documentation, not syntax.
As someone with only a little experience coding but some experience code diving and hacking, you search for it. You do a search through the code for where it is used elsewhere. You find things that are similar to what you want to do and work out how to modify it. You watch the commit log to learn how things are done. If I wanted to learn how to add a new meter such as influence/production/etc. that would be hard. However influence was recently added. The code is open source. There's a whole bunch of recent commits adding influence to the game that I can look at, follow and try and learn how a new meter is added to the game. You follow the examples of the more experienced coders working on the game. When you report a bug you watch the commit history and see the fix. You watch, you look, you learn. You modify, you test, you f' up, you correct.

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

Re: Excruciating FOCS doubts

#86 Post by Oberlus »

Is there a way in FOCS to query the total anti-planet damage of a set of ships (e.g. owned/allied warships in system)?
If not, can I expect it to be implemented before 0.5?

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

Re: Excruciating FOCS doubts

#87 Post by Geoff the Medio »

Oberlus wrote: Sat Jun 05, 2021 2:34 pmIs there a way in FOCS to query the total anti-planet damage of a set of ships (e.g. owned/allied warships in system)?
If you can script a number that calculates the total anti-planet damage of a single ship and a condition that selects the ships of interest, then yes: Use Statistic Sum as specify the single ship calculation as the value = parameter.

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

Re: Excruciating FOCS doubts

#88 Post by Ophiuchus »

Geoff the Medio wrote: Sat Jun 05, 2021 3:34 pm
Oberlus wrote: Sat Jun 05, 2021 2:34 pmIs there a way in FOCS to query the total anti-planet damage of a set of ships (e.g. owned/allied warships in system)?
If you can script a number that calculates the total anti-planet damage of a single ship and a condition that selects the ships of interest, then yes: Use Statistic Sum as specify the single ship calculation as the value = parameter.
With the master as for all cases to be correct, you need to take targeting manually into account (e.g. exclude flaks, strikers, interceptors), and do something funky for heavy bombers and the monster weapons.

You could use XXX.DamageStructurePerBattleMax valueref for getting the correct maximum damage against a ship. Still one would need to filter for only weapon/hangar parts which target planets.

Should we also provide a XXX.DamagePlanetPerBattleMax valueref or a generic one taking an object ID; e.g.

Code: Select all

DamagePerBattleMax ship = Source.ID target = LocalCandidate.ID
? Expecting it to be rarely used I would rather not add another valueref field to the ships part.

Also for your case - what damage model (especially) for heavy bombers would you want to use - is maximum battle damage the right one?
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: Excruciating FOCS doubts

#89 Post by Oberlus »

In my case, I was thinking on the Terror Suppression policy, that gives a bonus to stability from each warship in system. Since it gives all importance to #ships, 4 old frigates with 1 MD each would be producing much more stability than a huge Titan with plenty of Death Rays. Both for gameplay and for lore (think about it: "DEATH RAY", that should scare the shit out of people, much more than "mass driver"), I'd like the effect to be based on damage (or cost of the weapon parts) and not on number of ships.

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

Re: Excruciating FOCS doubts

#90 Post by Ophiuchus »

Oberlus wrote: Sun Jun 06, 2021 9:50 am In my case, I was thinking on the Terror Suppression policy, that gives a bonus to stability from each warship in system. Since it gives all importance to #ships, 4 old frigates with 1 MD each would be producing much more stability than a huge Titan with plenty of Death Rays. Both for gameplay and for lore (think about it: "DEATH RAY", that should scare the shit out of people, much more than "mass driver"), I'd like the effect to be based on damage (or cost of the weapon parts) and not on number of ships.
That would make terror suppression cheaper and cheaper as you upgrade weapon tech. Using old vessels for terror suppression sounds ok to me.
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!

Post Reply