Changing how engines work

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

Moderators: Oberlus, Committer

Post Reply
Message
Author
xlightwavex
Space Kraken
Posts: 111
Joined: Mon Nov 16, 2015 5:57 am

Changing how engines work

#1 Post by xlightwavex »

Overview.

Im attempting to alter the way engines work in relation to hulls. While there are different possibility's.
First i need a working example as a demo test to ensure any of them are even possible.

Here's the parts that i know ill need so far.

Edit:
this is now basically working however there is a bit more to it you need to also add the part 'SH_ENGINE_1' to the items.inf file. I changed many of the names to reflect how its currently being named which i didn't get at first so SE_ is being used to denote the parts (Ship Engine) then SHP as the others are to denote what the Tech Itself (if any) Unlocks.

However the balance premise of this idea as of now is...
You get a engine of the type of hull you unlock when you get the hull. That engine has a power rating that is reduced by the hulls tech or size i.e. its speed is given a negative value (sort of like a drag mass, or lower tech penalty).

The engine itself is given a power rating that is a found value by the following instructions...
  • #1) You take the current speed of any hull as it is now, to be the starting value for the engine which corresponds to the same hull.
    #2) You then assign a hull a negative value, giving the absolute of that, as a addition to the corresponding engine. You do this in turn for each hull that will unlock a engine.
    #3) The result is the engine and hull have different speeds separately, however when combined they are exactly the same as before you started.


The idea is to add a increase of tactical flexibility. This idea allows you to swap engines between hulls to either improve old ones extending there life (maybe you just like the way the older ships look and don't want to toss them yet). Or decrease the cost of newer ones when in a fully defensive situation so they are less capable of offense at a reduced cost. This can also work for offense as backup support or with a mix of both. You can optionally simply not add a star drive and they are then in system ships with a free extra internal slot. So it also adds to the strategic aspect. One additional benefit is that hulls themselves can be balanced in another way besides just hp slots or firepower but by the speed drag penalty on the hull itself.

Code: Select all

//______________________________________________
// attempting to change the way engines behave
//______________________________________________
 
  //______________________________________
 //  scripting shiphulls basic.focs
//

Hull
    name = "SH_STANDARD"
    description = "SH_STANDARD_DESC"
    speed = -30 // was 60
    fuel = 3
    stealth = 5
    structure = 15
    slots = [
        Slot type = External position = (0.50, 0.35)
        Slot type = External position = (0.50, 0.60)
        Slot type = External position = (0.80, 0.45)
        Slot type = Internal position = (0.30, 0.40)
        Slot type = Internal position = (0.20, 0.40) //added
    ]
    buildCost = 30 * [[FLEET_UPKEEP_MULTIPLICATOR]]
    buildTime = 2
    location = Contains And [
        Building name = "BLD_SHIPYARD_BASE"
        OwnedBy empire = Source.Owner
    ]
    effectsgroups = [
        [[REGULAR_HULL_DETECTION]]
        [[SCAVANGE_FUEL_UNOWNED]]
        [[UNOWNED_GOOD_VISION]]
        [[UNOWNED_MOVE]]
    ]
    icon = "icons/ship_hulls/basic-large-hull_small.png"
    graphic = "hulls_design/basic-large-hull.png"

#include "ship_hulls.macros"

#include "/scripting/common/upkeep.macros"


  //______________________________________
 // scripting ship_designs sd_large_mark_3
//

ShipDesign
    name = "SD_LARGE_MARK_3"
    description = "SD_LARGE_MARK3_DESC"
    hull = "SH_STANDARD"
    parts = [
        "SR_WEAPON_2_1"
        "SR_WEAPON_2_1"
        "AR_STD_PLATE"
        "FU_BASIC_TANK"
		"SH_ENGINE_1" // added
    ]
    model = "mark1"

  //______________________________________
 // default scripting ship_parts
//

// there will basically be 5 of these

Part
    name = "SH_ENGINE_1"
    description = "SH_ENGINE_1_DESC"
    class = Speed
    capacity = 90
    mountableSlotTypes = Internal
    buildcost = 10 * [[FLEET_UPKEEP_MULTIPLICATOR]]
    buildtime = 3
    location = OwnedBy empire = Source.Owner
	effectsgroups = [[SPEED_STACKING]] // << added
    icon = "icons/ship_parts/engine-1.png"

#include "/scripting/common/upkeep.macros"

	
  //______________________________________
 // en.txt
// 
SH_ENGINE_1
Standard Engine

SH_ENGINE_1_DESC
'''A standard star drive engien with a 90 BHP ( [[SPEED_INTERFERENCE]] Bazillion Horse Power :) rating. This value is decrease by a ships hull, typically larger or lower tech hulls, reduce the star lane speed a engine can theoretically achieve.'''

  //______________________________________
 // scripting ship_parts stacking.macros
//
BEST_SPEED_EFFECT
'''
max(max(max(max(
    min(1, PartsInShipDesign Name = "SH_ENGINE_1" design = Source.DesignID)
    * PartCapacity name = "SH_ENGINE_1",
    min(1, PartsInShipDesign Name = "SH_ENGINE_2" design = Source.DesignID)
    * PartCapacity name = "SH_ENGINE_2"),
    min(1, PartsInShipDesign Name = "SH_ENGINE_3" design = Source.DesignID)
    * PartCapacity name = "SH_ENGINE_3"),
    min(1, PartsInShipDesign Name = "SH_ENGINE_4" design = Source.DesignID)
    * PartCapacity name = "SH_ENGINE_4"),
    min(1, PartsInShipDesign Name = "SH_ENGINE_5" design = Source.DesignID)
    * PartCapacity name = "SH_ENGINE_5" 
    )
'''


SUM_SPEED_CAPACITY
'''
((PartCapacity name = "SH_ENGINE_1")* (PartsInShipDesign Name = "SH_ENGINE_1" design = Source.DesignID)
+(PartCapacity name = "SH_ENGINE_2")* (PartsInShipDesign Name = "SH_ENGINE_2" design = Source.DesignID)
+(PartCapacity name = "SH_ENGINE_3")* (PartsInShipDesign Name = "SH_ENGINE_3" design = Source.DesignID)
+(PartCapacity name = "SH_ENGINE_4")* (PartsInShipDesign Name = "SH_ENGINE_4" design = Source.DesignID)
+(PartCapacity name = "SH_ENGINE_5")* (PartsInShipDesign Name = "SH_ENGINE_5" design = Source.DesignID))
'''


SPEED_STACKING
'''
EffectsGroup    // Make sure to add new engine parts to the macros SUM_SPEED_CAPACITY and BEST_SPEED_EFFECT
    scope = Source
    activation = DesignHasPartClass Low=2 High=999 Class=Speed
    //  im still iffy on this. ?
    stackinggroup = "SPEED_PART_STACK"
    // from the responses this is essentially en.txt link listing that also outputs the effects value when you hover over it.
    accountinglabel = "SPEED_INTERFERENCE"
    // now this is correct the wiki is out of date on this.
    effects = SetSpeed value = Value - [[SUM_SPEED_CAPACITY]] + [[BEST_SPEED_EFFECT]] 
'''

#include "stacking.macros"

#include "/scripting/common/upkeep.macros"
this now basically is working.
Last edited by xlightwavex on Sat Sep 17, 2016 12:34 am, edited 21 times in total.

dbenage-cx
Programmer
Posts: 389
Joined: Sun Feb 14, 2016 12:08 am

Re: Changing how engines work

#2 Post by dbenage-cx »

Completely glossed over accountinglabel, will get it added.

Basically it allows you to document an effect or effectgroup to the user, when it would otherwise be included in the total.
So if you add +1 speed with the effect, you would set:

Code: Select all

accountinglabel = "NEW_ITEM_EFFECT"
Order is important for placement, it goes between stackinggroup and priority:
EffectsGroup order (something else to add):
  • description (optional)
  • scope
  • activation (optional)
  • stackinggroup (optional)
  • accountinglabel (optional)
  • priority (optional)
  • effects
Then in en.txt:

Code: Select all

NEW_ITEM_EFFECT
Bottle rocket booster
When you hover over the speed value for any ship with this part, this label will appear along with the effect value.
The name of this label is not critical afaik, it could be BOB_TREES and should still work.

It can also be added to just a single effect within an EffectGroup, if that becomes a need:

Code: Select all

EffectsGroup
    scope = Source
    effects = [
        SetMaxSomething1 value = Value + 2 accountinglabel = "ENGINE_TECH"
        SetMaxSomething2 value = Value * 0.8 accountinglabel = "ENGINE_SIZE"
    ]

dbenage-cx
Programmer
Posts: 389
Joined: Sun Feb 14, 2016 12:08 am

Re: Changing how engines work

#3 Post by dbenage-cx »

Code: Select all

Part
    name = "SH_ENGINE_1"
    description = "SH_ENGINE_1_DESC"
    class = Speed
    capacity = 90
    mountableSlotTypes = Internal
    buildcost = 10 * [[FLEET_UPKEEP_MULTIPLICATOR]]
    buildtime = 3
    location = OwnedBy empire = Source.Owner
   effectsgroups = [[SPEED_STACKING]] // << added
    icon = "icons/ship_parts/engine-1.png"
If you have problems, you might want to start with just one part and without the macro, to help with troubleshooting.
Then as you add parts, move to a simpler macro to keep the effectsgroups consistent, and expand the macro as needed.

xlightwavex
Space Kraken
Posts: 111
Joined: Mon Nov 16, 2015 5:57 am

Re: Changing how engines work

#4 Post by xlightwavex »

I have made amendments to the original post to reflect your advice.

Code: Select all

accountinglabel = "SPEED_INTERFERENCE"

Code: Select all

SH_ENGINE_1
Standard Engine

SH_ENGINE_1_DESC
'''A standard star drive engien with a 90 BHP ( [[SPEED_INTERFERENCE]] Bazillion Horse Power :) rating. This value is decrease by a ships hull, typically larger or lower tech hulls, reduce the star lane speed a engine can theoretically achieve.'''

SPEED_INTERFERENCE
power rateing 
Is that correct or the proper way to place it ?


stackinggroup im a bit unclear on as well how does that work ? By the description it sounds like it's more a non-stacking group.

Code: Select all

stackinggroup = "SPEED_PART_STACK"

Also is the effect parameter value that identifies a ship speed as the modifying target (SetStarlaneSpeed) correct in the context of that script macro.

Code: Select all

effects = SetStarlaneSpeed value = Value - [[SUM_SPEED_CAPACITY]] + [[BEST_SPEED_EFFECT]]
If you have problems, you might want to start with just one part and without the macro, to help with troubleshooting.
Then as you add parts, move to a simpler macro to keep the effectsgroups consistent, and expand the macro as needed.
The macros in this case are simply copied from scripting>ship parts>stacking.macros and then altered.

No point in doing a test run until i understand the function linking and usage of these keywords... reading still.

dbenage-cx
Programmer
Posts: 389
Joined: Sun Feb 14, 2016 12:08 am

Re: Changing how engines work

#5 Post by dbenage-cx »

Is that correct or the proper way to place it ?
Not seeing a problem off-hand. The block quotes (''') are usually only needed when there is a line break.

stackinggroup:
only applies once, if another EffectsGroup comes up with that same stackinggroup name, it does not occur.
This "other" EffectsGroup could be the same one, for a second object.
First come, first serve so you need to be mindful on the order or specify it with priority.

SetStarlaneSpeed was removed in commit 8858abb2, might use SetSpeed if you need an effect.

If you prefer, I can start linking to cpp portions (alot of it is through boost::spirit v2).

What I meat about not using the macro (and if you want to sort the concept out as-is first, that is fine):

Code: Select all

Part
    name = "SH_ENGINE_1"
    description = "SH_ENGINE_1_DESC"
    class = Speed
    capacity = 90
    NoDefaultCapacityEffect
    mountableSlotTypes = Internal
    buildcost = 10 * [[FLEET_UPKEEP_MULTIPLICATOR]]
    buildtime = 3
    location = OwnedBy empire = Source.Owner
    effectsgroups = [
        EffectsGroup
            scope = Source
            stackinggroup = "ENGINE_STACK_GROUP"
            priority = 30
            effects = SetSpeed value = PartCapacity name = "SH_ENGINE_1"
    ]
    icon = "icons/ship_parts/engine-1.png"
Should give you a starting base that is clearer to read/understand, and be more efficient.
This follows the example set in PR #935.

When adding another part, you can then change the effectsgroup to a macro:

Code: Select all

EG_ENGINE_CAPACITY
'''EffectsGroup
    scope = Source
    stackinggroup = "ENGINE_STACK_GROUP"
    priority = @1@
    effects = SetSpeed value = PartCapacity name = @2@
'''

Code: Select all

effectsgroup = [[EG_ENGINE_CAPACITY(30, "SH_ENGINE_1")]]
Note for priority, zero occurs first, so a higher number is a lower/later priority.
These need to be an int, so you can not add to a number here.
The macro is ok as that is basically a copy/paste operation before the actual parse.
Changing to either:

Code: Select all

priority = 30 - 1
or

Code: Select all

effectsgroup = [[EG_ENGINE_CAPACITY(30 - 1, "SH_ENGINE_1")]]
Would result in an error.

dbenage-cx
Programmer
Posts: 389
Joined: Sun Feb 14, 2016 12:08 am

Re: Changing how engines work

#6 Post by dbenage-cx »

Just to expand on stackinggroup.

Code: Select all

Part
    name = "PART_A"
    ...
    effectsgroups = [
        EffectsGroup
            scope = And [
                Ship
                InSystem id = Source.SystemID
            ]
            stackinggroup = "PART_A_STACK"
            effects = SetMaxDamage value = Value * 0.75
    ]
PartA, decreases the damage of all ships in the same system by 25%.

Without a stackinggroup, if you had a ship with two of these parts (or two ships with this part), the effect would apply twice.

If we create a PartB with the same stackinggroup, which increases the damage by 25%,
the ships will either be reduced by 25% or increased by 25%,
depending on which effectsgroup is processed first.

xlightwavex
Space Kraken
Posts: 111
Joined: Mon Nov 16, 2015 5:57 am

Re: Changing how engines work

#7 Post by xlightwavex »

dbenage-cx wrote: If you prefer, I can start linking to cpp portions (alot of it is through boost::spirit v2).
Ya maybe its a good idea to look to the relevant parser code though im pretty terrible with c c++ now last time i looked at c++ my eyes started spinning. I imagine that will help somewhat though, it seems the wiki isn't fully up to date. Took me a minute to realize what the debug output was complaining about.

Well i think i may have to call it quits for now im tired. Ill read that over later on when i start up again, ill try to see if i cant get my head around it, looks pretty complicated.
SetStarlaneSpeed was removed in commit 8858abb2, might use SetSpeed if you need an effect.
I wish i had checked back here much earlier, i was carried away typing. The wiki needs updated on that one lol. Changed that and my test worked in fact i think that was the only error i had.

Though i dunno if it fully works or not i just know it finally ran lol.

...I made alterations to...

Basic.focs in ship_hulls
en.txt in stringtables
stacking.macros in ship_parts
SD_MARK focs most of them in ship designs.
items.inf in starting unlocks

...created...

SHP_StarDrives.focs in tech>ships
SE_StarDrive.focs in ship_parts

Image

so the hull is -30 the first engine is + 80 while the anti stacking effect works it still adds the cost if you put a extra engine on it.

Image

xlightwavex
Space Kraken
Posts: 111
Joined: Mon Nov 16, 2015 5:57 am

Re: Changing how engines work

#8 Post by xlightwavex »

dbenage-cx wrote: stackinggroup:
only applies once, if another EffectsGroup comes up with that same stackinggroup name, it does not occur.
This "other" EffectsGroup could be the same one, for a second object.
First come, first serve.


So then in the case of a engines speed if some other thing were to use Engine_Speed_Stack before the current macro it would then nullify the above macro. Unless...
You need to be mindful on the order or specify it with priority.
If a macro came up with priority 2 and had wanted to assigned the value of 10 to SetSpeed. Then my current SPEED_STACKING macro with a priority of 1 which wished to assigned the value of SetSpeed to 20. Then the final result would be 20, but the prior wouldn't be overwritten it wouldn't execute at all. Is that correct ?

What I meant about not using the macro.

Code: Select all

Part
    name = "SH_ENGINE_1"
    description = "SH_ENGINE_1_DESC"
    class = Speed
    capacity = 90
    NoDefaultCapacityEffect
    mountableSlotTypes = Internal
    buildcost = 10 * [[FLEET_UPKEEP_MULTIPLICATOR]]
    buildtime = 3
    location = OwnedBy empire = Source.Owner
    effectsgroups = [
        EffectsGroup
            scope = Source
            stackinggroup = "ENGINE_STACK_GROUP"
            priority = 30
            effects = SetSpeed value = PartCapacity name = "SH_ENGINE_1"
    ]
    icon = "icons/ship_parts/engine-1.png"
This follows the example set in PR #935
So above basically you get the PartCapacity value of this part and set it to the SetSpeed value;
When adding another part, you can then change the effectsgroup to a macro:

Code: Select all

EG_ENGINE_CAPACITY
'''EffectsGroup
    scope = Source
    stackinggroup = "ENGINE_STACK_GROUP"
    priority = @1@
    effects = SetSpeed value = PartCapacity name = @2@
'''
What function does the @1@ @2@ denote? Is that syntax for input in order for parenthesis in the macro ? e.g. ( argument#1, argument#2) is that correct ?

Code: Select all

effectsgroup = [[EG_ENGINE_CAPACITY(30, "SH_ENGINE_1")]]
So the above basically sets the speed for the partname by its own capacity if it has a lowest priority in the stacking group. Is that correct ?
Note for priority, zero occurs first, so a higher number is a lower/later priority.
These need to be an int, so you can not add to a number here.
This is a constant value for the parameter.
The macro is ok as that is basically a copy/paste operation before the actual parse.
Changing to either:

Code: Select all

priority = 30 - 1
or

Code: Select all

effectsgroup = [[EG_ENGINE_CAPACITY(30 - 1, "SH_ENGINE_1")]]
Would result in an error.
Got it i think, woosh that's a lot to remember.

Is it possible to pass the part capacity in some way to the macro using a macro ?

Code: Select all

effectsgroup = [[EG_ENGINE_CAPACITY(INVERSE_CAPACITY_OF_ITEM(SH_ENGINE_1), "SH_ENGINE_1")]]
Something like the above were the macro can get a value of a part with a operation then return a value to be used in place as a constant ? Not saying i would do that if i could though but something like priority = (Int.Max -1) - capacity; might be useful

dbenage-cx
Programmer
Posts: 389
Joined: Sun Feb 14, 2016 12:08 am

Re: Changing how engines work

#9 Post by dbenage-cx »

Note: I am far from the most proficient or experienced person around here, so please take my understanding of the code basis with that in mind.
That said, if someone notices some omission or error in anything here, please point it out if you find the time to do so.
xlightwavex wrote:Ya maybe its a good idea to look to the relevant parser code though im pretty terrible with c c++ now last time i looked at c++ my eyes started spinning. I imagine that will help somewhat though, it seems the wiki isn't fully up to date. Took me a minute to realize what the debug output was complaining about.
I believe spirit (and related) is seen as a somewhat advanced topic, though once you are familiar with the syntax it should not be hard to distinguish between optional and required attributes.
To start you down the rabbit hole, Buildings -> Buildings Parser -> Parse(via ParseImpl.h).
In the last link, note that includes are copied in, and then macros, before the parsing work starts.

Macros are basically a user tool for consistent text, ease of use, and readability.
These replace all instances of [[XYZ]] with the text defined in XYZ (similar to the "search and replace all" feature in a text editor).

Being alpha, the wiki is out of date a day after it is updated ;) Hopefully the documentation can move to doxygen/sphinx later, but it is not worth the effort if it will change soon (re: proposal to move FOCS to Python).

If you are not doing so, you might want to start the game from the command line when troubleshooting scripts. That debug output will show in the console window, saving a need to refresh the log file (and saving time if it is parsed when the game first starts).
Then the final result would be 20, but the prior wouldn't be overwritten it wouldn't execute at all. Is that correct ?
The end result would be 20, yes. I can't say for certain there is overhead for the other effectsgroup, if there is it should be minimal.

So above basically you get the PartCapacity value of this part and set it to the SetSpeed value
The part has an attribute "capacity", with a value of 90.
By itself, this does nothing for a ship hull it is attached to.
By default, an effect is created giving the ship a speed of 90.
Declaring NoDefaultCapacityEffect prevents that default effect from being created.
This allows us to setup our own effectsgroup to apply the capacity, when we want additional constraints (priority and stackinggroup in this case).
What function does the @1@ @2@ denote? Is that syntax for input in order for parenthesis in the macro ? e.g. ( argument#1, argument#2) is that correct ?
Correct :)
So the above basically sets the speed for the partname by its own capacity if it has a lowest priority in the stacking group. Is that correct ?
This replace the text

Code: Select all

[[EG_ENGINE_CAPACITY(30, "SH_ENGINE_1")]]
with

Code: Select all

EffectsGroup
    scope = Source
    stackinggroup = "ENGINE_STACK_GROUP"
    priority = 30
    effects = SetSpeed value = PartCapacity name = "SH_ENGINE_1"
Is it possible to pass the part capacity in some way to the macro using a macro ?

Code: Select all

effectsgroup = [[EG_ENGINE_CAPACITY(INVERSE_CAPACITY_OF_ITEM(SH_ENGINE_1), "SH_ENGINE_1")]]
Something like the above were the macro can get a value of a part with a operation then return a value to be used in place as a constant ? Not saying i would do that if i could though but something like priority = (Int.Max -1) - capacity; might be useful
Commonly used priority values are defined in default/scripting/common/priorities.macros.
Macros are not functions however, given the macro:

Code: Select all

ABC
1 + 1 + 3
The macro returns "1 + 1 + 3", not "5".

Code: Select all

priority = [[ABC]]
priority = 1 + 1 + 3
Are the same, minus some small overhead for the macro replacement. Both will result in an error.

You can pass a macro through a macro if you need

Code: Select all

[[MACRO_A1(MACRO_B1,MACRO_B2(14))]]

MACRO_A1
[[@1@]] * [[@2@]]

MACRO_B1
5

MACRO_B2
(@1@ / 2)
Would resolve to: 5 * (14 / 2)

xlightwavex
Space Kraken
Posts: 111
Joined: Mon Nov 16, 2015 5:57 am

Re: Changing how engines work

#10 Post by xlightwavex »

Thank you for the detailed reply's. This is excellent and clear.

I will take a little time to digest this and try to put it into practice a bit.

Post Reply