Fractal Softworks Forum

Please login or register.

Login with username, password and session length
Advanced search  

News:

Starsector 0.97a is out! (02/02/24); New blog post: Simulator Enhancements (03/13/24)

Author Topic: Script Help: Advanced Scripting with Rules.csv  (Read 2294 times)

Morrokain

  • Admiral
  • *****
  • Posts: 2143
  • Megalith Dreadnought - Archean Order
    • View Profile
Script Help: Advanced Scripting with Rules.csv
« on: August 24, 2017, 02:11:38 PM »

Ok, so this script is pretty big so no worries if noone feels like sifting through it, but the gist of it is that the conditions in rules.csv require it to pass or fail. Sometimes, randomly, it seems to return neither true nor false and causes the rules to fail to find a match in the conditions. Not the worst since just rehitting the dialogue option runs the script again where is passes or fails like 90% or more of the time. But weird and annoying lol.

Short end of the story: Where in the script would it "never" return true or false???

Proof of error:


Spoiler
673161 [Thread-4] INFO  com.fs.starfarer.campaign.rules.Rules  - Checking rule: CommodityRequestedBefore
673161 [Thread-4] INFO  com.fs.starfarer.campaign.rules.Rules  - Conditions: $option == Aid_request $entity.Requested_Aid score:1600 CommodityRequestCalc
673161 [Thread-4] INFO  com.fs.starfarer.campaign.rules.Rules  - Failed condition: CommodityRequestCalc
673161 [Thread-4] INFO  com.fs.starfarer.campaign.rules.Rules  - Checking rule: CommodityRequestedBeforeExalted
673161 [Thread-4] INFO  com.fs.starfarer.campaign.rules.Rules  - Conditions: $option == Aid_request $entity.Requested_Aid score:80 RepIsAtWorst $faction.id COOPERATIVE score:1500
673162 [Thread-4] INFO  com.fs.starfarer.campaign.rules.Rules  - Failed condition: RepIsAtWorst $faction.id COOPERATIVE score:1500
673162 [Thread-4] INFO  com.fs.starfarer.campaign.rules.Rules  - Checking rule: CommodityRequestedBeforeandAngry
673162 [Thread-4] INFO  com.fs.starfarer.campaign.rules.Rules  - Conditions: $option == Aid_request $entity.Requested_Aid score:1600 !CommodityRequestCalc
673162 [Thread-4] INFO  com.fs.starfarer.campaign.rules.Rules  - Failed condition: !CommodityRequestCalc

[close]


and the script...  :P

Spoiler

package archeus.rulecmd;

import java.util.List;
import java.util.Map;

import com.fs.starfarer.api.Global;
import com.fs.starfarer.api.characters.PersonAPI;
import com.fs.starfarer.api.characters.PersonalityAPI;
import com.fs.starfarer.api.characters.RelationshipAPI;
import com.fs.starfarer.api.campaign.InteractionDialogAPI;
import com.fs.starfarer.api.campaign.CampaignFleetAPI;
import com.fs.starfarer.api.campaign.rules.MemKeys;
import com.fs.starfarer.api.campaign.rules.MemoryAPI;
import com.fs.starfarer.api.campaign.FactionAPI;
import com.fs.starfarer.api.campaign.RepLevel;
import com.fs.starfarer.api.util.Misc.Token;
import com.fs.starfarer.api.impl.campaign.rulecmd.BaseCommandPlugin;
/**
 *   Commodity Request Calculation
 *    by Morrokain
 */
public class CommodityRequestCalc extends BaseCommandPlugin {
    @Override
   public boolean execute(String ruleId, InteractionDialogAPI dialog, List<Token> params, Map<String, MemoryAPI> memoryMap) {
      if (dialog == null) return false;

        int BaseFireChance = 40;          // base chance of success before other factors calculated in

        CampaignFleetAPI playerFleet;
        CampaignFleetAPI otherFleet;

        FactionAPI faction;
        FactionAPI playerFaction;

        playerFleet = Global.getSector().getPlayerFleet();
        otherFleet = (CampaignFleetAPI) (dialog.getInteractionTarget());
        faction = otherFleet.getFaction();
        playerFaction = playerFleet.getFaction();

        PersonAPI commander = otherFleet.getCommander(); // get commander of fleet

        RepLevel level = faction.getRelationshipLevel(playerFaction);
                                                         // get rep level relative to player

        if (level.isAtWorst(RepLevel.INHOSPITABLE));     // no chance once hostile of course.
        {
            int fireChance = BaseFireChance + (int) (Math.random() * 101);
                                                         // generates random number and adds to fireChance

            int fleetStrength = (int) otherFleet.getFleetPoints();
            int playerStrength = (int) Global.getSector().getPlayerFleet().getFleetPoints();
            double relativeStrength = 0;                 // gets relative size of fleet to player

            int repWeight = 1;                              // will impact the effect of fleet strength calc below


            if (level.isAtWorst(RepLevel.COOPERATIVE)) {    // rep impacts chance of success and weight of strength calc
                fireChance += 100;
                repWeight = 8;
            }

            if (level.isAtWorst(RepLevel.FRIENDLY)){
                fireChance += 30;
                repWeight = 6;
            }

            if (level.isAtWorst(RepLevel.WELCOMING)){
                fireChance += 30;
                repWeight = 4;
            }

            if (level.isAtWorst(RepLevel.FAVORABLE)){
                fireChance += 15;
                repWeight = 3;
            }

            if (level.isAtBest(RepLevel.NEUTRAL)){
                fireChance += 5;
                repWeight = 2;
            }

            if (level.isAtBest(RepLevel.SUSPICIOUS))
                fireChance -= 20;

            if (level.isAtBest(RepLevel.INHOSPITABLE))
                fireChance -= 40;

            if (faction.getId().equals("scicorps")) {       // faction also has an effect
                fireChance += 30;                      // different factions have different base percentages
                repWeight += 2;                        // to aid player
            }

            if (faction.getId().equals("hegemony"))  {      // fleet strength has a slightly lower impact on success rate
                fireChance += 15;                      // for some factions like hegemony and independent due to good nature
                repWeight += 1;
            }

            if (faction.getId().equals("independent")) {
                fireChance += 5;
                repWeight += 1;
            }

            if (faction.getId().equals("luddic_church")) {   // similar to hegemony in generosity.
                fireChance += 15;
                repWeight += 1;
            }

            if (faction.getId().equals("luddic_path"))
            {
                float credits = Global.getSector().getPlayerFleet().getCargo().getCredits().get();
                float aidCost = (int) Global.getSector().getPlayerFleet().getFleetPoints() * 500;

                memoryMap.get(MemKeys.LOCAL).set("$AidRequest_estCost", aidCost, 1);

                boolean canAfford;

                if (credits >= aidCost)
                {
                    canAfford = true;
                    fireChance += 10;                   // if player can afford the estimated costs of resupply,
                }                                       // much higher chance of success for greedier factions
                else
                {
                    canAfford = false;
                    fireChance -= 25;
                }
                memoryMap.get(MemKeys.LOCAL).set("$CanAfford_estCost", canAfford, 1);
            }


            if (faction.getId().equals("archean_order"))
            {
                float credits = Global.getSector().getPlayerFleet().getCargo().getCredits().get();
                float aidCost = (int) Global.getSector().getPlayerFleet().getFleetPoints() * 500;

                memoryMap.get(MemKeys.LOCAL).set("$AidRequest_estCost", aidCost, 1);

                boolean canAfford;

                if (credits >= aidCost)
                {
                    canAfford = true;
                    fireChance += 20;                   // if player can afford the estimated costs of resupply,
                }                                       // much higher chance of success for greedier factions
                else
                {
                    canAfford = false;
                    fireChance -= 15;
                }
                memoryMap.get(MemKeys.LOCAL).set("$CanAfford_estCost", canAfford, 1);
            }


            if (faction.getId().equals("adamantine_consortium")) // in general consortium doesn't give much aid
            {
                float credits = Global.getSector().getPlayerFleet().getCargo().getCredits().get();
                float aidCost = (int) Global.getSector().getPlayerFleet().getFleetPoints() * 500;

                memoryMap.get(MemKeys.LOCAL).set("$AidRequest_estCost", aidCost, 1);

                boolean canAfford;

                if (credits >= aidCost)
                {
                    canAfford = true;
                    fireChance -= 5;                   // if player can afford the estimated costs of resupply,
                }                                       // much higher chance of success for greedier factions
                else
                {
                    canAfford = false;
                    fireChance -= 35;
                }
                memoryMap.get(MemKeys.LOCAL).set("$CanAfford_estCost", canAfford, 1);
            }

            if (faction.getId().equals("trader_guilds"))
            {
                float credits = Global.getSector().getPlayerFleet().getCargo().getCredits().get();
                float aidCost = (int) Global.getSector().getPlayerFleet().getFleetPoints() * 400;

                memoryMap.get(MemKeys.LOCAL).set("$AidRequest_estCost", aidCost, 1);

                boolean canAfford;

                if (credits >= aidCost)
                {
                    canAfford = true;
                    fireChance += 10;
                }
                else
                {
                    canAfford = false;
                    fireChance -= 15;
                }
                memoryMap.get(MemKeys.LOCAL).set("$CanAfford_estCost", canAfford, 1);
            }

            if (faction.getId().equals("pirates"))
            {
                float credits = Global.getSector().getPlayerFleet().getCargo().getCredits().get();
                float aidCost = (int) Global.getSector().getPlayerFleet().getFleetPoints() * 500;

                memoryMap.get(MemKeys.LOCAL).set("$AidRequest_estCost", aidCost, 1);

                boolean canAfford;

                if (credits >= aidCost)
                {
                    canAfford = true;
                    fireChance += 10;                   // if player can afford the estimated costs of resupply,
                }                                       // much higher chance of success for greedier factions
                else
                {
                    canAfford = false;
                    fireChance -= 25;
                }
                memoryMap.get(MemKeys.LOCAL).set("$CanAfford_estCost", canAfford, 1);
            }

            PersonalityAPI personality = commander.getPersonalityAPI();

            if (personality.toString().equals("reckless")) {
                fireChance -= 15;
                repWeight -= 2;
            }

            if (personality.toString().equals("aggressive")) {
                fireChance -= 10;
                repWeight -= 1;
            }

            if (personality.toString().equals("cautious")) {
                fireChance -= 10;
                repWeight += 1;
            }


            if (personality.toString().equals("timid")) {
                fireChance += 20;
                repWeight += 2;
            }

            RelationshipAPI relationship = commander.getRelToPlayer();
            // finally, commander's personality and opinion of player matters

            if (relationship.isAtWorst(RepLevel.FRIENDLY)) {
                fireChance += 45;
                repWeight += 2;
            }

            if (relationship.isAtWorst(RepLevel.WELCOMING)) {
                fireChance += 25;
                repWeight += 1;
            }

            if (relationship.isAtWorst(RepLevel.FAVORABLE)) {
                fireChance += 15;
                repWeight += 1;
            }

            if (relationship.isAtBest(RepLevel.SUSPICIOUS))
                fireChance -= (int) (fireChance * 0.2);

            if (relationship.isAtBest(RepLevel.INHOSPITABLE))
                fireChance -= (int) (fireChance * 0.5);

            if (relationship.isAtBest(RepLevel.HOSTILE))
            {
                if (!level.isAtWorst(RepLevel.COOPERATIVE))
                {
                    fireChance = 0;                         // unless highest rep, will fail if commander is hostile
                }                                           // even then, reduces by 50% like inhospitable rep
            }

            if (repWeight <= 0)                             // safeguard for strength calc
                repWeight = 1;

            //** Note on Fleet Strength calculations: with neutral or lower rep, fleet strength is one of the primary
            // factors and those players without at least close to equal strength will be hard pressed to find any aid from
            // most factions. **


            if (fleetStrength > playerStrength) {       // less likely as other fleet gets stronger
                relativeStrength = (((playerStrength * 100) / fleetStrength)) * 0.01; // but higher rep reduces impact
                fireChance -= (int) ((fireChance - (fireChance * relativeStrength)) / repWeight); // of this calculation
            }

            if (fleetStrength <= playerStrength) {      // more likely as the other fleet gets weaker
                relativeStrength = (((fleetStrength * 100) / playerStrength)) * 0.01;
                fireChance += (int) ((fireChance * (1 - relativeStrength)));
            }                                         // modifies final chance to fire by percentage of strength difference

            memoryMap.get(MemKeys.LOCAL).set("$AidRequest_fireChance", fireChance, 1);
            memoryMap.get(MemKeys.LOCAL).set("$FleetStrength_repWeight", repWeight, 1);

            if (fireChance >= 100)
                return true;                    // request granted if fireChance over 100 (successful roll)
        }
      return false;
   }
}
[close]

And some screens of the script (and some others) for funsies  ;D

Spoiler


















[close]

Logged

Alex

  • Administrator
  • Admiral
  • *****
  • Posts: 23986
    • View Profile
Re: Script Help: Advanced Scripting with Rules.csv
« Reply #1 on: August 24, 2017, 02:19:33 PM »

fireChance has a random component :)

If you want the check to only be run once, put the result of it in memory in CommodityRequestCalc, and then only call that once, and not as a condition, but rather in the body of another rule before this stuff fires.

(This is looking very cool, btw!)
Logged

Morrokain

  • Admiral
  • *****
  • Posts: 2143
  • Megalith Dreadnought - Archean Order
    • View Profile
Re: Script Help: Advanced Scripting with Rules.csv
« Reply #2 on: August 24, 2017, 03:12:00 PM »

fireChance has a random component :)

If you want the check to only be run once, put the result of it in memory in CommodityRequestCalc, and then only call that once, and not as a condition, but rather in the body of another rule before this stuff fires.


Ok I think I gotcha, so just like the cost of the aid request, the calc script would put a boolean into memory that would be set as true if fireChance is over 100 and false otherwise. Then the calc script could be run, say at the initial dialogue (in the scripts column, not the conditions) that would set the variable (and give you the description flavor), then the condition in the following line of rules simply check for the memory variable.

That sum up what you mean?

edit:
Also, why does the random number added to fireChance make the rule sometimes not return anything? I would have thought simply having two paths based on one variable where an end equals a true return and the other end equals a false return would be enough. (This is more for my own curiosity and for me to better understand the engine/java)

Nvm I get it now! Just clicked!  ::)

In case people are following this, so its running the script each rule entry, (duh, cant believe I didn't see that flaw).

So actually, though it would appear that the script would return "one" true or false, its actually running the calc script each time a new rule is checked, so it can, sometimes, return the script as false in the rule that checks for true, but still have the condition that checks for false ALSO return a true, by pure chance, when the script is run AGAIN, causing that rule to fail too, so rules can't find a match. Thats why it only "fails" to return a true or false rarely, because multiple chance calculations have to align... haha  :D

Putting the script in a precursor rule makes it only run once, therefore, the true or false return stays "constant" across all the followup rule checks in rules.csv

(This is looking very cool, btw!)

Wow thanks that's high praise coming from you!

Have more in the development list that I'm excited about too! How big can rules be, btw? The commodity request rules configurations has.. about 100 entries so far, or with dialogue options around 300 different potential outputs and 100 condition configurations. It doesn't seem to slow anything down that I can tell, but I'm curious as to its limitations.

I'm thinking once I start scripting in story stuff, that will begin to get a lot higher. School is starting next week though so time is going to get more limited.

I also want to say I love how rules.csv works! I was intimidated at first, but it really makes things a lot easier once you get it down!
« Last Edit: August 24, 2017, 04:19:16 PM by Morrokain »
Logged

Alex

  • Administrator
  • Admiral
  • *****
  • Posts: 23986
    • View Profile
Re: Script Help: Advanced Scripting with Rules.csv
« Reply #3 on: August 24, 2017, 04:12:10 PM »

That sum up what you mean?

Yep!

Also, why does the random number added to fireChance make the rule sometimes not return anything? I would have thought simply having two paths based on one variable where an end equals a true return and the other end equals a false return would be enough. (This is more for my own curiosity and for me to better understand the engine/java)

What happens is it returns true for one rule and false for another, because of the random component. It's not that it returns nothing - that's not possible - but what it returns is inconsistent from call to call.

Have more in the development list that I'm excited about too! How big can rules be, btw? The commodity request rules configurations has.. about 100 entries so far, or with dialogue options around 300 different potential outputs and 100 condition configurations. It doesn't seem to slow anything down that I can tell, but I'm curious as to its limitations.

I'm thinking once I start scripting in story stuff, that will begin to get a lot higher. School is starting next week though so time is going to get more limited.

I'm not sure how big rules can get, but the system is meant to handle a lot of them and tries to be efficient about it.

I also want to say I love how rules.csv works! I was intimidated at first, but it really makes things a lot easier once you get it down!

Cool, I'm glad it's clicking for you! Yeah, I'm excited to see someone using it :)
Logged

Morrokain

  • Admiral
  • *****
  • Posts: 2143
  • Megalith Dreadnought - Archean Order
    • View Profile
Re: Script Help: Advanced Scripting with Rules.csv
« Reply #4 on: August 24, 2017, 04:22:56 PM »


Also, why does the random number added to fireChance make the rule sometimes not return anything? I would have thought simply having two paths based on one variable where an end equals a true return and the other end equals a false return would be enough. (This is more for my own curiosity and for me to better understand the engine/java)

What happens is it returns true for one rule and false for another, because of the random component. It's not that it returns nothing - that's not possible - but what it returns is inconsistent from call to call.


Yeah lol just picked up on what you meant, one of those tricky areas I really did not anticipate at first. Makes total sense once you think about it, though. Why would all rules "check" at once??  :P

Logged