SmartStasis -- a complex script for a simple CCS

lostcalpolydude

Developer
Staff member
Two masks, not two shields.

Also, not using Throw Shield for stasis already dictates strategy some if Entangling Noodles is cast without using Throw Shield.
 

Bale

Minion
I've decided that this very important line in SmartStasis has a problem:

Code:
   while ((to_profit(plink) > to_float(vars["BatMan_profitforstasis"]) || is_our_huckleberry())
          && round < maxround - 1 - kill_rounds(get_action("attack")) && die_rounds() > kill_rounds(get_action("attack")))  {

This is the code that decides if the monster will be Stasised. The problem here is that sometimes you can be facing a monster which will take many rounds to kill you, but you cannot hit with attack. Obviously you'll kill the monster with another source of damage. In those instances you shouldn't be bound by the fact that kill_rounds(get_action("attack")) is greater than 30. If it is larger than 30, you should assume that whatever means the character is using to kill the monster shouldn't take more than 5 rounds.

Mostly this situation will only happen when the characters highest stat is Myst.

This came to my attention when to_profit(plink) was 73.0165 (due to a hobo monkey) and I could kill the monster in 3 rounds by funkslinging Miniborg Destroy-O-Bots. (My combat script was choosing the destroy-o-bots as suitable for a monster that would kill me in 22 rounds.) I feel in this instance SS should have tried to drag out combat for that much profit.

Code:
> zlib verbosity = 9

Previous value of verbosity: 3
Changed to 9.
Validating adventure sequence...
Requests complete.

Visit to Manor0: Haunted Wine Cellar (automatic) in progress...

[2103] Haunted Wine Cellar (Northeast)
Encounter: skeletal sommelier
Strategy: C:\Documents and Settings\David\My Documents\My Dropbox\KolMafia\ccs\default.ccs [default]
Round 0: bale wins initiative!
Round 1: Chu produces a tubular red firecracker labeled M-34, lights the long fuse, and tosses it behind your opponent.
1 MP costs 3.8461537μ.
1 HP costs 0.2945253μ.
dusty bottle of Marsala (20.0 @ +191.0): 247μ * 58.2% = 143.754
dusty bottle of Merlot (20.0 @ +191.0): 243μ * 58.2% = 141.42601
dusty bottle of Muscat (20.0 @ +191.0): 256μ * 58.2% = 148.992
dusty bottle of Pinot Noir (20.0 @ +191.0): 283μ * 58.2% = 164.706
dusty bottle of Port (20.0 @ +191.0): 297μ * 58.2% = 172.854
dusty bottle of Zinfandel (20.0 @ +191.0): 261μ * 58.2% = 151.90201
wine-soaked bone chips (0.01 @ +191.0): 500μ * 0.029099999% = 0.14549999
Value of stat gain: 416.88μ
Factoring in Scarysauce: (6) damage, retal
Profit per round: ActionProfitDamageOtherbase; Hobo Monkey (75μ)75μ--
Parsed round number: 1
Building options...
Options built! (60 actions)
Stasis action chosen: use 1316
SmartStasis profit: 73.0165
dusty bottle of Marsala (20.0 @ +191.0): 247μ * 58.2% = 143.754
dusty bottle of Merlot (20.0 @ +191.0): 243μ * 58.2% = 141.42601
dusty bottle of Muscat (20.0 @ +191.0): 256μ * 58.2% = 148.992
dusty bottle of Pinot Noir (20.0 @ +191.0): 283μ * 58.2% = 164.706
dusty bottle of Port (20.0 @ +191.0): 297μ * 58.2% = 172.854
dusty bottle of Zinfandel (20.0 @ +191.0): 261μ * 58.2% = 151.90201
wine-soaked bone chips (0.01 @ +191.0): 500μ * 0.029099999% = 0.14549999
Value of stat gain: 416.88μ
Monster: Skeletal Sommelier, ATT: 178, DEF: 152, HP: 172, Value: 1694.15
You will die in 22 rounds.
Your attack will kill the monster in 35 rounds.
Building custom actions...
Custom actions built! (0 actions)
Stasis action chosen: use 1316
Stasis loop complete.
SmartStasis complete.
DestroyAllMonsters: Miniborg Destroy-O-Bot,Miniborg Destroy-O-Bot... killrounds: 3, dierounds: 22
Executing macro: scrollwhendone; sub batround; if haseffect 8 || haseffect 264 || haseffect 282 || haseffect 283 || haseffect 284; abort "BatBrain abort: poisoned"; endif; endsub; sub batsub1; use 3114,3114; call batround; endsub; call batsub1; repeat hascombatitem 3114 && (!times 21); if hpbelow 27; abort "BatBrain abort: Danger, Will Robinson"; endif; 
Round 1: bale executes a macro!
Round 1: bale uses the Miniborg Destroy-O-Bot and uses the Miniborg Destroy-O-Bot!
Round 2: skeletal sommelier takes 43 damage.
Round 2: skeletal sommelier drops 3 attack power.
Round 2: skeletal sommelier drops 5 defense.
Round 2: skeletal sommelier takes 43 damage.
Round 2: skeletal sommelier drops 4 attack power.
Round 2: skeletal sommelier drops 3 defense.
Round 2: skeletal sommelier takes 1 damage.
Round 2: skeletal sommelier takes 1 damage.
Round 2: skeletal sommelier takes 5 damage.
You lose 13 hit points
Round 2: bale uses the Miniborg Destroy-O-Bot and uses the Miniborg Destroy-O-Bot!
Round 3: skeletal sommelier takes 32 damage.
Round 3: skeletal sommelier drops 4 attack power.
Round 3: skeletal sommelier drops 4 defense.
Round 3: skeletal sommelier takes 37 damage.
Round 3: skeletal sommelier drops 4 attack power.
Round 3: skeletal sommelier drops 5 defense.
Round 3: skeletal sommelier takes 1 damage.
Round 3: skeletal sommelier takes 1 damage.
Round 3: skeletal sommelier takes 5 damage.
You lose 11 hit points
Round 3: bale uses the Miniborg Destroy-O-Bot and uses the Miniborg Destroy-O-Bot!
Round 4: skeletal sommelier takes 43 damage.
Round 4: skeletal sommelier drops 3 attack power.
Round 4: skeletal sommelier drops 5 defense.
Round 4: Chu climbs up and sits on your shoulder, and hands you some Meat. Huh, where did he find that?
You gain 58 Meat.
Round 4: skeletal sommelier takes 51 damage.
Round 4: bale wins the fight!
After Battle: Chu sets off a lovely little cluster rocket, and smiles broadly as it explodes.
Your familiar gains a pound: Chu, the 2 lb. Hobo Monkey
After Battle: Chu sits on your fallen opponent's body, blows a smoke ring, and winks at you.
You gain 304 Meat
You acquire an item: dusty bottle of Muscat
You acquire an item: wine-soaked bone chips
You gain 10 Strengthliness
You gain 27 Enchantedness
You gain 14 Chutzpah
Parsed round number: 2
Look! You found 1 dusty bottle of Muscat (256μ)!
Look! You found 1 wine-soaked bone chips (500μ)!
Building options...
Options built! (60 actions)

Requests complete.
 

roippi

Developer
Having issues trying to figure out why SS is not deciding to go into a stasis loop.

Code:
[78]Dark Elbow of the Woods
Encounter: L imp
Round 0: roippi wins initiative!
1 MP costs 8.0μ.
1 HP costs 5.714286μ.
Imp Ale (30.0 @ +50.0): 25μ * 45.0% = 11.25
cast (30.0 @ +50.0): 32μ * 45.0% = 14.4
flaming crutch (30.0 @ +50.0): 65μ * 45.0% = 29.25
Value of stat gain: 226.88μ
Profit per round: ActionProfitDamageOtherbase; Stocking Mimic (5.03μ)18.25μ1.24 (-4.07 μ/dmg)Att: -0.38 (-0.0 DPR) Def: -0.38 HP: 1.65 MP: 1.65
Parsed round number: 1
Building options...
Evaluating '1.0*(12+min(0.15*30.0,20)+min(10.0,40)+0.0)'...
Options built! (15 actions)
Imp Ale (30.0 @ +50.0): 25μ * 45.0% = 11.25
cast (30.0 @ +50.0): 32μ * 45.0% = 14.4
flaming crutch (30.0 @ +50.0): 65μ * 45.0% = 29.25
Value of stat gain: 226.88μ
Monster: L Imp, ATT: 54, DEF: 49, HP: 54, Value: 311.78
You will die in 113 rounds.
Your attack will kill the monster in 3 rounds.
Building custom actions...
Custom actions built! (0 actions)
Executing macro: scrollwhendone; sub batround; if haseffect 8 || haseffect 264 || haseffect 282 || haseffect 283 || haseffect 284; abort "BatBrain abort: poisoned"; endif; endsub; pickpocket; call batround; if hpbelow 9; abort "BatBrain abort: Danger, Will Robinson"; endif; 
Round 1: roippi executes a macro!
Round 1: roippi tries to steal an item!
Round 2: Love Glove mimics a red-and-white striped candy cane, and canes him for 14 damage.
Round 2: l imp takes 14 damage.
Parsed round number: 2
Building options...
Evaluating '1.0*(12+min(0.15*30.0,20)+min(10.0,40)+0.0)'...
Options built! (15 actions)
Stasis action chosen: skill 3004
This monster is not your huckleberry.
Stasis loop complete.
SmartStasis complete.

zlib BatMan_profitforstasis is set to 10.0. It's a little hard to pick out in the above, but I believe batbrain is calculating profit at 18.25.
 
Last edited:

Theraze

Active member
Looks like it choose and rejected (for some reason) Entangling Noodles as your stasis option. Any reason why it might have aborted on choosing the noodles?
 

roippi

Developer
Hrm. Can't think of any reason. My CCS is just smartstasis followed by spamattack, and I definitely do have noodles.

You're right though, in combats where it picks suckerpunch for my stasis action, it works fine.
 

Theraze

Active member
Possibly because noodles has a 'cost' of 24 meat (3 mp at 8 meat each) which is less than your profit of 18.25 meat...

Suckerpunch would have a cost of 0 meat, unless it thinks you're going to get hurt...
 

roippi

Developer
Well, I'm at safe moxie, but it's possible that noodles is chosen since I'd take a good amount of damage on a crit.
 

Theraze

Active member
Only thing I can think of... :( With a moderately sized stocking mimic and another stasis action, it should calculate out at least 2-3 rounds of stasis with noodles, making it a good value. But by itself, it doesn't make sense with your current stats. Well, not directly... if you wanted to 'break' the detection, you could do something like
Code:
   while ((to_profit(plink) > to_float(vars["BatMan_profitforstasis"]) || plink.id == to_int($skill[entangling noodles]) || is_our_huckleberry())

That should force it to, anytime noodles comes up as the best stasis choice, say... yes! That IS a stasis I'd like you to do! :) The problem here is that if you change your familiar to something without any benefit, it'll still want to stasis if it thinks noodles is your best option. That being said, noodles are cheap. :)
 

roippi

Developer
Yeah, I generally don't pull my mimic out until the friar's woods, so it's 11 pounds there (hence the lowish profit of 18 meat). Still, let me see if I understand what's going on here:

BB: In order to pick a stasis action, batbrain sorts all the options by profit.
BB: In this case, 0-cost skills have a slightly negative profit, since you can get hit on crits.
BB: Noodles has a 24 meat cost, but a less negative (i.e. higher) profit than 0-cost options, so it is ranked as the most profitable option.
SS: SmartStasis looks at the cost of noodles (24) and the profit of stasis (18.25) and decides it doesn't want to stasis.

I'm hazy on that last point, because I'm not positive that is what's happening. Note how lazy I am being and not looking at the code to figure out my own answers. Still, it seems like undesirable behavior, since this is clearly a profitable situation to stasis in.

Anyway, I think this issue will go away later in the run when the mimic is fatter (and HP is valued less). Thanks for the kludge Theraze, I'll totally use that :)
 

zarqon

Well-known member
That 18.25 number is your static "base round" profit, including your familiar and gear you're wearing. It does not include the monster's actions or your actions. Adding the monster's attack to that (even if it could only hit you on crits) would decrease that "base" profit. You are evidently right on the cusp of the point where a round of monster damage just outweighs the cost of Noodling.

However, SS should probably ignore multi-round stunners when selecting a stasis action. That will probably resolve your problem.
 

chinesedude4

New member
Confused

Herroooooo,

Unknown variable 'waved' (SmartStasis.ash, line 369)
Consult script 'SmartStasis.ash' not found.
You're on your own, partner.

The CLI spatted out that at me. Spatted. I changed something in BatBrain from demon of new wave to the Demon of New Wave. Something like that. Then SmartStatis had this error. And I don't know how to work forums.
 

roippi

Developer
Herroooooo,

Unknown variable 'waved' (SmartStasis.ash, line 369)
Consult script 'SmartStasis.ash' not found.
You're on your own, partner.

The CLI spatted out that at me. Spatted. I changed something in BatBrain from demon of new wave to the Demon of New Wave. Something like that. Then SmartStatis had this error. And I don't know how to work forums.

sounds like you did a find-and-replace where you shouldn't have. Or somehow removed the quotes from that line. Try re-downloading SS.
 

Aankhen

Member
I found myself wanting to repeatedly putty the same monster independently of olfacting it, so I added an ftf_putty option. Here’s a diff for anyone who’s interested in the same functionality:
Code:
--- SmartStasis.ash.3.6	Sun Jul 24 17:45:54 2011
+++ SmartStasis.ash	Sun Jul 24 17:43:21 2011
@@ -76,7 +76,15 @@
    if (item_drops(m) contains to_item(excise(get_property("autoOlfact"),"item ",""))) should_olfact = true;
    if (item_drops(m) contains to_item(excise(get_property("autoPutty"),"item ",""))) should_putty = true;
    if (should_putty && should_olfact) return;
-  // second, set puttifaction for bounty monsters
+  // second, handle ftf_putty
+   string [int] monsters = split_string(vars["ftf_putty"], "\\s*,\\s*");
+   foreach idx, name in monsters {
+     if (to_monster(name) == m) {
+       should_putty = true;
+       return;
+     }
+   }
+  // third, set puttifaction for bounty monsters
    item ihunt = to_item(to_int(get_property("currentBountyItem")));
    if (ihunt != $item[none]) {                       // TODO: use bounty proxy records when possible
       record {
@@ -429,6 +437,7 @@
 setvar("ftf_olfact","blooper, dairy goat, shaky clown, zombie waltzers, goth giant, knott yeti, hellion, violent fungus","list of monster");
 setvar("ftf_grin","procrastination giant","list of monster");
 setvar("ftf_yellow","knob goblin harem girl","list of monster");
+setvar("ftf_putty","");
 check_version("SmartStasis","SS","3.6",1715);
 
 void main(int initround, monster foe, string page) {
 

fronobulax

Developer
Staff member
AFAIK latest versions of everything. NPZR so there is a reason to stasis. After several rounds SS switches from a spectre scepter to a toy soldier and then goes into a sequence of "KoLmafia thinks it is round X but KoL thinks it is round Y" where X increments by one and has been as high as 247 before I realized something was wrong. When I abort I see the looking for a bottle of tequila message. Temporary solution is to closet the soldier ;-) Thanks.
 

zarqon

Well-known member
@chinesedude: You are on step 3 of 3: update SS.

@Aankhen: Another method, perhaps easier, would be to add "set autoPutty = monster <monstername>" to your mood. If you like, you could get fancy using ASH and only adjust the setting if you have available putties remaining.

@frono: Ha, you've successfully found another thing BatBrain doesn't know. I'll add in the check for a bottle of tequila.
 
Smart stasis is stasising an oddly long time on the battlefield. I'm using a stocking mimic (100% run) and when I fought a War Frat Kegrider it kept waving fat stacks of cash at it until turn 27 before attacking. It shouldn't be waiting for the mimic to drop more meat, that stops at turn 10 right? And my HP and MP were both maxed for many turns prior to 27 so it shouldn't have been waiting for it to heal/restore mp. Any clue what gives?
 

Winterbay

Active member
Set zlib's verbosity to 9 to get the macro output by the script and then we can use that to see what was happening. A bit hard before that I think.
 
Set zlib's verbosity to 9 to get the macro output by the script and then we can use that to see what was happening. A bit hard before that I think.

Running r9697 here's what looks to be a 30 round fight against a War Frat 151st Infantry Man . . .

Code:
Visit to IsleWar: Battlefield (Hippy Uniform) in progress...

[2133] Battlefield (Hippy Uniform)
Encounter: War Frat 151st Infantryman
Strategy: C:\Users\Martin\Desktop\Mafia\ccs\default.ccs [default]
Round 0: redwulf25 wins initiative!
1 MP costs 4.0μ.
1 HP costs 0.2814424μ.
beer bomb (5.0 @ +57.0): 150μ * 7.85% = 11.775
beer helmet (10.0 @ +57.0): 544μ * 15.7% = 85.408
bejeweled pledge pin (10.0 @ +57.0): 560μ * 15.7% = 87.92
bottle opener belt buckle (12.0 @ +57.0): 574μ * 18.84% = 108.1416
distressed denim pants (9.0 @ +57.0): 1065μ * 14.13% = 150.4845
keg shield (5.0 @ +57.0): 577μ * 7.85% = 45.2945
perforated battle paddle (10.0 @ +57.0): 572μ * 15.7% = 89.80399
Value of stat gain: 451.56μ
Profit per round: ActionProfitDamageOtherbase; Stocking Mimic (12.62μ)26.81μ3.14 (-4.03 μ/dmg)Att: -1.02 (-0.0 DPR) Def: -1.02 HP: 3.55 MP: 3.55
Parsed round number: 1
Building options...
Options built! (136 actions)
beer bomb (5.0 @ +57.0): 150μ * 7.85% = 11.775
beer helmet (10.0 @ +57.0): 544μ * 15.7% = 85.408
bejeweled pledge pin (10.0 @ +57.0): 560μ * 15.7% = 87.92
bottle opener belt buckle (12.0 @ +57.0): 574μ * 18.84% = 108.1416
distressed denim pants (9.0 @ +57.0): 1065μ * 14.13% = 150.4845
keg shield (5.0 @ +57.0): 577μ * 7.85% = 45.2945
perforated battle paddle (10.0 @ +57.0): 572μ * 15.7% = 89.80399
Value of stat gain: 451.56μ
Monster: War Frat 151st Infantryman, ATT: 170, DEF: 158, HP: 185, Value: 1030.39
You will die in 1115 rounds.
Your attack will kill the monster in 2 rounds.
Building custom actions...
Custom actions built! (0 actions)
Stasis action chosen: use 185
Top of the stasis loop.
Executing macro: scrollwhendone; sub batround; if haseffect 264 || haseffect 282 || haseffect 283 || haseffect 284; abort "BatBrain abort: poisoned"; endif; endsub; sub batsub1; use 185; call batround; endsub; call batsub1; repeat hascombatitem 185 && (!hpbelow 439.0 && !mpbelow 277.0 && !pastround 28); if hpbelow 8; abort "BatBrain abort: Danger, Will Robinson"; endif; 
Round 1: redwulf25 executes a macro!
Round 1: redwulf25 uses the fat stacks of cash!
Round 2: redwulf25 uses the fat stacks of cash!
Round 3: redwulf25 uses the fat stacks of cash!
Round 4: redwulf25 uses the fat stacks of cash!
Round 5: Cousin Mel mimics a red-and-white striped barber pole, spinning in front of your opponent. He looks mesmerized.
Round 5: war frat 151st infantryman drops 13 attack power.
Round 5: war frat 151st infantryman drops 13 defense.
Round 5: redwulf25 uses the fat stacks of cash!
Round 6: redwulf25 uses the fat stacks of cash!
Round 7: Cousin Mel mimics a red-and-white striped candy cane, and canes him for 39 damage.
Round 7: war frat 151st infantryman takes 39 damage.
Round 7: redwulf25 uses the fat stacks of cash!
Round 8: redwulf25 uses the fat stacks of cash!
Round 9: redwulf25 uses the fat stacks of cash!
Round 10: Cousin Mel mimics a candy-striper nurse, heals some of your wounds, and recharges your mojo.
You gain 44 hit points
You gain 44 Muscularity Points
Round 10: redwulf25 uses the fat stacks of cash!
Round 11: redwulf25 uses the fat stacks of cash!
Round 12: Cousin Mel mimics a candy-striper nurse, heals some of your wounds, and recharges your mojo.
You gain 43 hit points
You gain 43 Muscularity Points
Round 12: redwulf25 uses the fat stacks of cash!
Round 13: Cousin Mel mimics a candy-striper nurse, heals some of your wounds, and recharges your mojo.
You gain 43 hit points
You gain 43 Muscularity Points
Round 13: redwulf25 uses the fat stacks of cash!
Round 14: redwulf25 uses the fat stacks of cash!
Round 15: Cousin Mel mimics a candy-striper nurse, heals some of your wounds, and recharges your mojo.
You gain 43 hit points
You gain 43 Muscularity Points
Round 15: redwulf25 uses the fat stacks of cash!
Round 16: redwulf25 uses the fat stacks of cash!
Round 17: Cousin Mel mimics a red-and-white striped barber pole, spinning in front of your opponent. He looks mesmerized.
Round 17: war frat 151st infantryman drops 12 attack power.
Round 17: war frat 151st infantryman drops 12 defense.
Round 17: redwulf25 uses the fat stacks of cash!
Round 18: Cousin Mel mimics a red-and-white striped candy cane, and canes him for 38 damage.
Round 18: war frat 151st infantryman takes 38 damage.
Round 18: redwulf25 uses the fat stacks of cash!
Round 19: Cousin Mel mimics a red-and-white striped barber pole, spinning in front of your opponent. He looks mesmerized.
Round 19: war frat 151st infantryman drops 12 attack power.
Round 19: war frat 151st infantryman drops 12 defense.
Round 19: redwulf25 uses the fat stacks of cash!
Round 20: Cousin Mel mimics a red-and-white striped barber pole, spinning in front of your opponent. He looks mesmerized.
Round 20: war frat 151st infantryman drops 13 attack power.
Round 20: war frat 151st infantryman drops 13 defense.
Round 20: redwulf25 uses the fat stacks of cash!
Round 21: redwulf25 uses the fat stacks of cash!
Round 22: redwulf25 uses the fat stacks of cash!
Round 23: redwulf25 uses the fat stacks of cash!
Round 24: Cousin Mel mimics a red-and-white striped barber pole, spinning in front of your opponent. He looks mesmerized.
Round 24: war frat 151st infantryman drops 12 attack power.
Round 24: war frat 151st infantryman drops 12 defense.
Round 24: redwulf25 uses the fat stacks of cash!
Round 25: Cousin Mel mimics a candy-striper nurse, heals some of your wounds, and recharges your mojo.
You gain 44 hit points
You gain 44 Muscularity Points
Round 25: redwulf25 uses the fat stacks of cash!
Round 26: redwulf25 uses the fat stacks of cash!
Round 27: redwulf25 uses the fat stacks of cash!
Round 28: Cousin Mel mimics a red-and-white striped candy cane, and canes him for 37 damage.
Round 28: war frat 151st infantryman takes 37 damage.
Round 28: redwulf25 uses the fat stacks of cash!
Parsed round number: 2
Building options...
Options built! (136 actions)
Stasis action chosen: use 2678
This monster is not your huckleberry.
Stasis loop complete.
SmartStasis complete.
Round 29: redwulf25 attacks!
Round 30: war frat 151st infantryman takes 248 damage.
Round 30: redwulf25 wins the fight!
You acquire an item: beer helmet
You acquire an item: bottle opener belt buckle
You gain 29 Beefiness
You gain 9 Wizardliness
You gain 10 Sarcasm
1 frat boy defeated; 391 down, 609 left

As I said, I've sat and watched it stasis at least 10 turns after getting to full HP and MP.
 

zarqon

Well-known member
I'm happy to see from this that 1) the more permissive stasis loop is definitely saving server hits, and 2) the round number at which to abort the stasis loop is calculated correctly -- it quit stasising in enough time for you to kill the monster.

However, parsed round number: 2??? That's confusing.

There should probably also be a repeat abort condition added to the stasis loop to stop and recalculate at round 10 if you have a Coco-type and full HP/MP, since the familiar calculations that BB does can't be performed in the macro itself. Don't like doing that since it adds more server hits back in, but even though it doesn't cost anything it's confusing for people if SS stasises pointlessly.
 
Top