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
LienRag
Cosmic Dragon
Posts: 2103
Joined: Fri May 17, 2019 5:03 pm

Re: Excruciating FOCS doubts

#61 Post by LienRag »

My apology, I used an old version of the Sly focs file rather than the new one, the right case is GasGiant.
Now everything seems to parse.

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

Re: Excruciating FOCS doubts

#62 Post by LienRag »

Not directly related to the above test game : I noticed that there is a "tag = monster" but apparently monsters do not have it ?

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

Re: Excruciating FOCS doubts

#63 Post by Geoff the Medio »

LienRag wrote: Fri Apr 30, 2021 6:13 pmI don't understand why it removed the "exit" button though ?
Probably it's there, but the code that decides how big to make the menu is buggy and it's hidden off the bottom of the containing window.

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

Re: Excruciating FOCS doubts

#64 Post by LienRag »

Is there a way to test for a ship being inside a field ?

The way it works now, the code that affects ships is in the field FOCS file, and tests for ships.
Is it possible to do it the other way around, put some code on a ship (or ship part) FOCS file, code which will activate only if the ship is in a particular field ?

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

Re: Excruciating FOCS doubts

#65 Post by Geoff the Medio »

LienRag wrote: Fri May 14, 2021 11:06 amIs there a way to test for a ship being inside a field ?
The field containment tests are implemented using WithinDistance, like:

Code: Select all

scope = And [
    Not Field
    WithinDistance distance = Source.Size * 0.9 condition = Source
]
A very similar script could be added to a ship part or hull, probably in the activation condition of an effectsgroup, with Source then referring to the ship, and the condition parameter modified to select a field of a particular type.

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

Re: Excruciating FOCS doubts

#66 Post by LienRag »

Thanks.
Geoff the Medio wrote: Tue May 18, 2021 9:25 am A very similar script could be added to a ship part or hull, probably in the activation condition of an effectsgroup, with Source then referring to the ship, and the condition parameter modified to select a field of a particular type.
Though I wouldn't know how to do that part, actually. I looked through the FOCS details page and it doesn't seem to have a variable "field" in it ?

There is "ObjectType" and I guess I can test "ObjectType = field" but then ? Will "Name=FLD_ION_STORM" do the trick ?
Also I more or less understand how to use Source (even if it's sometime tricky) and usually Target too (even if it's sometime even more tricky) but this paragraph always had me at a loss :

Code: Select all

Here there are two sets of objects being matched: 1) The objects actually being matched for the scope. These are objects within distance 5 of an object matched by the subcondition. 2) The objects matched by the subcondition, which are used to evaluate the outer condition. These are planets that are owned by the same empire that owns the object matched in the outer condition, and that have less than half their own target construction.

RootCandidate refers to the object being matched in the outer-most condition - WithinDistance in this case. This gives a way to refer to the object actually being matched by a big multi-part condition from one of the inner condition definitions, where the object being matched by a subcondition is likely not the same object being matched by the outer condition.

LocalCandidate refers to the object being matched in whatever condition it is directly in - the Construction meter condition in this case. This gives a way to refer to the object being matched by the current condition, regardless of what other conditions are matching outside or inside the current condition.

The RootCandidate and LocalCandidate may be used with the same types of variable references as for Source and Target.

For the EffectGroups in Techs, the Location specification, BuildTime value and BuildCost value for content such as a BuildingType, ShipHull or ShipPart, the context Source is the EmpireSource for the empire currently under consideration; this is its Capital planet if it has one, otherwise some other object owned by the empire. The Target in this context is the potential production location (planet) for which the Location, BuildTime or BuildCost is being evaluated.

For the Location specification for Specials, Source and Target are not set, but the LocalCandidate and RootCandidate references may be used. 
I guess the field size would be adressed by RootCandidate.Size ?
Or am I getting this completely wrong ?

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

Re: Excruciating FOCS doubts

#67 Post by Ophiuchus »

LienRag wrote: Tue May 18, 2021 9:49 pm There is "ObjectType" and I guess I can test "ObjectType = field" but then ? Will "Name=FLD_ION_STORM" do the trick ?
...
I guess the field size would be adressed by RootCandidate.Size ?
RootCandidate if you are inside the scope condition. Target if you are in the effects.

Size valueref should return you the radius for a field.

so a guess

Code: Select all

scope = And [ ObjectType = "Field" Name = "FLD_ION_STORM"  WithinDistance distance = RootCandidate.Size * 0.9 condition = RootCandidate ]
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: 13586
Joined: Wed Oct 08, 2003 1:33 am
Location: Munich

Re: Excruciating FOCS doubts

#68 Post by Geoff the Medio »

Ophiuchus wrote: Wed May 19, 2021 1:25 pm

Code: Select all

scope = And [ ObjectType = "Field" Name = "FLD_ION_STORM"  WithinDistance distance = RootCandidate.Size * 0.9 condition = RootCandidate ]
Nether ObjectType = "Field" nor Name = "FLD_ION_STORM" look like valid conditions to me... Just Field should select fields. For the name, I think that won't work as conceived due to localization of the object name, rather than it still having the stringtable key as a name. Rather using (LocalCandidate.FieldType = "") might work.

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

Re: Excruciating FOCS doubts

#69 Post by LienRag »

Ophiuchus wrote: Wed May 19, 2021 1:25 pm RootCandidate if you are inside the scope condition. Target if you are in the effects.

Size valueref should return you the radius for a field.

so a guess

Code: Select all

scope = And [ ObjectType = "Field" Name = "FLD_ION_STORM"  WithinDistance distance = RootCandidate.Size * 0.9 condition = RootCandidate ]
Wow, thanks for the attempt but I really don't understand at all neither your explanation (a bit too laconic for my limited and confused comprehension of this part of FOCS) nor your code (why condition=RootCandidate ? This makes absolutely no sense to me)...

That's clearly one part of FOCS that I won't miss if we switch entirely to Python !

Geoff the Medio wrote: Wed May 19, 2021 2:17 pm Nether ObjectType = "Field" nor Name = "FLD_ION_STORM" look like valid conditions to me... Just Field should select fields. For the name, I think that won't work as conceived due to localization of the object name, rather than it still having the stringtable key as a name. Rather using (LocalCandidate.FieldType = "") might work.
At least I get the first part, thanks.
Why LocalCandidate to address FieldType though ? I get more confused...

(ever watched Kaamelott's episode about Percival and the cardinal points ? that's exactly how I feel...)

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

Re: Excruciating FOCS doubts

#70 Post by Geoff the Medio »

LienRag wrote: Wed May 19, 2021 4:40 pmThat's clearly one part of FOCS that I won't miss if we switch entirely to Python !
At least a major part of your not understanding how the scripts works seems to be conceptual, regarding how conditions are set up. The switch to Python parsing won't change how that works. For example:
Why LocalCandidate to address FieldType though ? I get more confused...
You want have a condition as part of an effectsgroup that's attached to a ship (from a part or a hull or a species). If you want to check if the ship is within a field, you need to have a condition that matches fields of a particular type within a certain distance of the ship. Within the top level of that condition, the field being matched is both the RootCandidate and LocalCandidate objects.

Or if you're asking why it's (LocalCandidate.FieldType == "") and not just Field type = "FLD_WHATEVER", that's because there is no condition implemented specifically to match field types. The general ( == ) condition still works for any pair (or triplet) of values you want to compare, though, so can be used instead.

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

Re: Excruciating FOCS doubts

#71 Post by LienRag »

Geoff the Medio wrote: Wed May 19, 2021 6:15 pm At least a major part of your not understanding how the scripts works seems to be conceptual, regarding how conditions are set up. The switch to Python parsing won't change how that works.
Well, yes and no. Yes it is conceptual, and yes the switch to python will help conceptualization or not change my trouble conceptualizing it, depending on how it's done I guess.
But with Python, at least how I understand it, I can name the variable I'm testing and then refer to it clearly after that, not having to juggle with Root and Local and Presidential candidates that depends on when they're called and from what.
I mean,

Code: Select all

NearestField =FindNearestFieldFromTheCurrentShip(ThisShip)
If NearestField.Name == IonStorm
    DistanceFromCenter = distance(NearestField.Center,ThisShip)
    if DistanceFromCenter <= NearestField.Size
        ShipIsInField = True
        ShipIsInIonStorm = True
is maybe bad style of code and non-optimal but at least I can understand it and it should work...
(and if it doesn't I probably can understand why)

Geoff the Medio wrote: Wed May 19, 2021 6:15 pm
Why LocalCandidate to address FieldType though ? I get more confused...
You want have a condition as part of an effectsgroup that's attached to a ship (from a part or a hull or a species). If you want to check if the ship is within a field, you need to have a condition that matches fields of a particular type within a certain distance of the ship. Within the top level of that condition, the field being matched is both the RootCandidate and LocalCandidate objects.
I understand clearly your first phrase, and I believe that I understand your second as well (and what you say seems to indeed describe what I want and be coherent with what I understand of the code).
Your last phrase is still Klingon (or is it Ewok ? I can't even tell) to me, and I've read more than five times the paragraph about RootCandidate and LocalCandidate in the documentation...

Geoff the Medio wrote: Wed May 19, 2021 6:15 pm Or if you're asking why it's (LocalCandidate.FieldType == "") and not just Field type = "FLD_WHATEVER", that's because there is no condition implemented specifically to match field types. The general ( == ) condition still works for any pair (or triplet) of values you want to compare, though, so can be used instead.
Again, I understand your first phrase, and I get some intuitive grasp of your second, but it's still a bit confusing.
How do I know that the object Field (which, BTW, doesn't seem to be in the documentation) has a variable FieldType ? And which values this variable can take ?
Also, how do you compare triplets of values ?

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

Re: Excruciating FOCS doubts

#72 Post by Geoff the Medio »

LienRag wrote: Wed May 19, 2021 10:13 pmBut with Python, at least how I understand it, I can name the variable I'm testing and then refer to it clearly after that, not having to juggle with Root and Local and Presidential candidates that depends on when they're called and from what.
I mean,

Code: Select all

NearestField =FindNearestFieldFromTheCurrentShip(ThisShip)
If NearestField.Name == IonStorm
    DistanceFromCenter = distance(NearestField.Center,ThisShip)
    if DistanceFromCenter <= NearestField.Size
        ShipIsInField = True
        ShipIsInIonStorm = True
Python is just used as a parser, not as a scripting language. You still can't write scripts with custom named variables and expect them to be executed as part of or instead of a FOCS condition. Rather, what you can do in Python is define data structures that replicate what could be scripted in FOCS. See: See: https://github.com/freeorion/freeorion/ ... focs.py#L6
Geoff the Medio wrote: Wed May 19, 2021 6:15 pm
Why LocalCandidate to address FieldType though ? I get more confused...
You want have a condition as part of an effectsgroup that's attached to a ship (from a part or a hull or a species). If you want to check if the ship is within a field, you need to have a condition that matches fields of a particular type within a certain distance of the ship. Within the top level of that condition, the field being matched is both the RootCandidate and LocalCandidate objects.
I understand clearly your first phrase, and I believe that I understand your second as well (and what you say seems to indeed describe what I want and be coherent with what I understand of the code).
Your last phrase is still Klingon (or is it Ewok ? I can't even tell) to me, and I've read more than five times the paragraph about RootCandidate and LocalCandidate in the documentation...
So... yeah... a conceptual problem. A FOCS condition is a way to select objects in the universe, such as ships or planets or systems or fields. You can combine conditions with And/Or/Not and some conditions have subconditions that specify how the top level condition will work. A typial use for a condition is selecting what objects an effect should act on each turn, such as "all the populated planets with human species populating them that are owned by the empire that has researched this tech should get +5 to target research". If the condition for an effect is complicated and contains another condition, the inner condion could match objects that the outer condition doesn't. For example, you might want to match all ships within 5 distances of terran planets. The outer condition doesn't match planets, but the inner condition does. 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.
Geoff the Medio wrote: Wed May 19, 2021 6:15 pm Or if you're asking why it's (LocalCandidate.FieldType == "") and not just Field type = "FLD_WHATEVER", that's because there is no condition implemented specifically to match field types. The general ( == ) condition still works for any pair (or triplet) of values you want to compare, though, so can be used instead.
Again, I understand your first phrase, and I get some intuitive grasp of your second, but it's still a bit confusing.
How do I know that the object Field (which, BTW, doesn't seem to be in the documentation) has a variable FieldType ? And which values this variable can take ?
You'd probably have to read the parser C++ code and/or the ValueRef C++ code to know all of what properties of objects can be referred to. There's no good well-maintained documentation unfortunately. Or you can ask if there's a way to test for something.
Also, how do you compare triplets of values ?
Similarly to how you can compare two values... like this: https://github.com/freeorion/freeorion/ ... cs.txt#L24

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

Re: Excruciating FOCS doubts

#73 Post by Ophiuchus »

Geoff the Medio wrote: Wed May 19, 2021 10:42 pm
LienRag wrote: Wed May 19, 2021 10:13 pmBut with Python, at least how I understand it, I can name the variable I'm testing and then refer to it clearly after that, not having to juggle with Root and Local and Presidential candidates that depends on when they're called and from what.
I mean,

Code: Select all

NearestField =FindNearestFieldFromTheCurrentShip(ThisShip)
If NearestField.Name == IonStorm
    DistanceFromCenter = distance(NearestField.Center,ThisShip)
    if DistanceFromCenter <= NearestField.Size
        ShipIsInField = True
        ShipIsInIonStorm = True
Python is just used as a parser, not as a scripting language. You still can't write scripts with custom named variables and expect them to be executed as part of or instead of a FOCS condition. Rather, what you can do in Python is define data structures that replicate what could be scripted in FOCS.
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.
LienRag wrote: Wed May 19, 2021 10:13 pmBut with Python, at least how I understand it, I can name the variable I'm testing and then refer to it clearly after that, not having to juggle with Root and Local and Presidential candidates that depends on when they're called
How do I know that the object Field (which, BTW, doesn't seem to be in the documentation) has a variable FieldType ?
UniverseObjects you filter for in conditions are: Building, Field, Fighter, Fleet, Planet, Ship, System. properties etc do not directly interact with the cpp UniverseObjects. What you call a variable is actually a valueref (universe/ValueRefs.cpp); some of those access meters, some access member variables via functions; e.g. from ValueRefs.cpp:

Code: Select all

    } else if (property_name == "FieldType") {
        if (auto field = std::dynamic_pointer_cast<const Field>(object))
            return field->FieldTypeName();
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: 2103
Joined: Fri May 17, 2019 5:03 pm

Re: Excruciating FOCS doubts

#74 Post by LienRag »

Geoff the Medio wrote: Wed May 19, 2021 10:42 pm Python is just used as a parser, not as a scripting language. You still can't write scripts with custom named variables and expect them to be executed as part of or instead of a FOCS condition. Rather, what you can do in Python is define data structures that replicate what could be scripted in FOCS. See: See: https://github.com/freeorion/freeorion/ ... focs.py#L6
:cry:



Geoff the Medio wrote: Wed May 19, 2021 10:42 pm So... yeah... a conceptual problem. A FOCS condition is a way to select objects in the universe, such as ships or planets or systems or fields. You can combine conditions with And/Or/Not and some conditions have subconditions that specify how the top level condition will work. A typial use for a condition is selecting what objects an effect should act on each turn, such as "all the populated planets with human species populating them that are owned by the empire that has researched this tech should get +5 to target research".
We might be slowly getting somewhere there...
This part I understand clearly, to the point of having been able to use it in some of my FOCS scripts.
Actually, it's obvious to anyone with an even very basic grasp of programming (though it's still a good reminder of the basics before going to more complex matters).

Geoff the Medio wrote: Wed May 19, 2021 10:42 pm If the condition for an effect is complicated and contains another condition, the inner condition could match objects that the outer condition doesn't. For example, you might want to match all ships within 5 distances of terran planets.
Yep, this also is very clear (and not what confused me before either).
I'm a bit less confident in my ability to actually do it in FOCS , though.

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.

I thank you for your patience, but this part would probably need more explaining, with examples and probably a diagram (of a few ones).
Don't feel pressured to do so if you don't have time now though, what I want to script is not necessarily that important (the main addition I wanted to do to the game through FOCS for now is already done and works, it just needs multiplayer testing).

Though, once you have time, a clear explanation may be useful to other people than me, so it may be worth the effort.

I'm not entirely stupid, I understand the basics of what you say, but it's still not easy to see how it fares in all situations.
For example, why do you consider the ships to be the outer condition ?
Also, I see four conditions (ships, distance of five, planets, terran) so I'm not confident how you intuit that you can organize them in two conditions.
And why is the RootCandidate in your example one of the ships instead of all of them ? I feel very stupid asking this question but I am genuinely unable to answer it clearly myself.

The part about LocalCandidate I didn't understand at all.

Geoff the Medio wrote: Wed May 19, 2021 10:42 pm
LienRag wrote: Wed May 19, 2021 10:13 pmAlso, how do you compare triplets of values ?
Similarly to how you can compare two values... like this: https://github.com/freeorion/freeorion/ ... cs.txt#L24
Again, this makes no sense to me.
I mean, it works so in a way it makes sense somehow, but not in a way that I can understand.

First, you're not using the comparison == but the assignment = (if I'm not mistaken).
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.


¹ Note that the "something = value + n" syntax is quite intuitive to me, for a reason I don't know since actually it's not intuitive at all, so I guess this may confuse other people.

² That I also find quite intuitive though it isn't at all actually nor very logic

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

Re: Excruciating FOCS doubts

#75 Post by LienRag »

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.
Now you're talking wookie...
Remember that I have a very basic knowledge of Python, but that I know exactly nothing about C++.
I do have an extremely limited knowledge of C, but I insist on the "extremely limited" part (mostly, that is uses malloc and needs to free memory once a variable has run its course; actually I'm a bit exagerating, I know the existence of Data Structures thanks to the - very good - online course for beginners CS50).

Not that I want to put pressure on you individually, but if the FreeOrion team wants to have user-generated content, it certainly shouldn't need mastery of C++.

If Python is to be used only as a parser and not as a scripting language (which means that parts of actually scripting user-generated content will still be as arcane as they are now) a serious effort of documentation will be needed.
I may do a part myself once I understand it, but I don't know when this goal will be attained...


Ophiuchus wrote: Thu May 20, 2021 12:09 pm
LienRag wrote: Wed May 19, 2021 10:13 pm How do I know that the object Field (which, BTW, doesn't seem to be in the documentation) has a variable FieldType ?
UniverseObjects you filter for in conditions are: Building, Field, Fighter, Fleet, Planet, Ship, System. properties etc do not directly interact with the cpp UniverseObjects. What you call a variable is actually a valueref (universe/ValueRefs.cpp); some of those access meters, some access member variables via functions; e.g. from ValueRefs.cpp:

Code: Select all

    } else if (property_name == "FieldType") {
        if (auto field = std::dynamic_pointer_cast<const Field>(object))
            return field->FieldTypeName();
Again, wookie.
UniverseObjects you filter for in conditions are: Building, Field, Fighter, Fleet, Planet, Ship, System.
This I may have understood, if it means that a FOCS condition may test for building, field, fighter, fleet, planet, ship and/or system.
And even then, and even though I was able to filter for planets in some code (mostly by copy-pasting existing code) I don't really understand how to do it.

Post Reply