SmartStasis -- a complex script for a simple CCS

Bale

Minion
In mafia's CLI type: update clear

Then shut down mafia and restart it. Let us know if that solves the problem.
 

Theraze

Active member
Update on my bug above... think the issue is that gremlins are forced into a continual stasis in SmartStasis until they get detected as non-molybdenum, but BatBrain aborts picking a stasis item if you have equal to or less than 36 hp. Either BatBrain needs an exception for gremlins and an expectation that it'll likely kill you a bit more often, or SmartStasis needs an exception for myhp <= 36 in the string stasis function...
 

Bale

Minion
I was looking through BatBrain's logic some more and I found some errors with normalize_dmgtype()! Lines 394-398 are in the wrong place. Flavor of magic will not adjust the flavor of sauce spells, not even cayenne or peppermint. Those lines need to be bumped up to the "past" section.

Note those skills will still give a +10 damage bonus to sauce spells, just not any flavor.

Also, You forgot Ol' Scratch's ash can which turns sauceror spells hot, but only when you're a sauceror.

normalize_dmgtype() should look like this:

Code:
string normalize_dmgtype(string dmgt) {
   switch (dmgt) {
      case "pasta": if (have_effect($effect[spirit of cayenne]) > 0) return "hot";
         if (have_effect($effect[spirit of peppermint]) > 0) return "cold";
         if (have_effect($effect[spirit of garlic]) > 0 || have_equipped($item[cookbook of the damned])) return "stench";
         if (have_effect($effect[spirit of wormwood]) > 0 || have_equipped($item[necrotelicomnicon])) return "spooky";
         if (have_effect($effect[spirit of bacon grease]) > 0 ||
            have_equipped($item[chester aquarius medallion]) || have_equipped($item[sinful desires])) return "sleaze";
      case "sauce": if (have_equipped($item[ol' scratch's manacles]) || have_equipped($item[capsaicin conjuration]) ||
            (have_equipped($item[Ol' Scratch's ash can]) && my_class() == $class[sauceror]) || 
            have_equipped($item[snapdragon pistil])) return "hot";
         if (have_equipped($item[glacial grimoire]) || have_equipped($item[double-ice box])) return "cold";
         if (dmgt == "sauce") {
            if (have_skill($skill[immaculate seasoning]) && dmg_dealt(to_spread(1+spell_elem_bonus("hot"),"hot")) != dmg_dealt(to_spread(1+spell_elem_bonus("cold"),"cold")))
               return (dmg_dealt(to_spread(1+spell_elem_bonus("hot"),"hot")) > dmg_dealt(to_spread(1+spell_elem_bonus("cold"),"cold"))) ? "hot" : "cold";
            return "hot,cold";
         }
         string res = "cold,hot,sleaze,spooky,stench,physical";
         if (res.contains_text(monster_element())) res.replace_string(monster_element()+",","");
         return res;
   }
   return dmgt;
}
 

Winterbay

Active member
Not trying to be space saving I just moved the spirit checks up above the sauce check :)

That said, when Mafia lacks data on something it can lead to interesting effects. In my case I ran into Dr. Awkward who has no known monster defense-value (it is 1 according to Mafia, it is ??? according to the wiki). I thus made the following change to my batbrain. It can most likely be done in a better way but at least this way works :)

Code:
if (my_monster == $monster[none] || monster_attack(my_monster) == monster_level_adjustment() || (to_float(monster_defense(my_monster)) / monster_attack(my_monster) < 0.5))
{
	attadj = to_int(vars["unknown_ml"]); defadj = attadj;  hpadj = attadj;
}

Which made my consult script go from thinking I'd bash his head in with my oversized pizza cutter and 90 muscle in 2 rounds to thinking I had no chance of hitting him and instead casting fearful fettucini on him thus killing him instead of having him kill me :)

Edit: Changed the if-statement a bit since it actually caught most things...
 
Last edited:

fianor

Member
fianor : We can make things work sanely for you without using UR. Put the following in your login script. You do use a login script, right? Well you do now. Save this to a file in your /script directory with the extension .ash and set it as your login script in preferences for breakfast.

Code:
set_property("_meatperhp", to_string(max(mall_price($item[scroll of drastic healing])/ (my_maxhp()* .75), 0.001)));

That should work just fine for negating Saucy Salve by setting meatperhp, without compromising SS's idea of what it means for you to get hurt. While Universal Recovery would make SS work more accurately, it seems like a bad idea to use the script just to set a variable that can be set this easily.

The reason BB&SS do not use that simple calculation is because it is an approximation based on things I deduce about your character. If you've got Cannelloni Cocoon for example, that would change the calculation, but this is still close enough for your purpose.

setting _meatperhp to 0 worked, was in a hurry so I haven't tried your addition to my login script yet bale, but will be trying it with tomorrow's farming.
 

shazbot

Member
I've been bumping into a problem today where if my health dips low, SmartStasis gets stuck.

Code:
[2397] Battlefield (Frat Uniform)
Encounter: War Hippy Infantryman
Strategy: /Users/student/Library/Application Support/KoLmafia/ccs/default.ccs [default]
Round 0: oh shazbot loses initiative!
You lose 29 hit points
bullet-proof corduroys (10.0 @ +5.0): 580.0 meat * 10.5% = 60.9
hippy protest button (10.0 @ +5.0): 574.0 meat * 10.5% = 60.27
lead pipe (11.0 @ +5.0): 575.0 meat * 11.55% = 66.4125
reinforced beaded headband (11.0 @ +5.0): 575.0 meat * 11.55% = 66.4125
round purple sunglasses (10.0 @ +5.0): 970.0 meat * 10.5% = 101.85
wicker shield (6.0 @ +5.0): 555.0 meat * 6.3% = 34.965
water pipe bomb (5.0 @ +5.0): 150.0 meat * 5.25% = 7.875
bullet-proof corduroys (10.0 @ +5.0): 580.0 meat * 10.5% = 60.9
hippy protest button (10.0 @ +5.0): 574.0 meat * 10.5% = 60.27
lead pipe (11.0 @ +5.0): 575.0 meat * 11.55% = 66.4125
reinforced beaded headband (11.0 @ +5.0): 575.0 meat * 11.55% = 66.4125
round purple sunglasses (10.0 @ +5.0): 970.0 meat * 10.5% = 101.85
wicker shield (6.0 @ +5.0): 555.0 meat * 6.3% = 34.965
water pipe bomb (5.0 @ +5.0): 150.0 meat * 5.25% = 7.875
Monster value: 838.69
Profit per round: ActionProfitDamageOtherbase; Stocking Mimic (18.6μ)16.2μ4.62 (-4.02 MPD)Att: -1.5 (-0.59 DPR) Def: -1.5 HP: 5.16 MP: 5.16
1 MP costs 8.0 meat.
Round 1: oh shazbot executes a macro!
Round 1: oh shazbot uses the facsimile dictionary!
You lose 22 hit points
1 MP costs 8.0 meat.
Round 2: oh shazbot executes a macro!
Round 2: oh shazbot uses the facsimile dictionary!
You lose 23 hit points
1 MP costs 8.0 meat.
Round 3: oh shazbot executes a macro!
Round 3: oh shazbot uses the facsimile dictionary!
You lose 15 hit points
1 MP costs 8.0 meat.
Round 4: oh shazbot executes a macro!
Round 4: oh shazbot uses the facsimile dictionary!
You lose 19 hit points
1 MP costs 8.0 meat.
Round 5: oh shazbot executes a macro!
Round 5: oh shazbot uses the facsimile dictionary!
You lose 17 hit points
1 MP costs 8.0 meat.
Round 6: oh shazbot executes a macro!
Round 6: oh shazbot uses the facsimile dictionary!
You lose 17 hit points
1 MP costs 8.0 meat.
Round 7: oh shazbot executes a macro!
Round 7: oh shazbot uses the facsimile dictionary!
You gain 49 hit points
You gain 49 Muscularity Points
You lose 18 hit points
1 MP costs 8.0 meat.
Round 8: oh shazbot executes a macro!
Round 8: oh shazbot uses the facsimile dictionary!
You lose 18 hit points
1 MP costs 8.0 meat.
Round 9: oh shazbot executes a macro!
Round 9: oh shazbot uses the facsimile dictionary!
You lose 18 hit points
1 MP costs 8.0 meat.
Round 10: oh shazbot executes a macro!
Round 10: oh shazbot uses the facsimile dictionary!
You gain 48 hit points
You gain 48 Muscularity Points
You lose 20 hit points
1 MP costs 8.0 meat.
Round 11: oh shazbot executes a macro!
Round 11: oh shazbot uses the facsimile dictionary!
You lose 18 hit points
1 MP costs 8.0 meat.
Round 12: oh shazbot executes a macro!
Round 12: oh shazbot uses the facsimile dictionary!
You gain 49 hit points
You gain 49 Muscularity Points
You lose 18 hit points
1 MP costs 8.0 meat.
Round 13: oh shazbot executes a macro!
Round 13: oh shazbot uses the facsimile dictionary!
You lose 17 hit points
1 MP costs 8.0 meat.
Round 14: oh shazbot executes a macro!
Round 14: oh shazbot uses the facsimile dictionary!
You lose 16 hit points
1 MP costs 8.0 meat.
Round 15: oh shazbot executes a macro!
Round 15: oh shazbot uses the facsimile dictionary!
You lose 17 hit points
1 MP costs 8.0 meat.
Round 16: oh shazbot executes a macro!
Round 16: oh shazbot uses the facsimile dictionary!
You lose 17 hit points
1 MP costs 8.0 meat.
Round 17: oh shazbot executes a macro!
Round 17: oh shazbot uses the facsimile dictionary!
You lose 17 hit points
1 MP costs 8.0 meat.
Round 18: oh shazbot executes a macro!
KoLmafia thinks it is round 19 but KoL thinks it is round 18
1 MP costs 8.0 meat.
Round 19: oh shazbot executes a macro!
KoLmafia thinks it is round 20 but KoL thinks it is round 18
1 MP costs 8.0 meat.
Round 20: oh shazbot executes a macro!
KoLmafia thinks it is round 21 but KoL thinks it is round 18
1 MP costs 8.0 meat.
Round 21: oh shazbot executes a macro!
KoLmafia thinks it is round 22 but KoL thinks it is round 18
1 MP costs 8.0 meat.
Round 22: oh shazbot executes a macro!
KoLmafia thinks it is round 23 but KoL thinks it is round 18
1 MP costs 8.0 meat.
Round 23: oh shazbot executes a macro!
KoLmafia thinks it is round 24 but KoL thinks it is round 18
1 MP costs 8.0 meat.
Round 24: oh shazbot executes a macro!
KoLmafia thinks it is round 25 but KoL thinks it is round 18
1 MP costs 8.0 meat.
Round 25: oh shazbot executes a macro!
KoLmafia thinks it is round 26 but KoL thinks it is round 18
1 MP costs 8.0 meat.
Round 26: oh shazbot executes a macro!
KoLmafia thinks it is round 27 but KoL thinks it is round 18
1 MP costs 8.0 meat.
Round 27: oh shazbot executes a macro!
KoLmafia thinks it is round 28 but KoL thinks it is round 18
1 MP costs 8.0 meat.
Round 28: oh shazbot executes a macro!
KoLmafia thinks it is round 29 but KoL thinks it is round 18
1 MP costs 8.0 meat.
Round 29: oh shazbot executes a macro!
KoLmafia thinks it is round 30 but KoL thinks it is round 18
1 MP costs 8.0 meat.
Round 30: oh shazbot executes a macro!
KoLmafia thinks it is round 31 but KoL thinks it is round 18
1 MP costs 8.0 meat.
Round 31: oh shazbot executes a macro!
KoLmafia thinks it is round 32 but KoL thinks it is round 18
1 MP costs 8.0 meat.
Round 32: oh shazbot executes a macro!
KoLmafia thinks it is round 33 but KoL thinks it is round 18
1 MP costs 8.0 meat.
Round 33: oh shazbot executes a macro!
KoLmafia thinks it is round 34 but KoL thinks it is round 18
1 MP costs 8.0 meat.
Round 34: oh shazbot executes a macro!
KoLmafia thinks it is round 35 but KoL thinks it is round 18
1 MP costs 8.0 meat.
Round 35: oh shazbot executes a macro!
KoLmafia thinks it is round 36 but KoL thinks it is round 18
1 MP costs 8.0 meat.
Round 36: oh shazbot executes a macro!
KoLmafia thinks it is round 37 but KoL thinks it is round 18
1 MP costs 8.0 meat.
Round 37: oh shazbot executes a macro!
KoLmafia thinks it is round 38 but KoL thinks it is round 18
1 MP costs 8.0 meat.
Round 38: oh shazbot executes a macro!
KoLmafia thinks it is round 39 but KoL thinks it is round 18
1 MP costs 8.0 meat.
Round 39: oh shazbot executes a macro!
KoLmafia thinks it is round 40 but KoL thinks it is round 18
1 MP costs 8.0 meat.
Round 40: oh shazbot executes a macro!
KoLmafia thinks it is round 41 but KoL thinks it is round 18
1 MP costs 8.0 meat.
Round 41: oh shazbot executes a macro!
KoLmafia thinks it is round 42 but KoL thinks it is round 18
1 MP costs 8.0 meat.
Round 42: oh shazbot executes a macro!
KoLmafia thinks it is round 43 but KoL thinks it is round 18
1 MP costs 8.0 meat.
Round 43: oh shazbot executes a macro!
KoLmafia thinks it is round 44 but KoL thinks it is round 18
1 MP costs 8.0 meat.
Round 44: oh shazbot executes a macro!
KoLmafia thinks it is round 45 but KoL thinks it is round 18
1 MP costs 8.0 meat.
Round 45: oh shazbot executes a macro!
KoLmafia thinks it is round 46 but KoL thinks it is round 18
1 MP costs 8.0 meat.
KoLmafia declares world peace.
You're on your own, partner.
Click here to continue in the relay browser.

My CCS consults SmartStasis and then consults spamattack. But it seems odd for smartstasis to get stuck like that instead of just aborting or taking some other plan of action.
 

slyz

Developer
When you click to view the fight in the Relay Browser, is there any KoL Macro error?

Would running the same combat with a higher verbosity give more info?
 

Bale

Minion
Troublesome bug! You shouldn't mark slimelings as empty when initiative is won!

[395] F'c'le
Encounter: chatty pirate
Strategy: C:\Documents and Settings\Quicksilver\My Documents\My Dropbox\KolMafia\ccs\default.ccs [default]
Round 0: bale wins initiative!
Your slimeling needs sating.
Your slimeling needs sating.

Round 1: bale executes a macro!
Round 1: bale attacks!
Round 2: chatty pirate takes 50 damage.
Round 2: Princess Vina leaps on your opponent, sliming him for 19 damage. It's inspiring!
Round 2: chatty pirate takes 19 damage.
You gain 19 Muscularity Points
You lose 5 hit points
Round 2: bale attacks!
Round 3: chatty pirate takes 51 damage.
Round 3: Princess Vina sniffs around, looking for something to absorb.
Round 3: bale wins the fight!
You gain 110 Meat
After Battle: Princess Vina hops around, dancing a jig accompanied by wet squelching noises.
You gain 22 Beefiness
You gain 8 Magicalness
You gain 7 Cheek

needless to say it quickly set my slimeling fullness to 0.
 

zarqon

Well-known member
Exciting! My script is becoming more awesome thanks to a swarm of vigilant users.

@Theraze and shazbot: Yeah, either we need to remove the abort condition in the macro (allowing them to probably one-shot you while you courageously keep stasising them) or we need to not force stasis if they can one-shot you, thus allowing you to at least get stats. I opted for the latter, which will be in the next SS update -- or if you're in a hurry, add this to the top of is_our_huckleberry(): if (my_hp() < round(m_dpr(0,0))) return false;

@Winterbay: That's a good idea. I think even better would be to separate out the stats. For all three, if any stat is unknown, adjust it up by unknownML. This could lead to some funkily balanced monsters, but it's safer than being wrong the other way. So that's what I did for this update. I also moved the monster stat and stun adjustments into a single advevent, which can/will be used predictively.

@Bale: Your fix gives precedence to Flavor skills over cookbooks. I'm pretty sure that's not how it works. If you look a little more carefully at my code, you'll note that "sauce" never reaches the Flavor section of the switch statement. I did add Ol' Scratch's ash can though (which by the way you can write without omitting the apostrophes and it won't screw with syntax highlighting!).

I also fixed the jump issue for Slimelings (and ghosts), assuming that I remembered the jump string correctly as "You get the jump".
 

fianor

Member
Bale: I don't actually use a login script, but I do have a script which would be my login script if I wanted it to just completely automate before I looked into what's going on today. Basically it checks if I logged in with my main and buffs up /eats/drinks/spleens, farms 10+putty ducks, then farms the castle, sells/malls as appropriate, overdrinks and gets my pajamas on. If it's not my main it bounty hunts then logs on to the next multi and bounty hunts with it until all my multis have gotten their bounties.

Any way lots of probably unnecessary explanation to get to the point of, I added your suggestion to .. almost .. the first of my script and it has as you said fixed my issue.
 

Bale

Minion
Glad to hear that. I wasn't sure if you used a login script so I gave the primer just in case. I hope you didn't feel I was babying you with too much exposition.


@Bale: Your fix gives precedence to Flavor skills over cookbooks. I'm pretty sure that's not how it works. If you look a little more carefully at my code, you'll note that "sauce" never reaches the Flavor section of the switch statement.

Ah, my bad! At least I was able to contribute Ol' Scratch's ash can.
 

Bale

Minion
Suggestion for SS... When fighting a Quantum Mechanic (or Uppercase Q) do not stasis unless can_interact(). The lost opportunity cost of getting teleportitis is pretty severe and not worth the possible MP my slimeling might give me.

Ouch. I'm glad I put off finishing the dungeon of doom later than usual since that's gonna cost me a SGEEA.
 
Last edited:

Winterbay

Active member
@Winterbay: That's a good idea. I think even better would be to separate out the stats. For all three, if any stat is unknown, adjust it up by unknownML. This could lead to some funkily balanced monsters, but it's safer than being wrong the other way. So that's what I did for this update. I also moved the monster stat and stun adjustments into a single advevent, which can/will be used predictively.

Indeed it would probably be that, my fix was mainly thrown together quickly to let me use my consult script against Dr Awkward :)
 

lostcalpolydude

Developer
Staff member
Suggestion for SS... When fighting a Quantum Mechanic (or Uppercase Q) do not stasis unless can_interact(). The lost opportunity cost of getting teleportitis is pretty severe and not worth the possible MP my slimeling might give me.

You can't get teleportitis from an uppercase q.
 

Bale

Minion
You can't? I always assumed that it had all the same abilities as it's identified counterpart.

Well the Quantum Mechanic is still not a good stasis target, except possibly in aftercore.
 

zarqon

Well-known member
I added something slightly more succinct:

PHP:
if (last_monster() == $monster[quantum mechanic] && m_hit_chance() > 0.1) return page;  // avoid teleportitis

If a quantum mechanic has better than a 10% chance of hitting you, it will never stasis. This number can be tweaked down yet further if people are getting Teleported due to stasis.

I'm adjusting SS to use some of the more recent functions in BB. Once that's done, I'll post an SS update. Probably tomorrow.
 

Bale

Minion
I'm not sure that's good enough. Even if the quantum mechanic only hits you once, regardless of being a critical or a regular attack, it has a chance to ruin your next TEN turns. That's a big deal. Well, it will be very easy to edit in my local copy now that you added the line.
 
Top