Illarion's NeoStasis script v1.4

holatuwol

Developer

element monster_attack_element( monster ): Added
element monster_defense_element( monster ): Added

element monster_attack_element(): Added
element monster_defense_element(): Added

int monster_attack(): Added
int monster_defense(): Added
int monster_hp(): Added

boolean will_usually_miss(): Added
boolean will_usually_dodge(): Added
 
[quote author=holatuwol link=topic=799.msg4329#msg4329 date=1177549558]

element monster_attack_element( monster ): Added
element monster_defense_element( monster ): Added

element monster_attack_element(): Added
element monster_defense_element(): Added

int monster_attack(): Added
int monster_defense(): Added
int monster_hp(): Added

boolean will_usually_miss(): Added
boolean will_usually_dodge(): Added

[/quote]

And they have been added to the scripting wiki also, I hope my descriptions are correct.
 

gemelli

Member
The response you guys provide via this forum is nothing short of phenomenal. Kudos!

As long as we're adding a check for Amnesia:

Code:
	if(have_effect($effect[Jabañero Saucesphere])==0)
		 { cli_execute("abort: Oops!  You forgot the sauce."); }

On that note, it might be best to add a general effect-checking function that tweaks the combat handling logic in a few places ... e.g., if we're poisoned, we may not want to use the antidote action unless we have more than one antidote on hand. Although I'm not planning to make any major mods to the script myself until all those juicy new functions are available in a public release. You can't see it from here, but I am salivating :D
 

illarion

Member
Thanks Hola, very much appreciated!

One question:
boolean will_usually_miss(): Added
boolean will_usually_dodge(): Added

What exactly does "usually" mean in this context? "Always unless there is a critical", "5%", etc?

Gemelli> Agree with the idea.

Now if only we could queue non-combat skill use after the combat... ;)
 

holatuwol

Developer
>= 80% in the average case. It's the same tests KoLmafia uses internally to decide when to stop deleveling or when it's okay to steal.
 

BDrag0n

Member
OK, thanks to the wonderful new changes, and a few requests / ideas - here is a new version.

Note that this is NOT FULLY TESTED and is being posted so Illarion or Gemelli don't waste hours reproducing the same w**k - instead they can pick my hopeless coding to pieces and improve on it!

So - not fully tested, don't rely on it yet, etc etc - but here's what I've been w**king on. It is substantially changed from before, most of the changes are detailed at the top in the changelog but you can see that I've made quite a few changes in the coding.

BDrag0n

Code:
#  NeoStasis.ash
#  v2
#  by Illarion, BDrag0n & Gemelli
#  A KoL Stasis script for the post-noodle world.
#  formulae courtesy of HCO forums
#  Many thanks to Holatuwol and Veracity, without whom this never would have been possible
#  Thanks to dirkdiggler for leatherback formula

#  Change history

# v2 (28/04/07) Major changes by BDrag0n, mostly enabled by new functions added by Holatuwol
# Armour moved to Medium unsafe stasis list, and high if tetanus would take you below 68 mainstat.
# Aborts added for Amnesia, or no jab sphere running.
# Added elemental defence to expected monster damage
# Will not use up your last anti-anti-antidote during combat.
# Will try to kill immediately if expected damage is too high
# Changed killing logic
#  - All spells and TS/LTS are considered at the same time - with exceptions for Procrastination & physical resistance.
#  - takes into account elemental damage & weaknesses  (note: not for pastamancer spells)
#  - does cheapest attack which will kill in 1-shot where possible.
#  - When kill logic fails to find a skill to use, abort rather than try and hit
#  - will always try to kill as fast as possible where killing is necessary

#  v1.7b - (14/04/07) SauceKill rewritten to consider a 2-hit kill if 1-hit isn't possible. Changed behaviour for unsafe monsters which are weak against hot/cold IF you have immaculate seasoning & stream
#  v1.7a - Minor tweaks by Gemelli
#  v1.7 - (13/04/07) changes by BDrag0n - added new expected damage routine suggested by DarthDud, changed procrastination giant handling
#  v1.6 - changes by Gemelli - added check to see if monster is safe to use stasis against, added 
#       immediate-finish logic for unsafe monsters, tweaked logic of FinishNOW routine, added 
# 	    "we have enough MP" logic
#  v1.5 - changes by BDrag0n - closer min and max healing levels for salve/cocoon
#  v1.4 - better cocoon support, better handling of situations when mob or player cannot hit,
#	fixed panic noodling, included Gemelli's workaround for undefined monsters
#  v1.3 - fixed entangling noodle bug?, FinishNOW implemented, aware of physical-resistant monsters,
#	sanity check when monster can't hit player.
#  v1.2- fixed shield/hero test bug, tidied display messages, used antidote
#  v1.1 - Location checking for dictionary, pickpocket, fixed mp_cost check
#  v1.0 - Forked from ASHStasis v1.4



#*** Begin user-configurable variables ***#

//Change to false if antidote is changed!
boolean USE_ANTIDOTE = true;

//Change to false if goodfella contract is changed!
boolean USE_GOODFELLA = true;


#Default values:
int DAM_THRESHOLD = 20;

// This section is about healing. The safety net is how much HP you want spare - remember to allow for monster variance!
int SAFETY_NET = 3;            //Minimum health left after expected monster damage & risk of fumble  - suggested 3
int OOC_HEAL_LEVEL = 80;       //the max HP level at which changing to out of combat healing would be better

// Threshhold for painful combat effects: set to high (only abort on monsters with really bad
// effects), medium (abort on monsters with moderate-to-bad effects), or low (abort on all 
// monsters that could give a bad combat effect)
string EFFECT_THRESHOLD = "medium";

// Set threshhold for MP ... if you are more than MANA_MAX the script will stop stasising
int MANA_MAX = my_maxMP()-10;

// And since the good ol' Bugbear eats MP like it was Pringles ...
if(my_familiar()==$familiar[Pygmy Bugbear Shaman]) MANA_MAX=my_maxMP();

//if your moxie exceeds monster attack by this much, don't bother trying to stasis (as mob can't hit)
int OVERMOXIE_LEVEL = 8;

#print debug messages.  These go to the Mafia status bar, and the gCLI.  Turn them off if
#you're happy with the performance, and don't care about tweaking/understanding what's going on.
boolean dbug = true;

//Use to show more detailed output
boolean bVerbose = true;

#*** End of user-configurable variables ***#

#Used for status messages
int giRound;

int giCurDelevel;
boolean gbEnemyNoodled;
boolean gbInValley;
stat gDefenceStat;
monster zilch=$monster[];

boolean bUsedNoodles;
string MSG_NOODLEBREAK = "Your opponent struggles free of your entangling noodles.";


int max(int a, int b)
{
	int iRetVal;
 	if (a > b)
 	{
		iRetVal = a;
 	}
 	else
 	{
 		iRetVal = b;
 	}
 	return iRetVal;
}

int min(int a, int b)
{
	int iRetVal;
 	if (a < b)
 	{
		iRetVal = a;
 	}
 	else
 	{
 		iRetVal = b;
 	}
 	return iRetVal;
}

int LeatherBackDR()
{
	//DR from Leatherback, as dirkdiggler's formula:
	//Leatherback DR = Clamp[ 1 < ceil( (level-3)/2 ) ]

	int iResult;
	if (have_skill($skill[skin of the leatherback]))
	{
		iResult = (max(1, ceil( (my_level()-3)/2 )));
	}
	else
	{
		iResult = 0;
	}
	return iResult;
}

void ShowStatusMsg(string Msg)
{
	print( "Round: " + giRound + " " +
	"(MP Change=" + (my_mp()-string_to_int(get_property("IllStasis_StartMP"))) +      				", HP Change=" + (my_hp()-string_to_int(get_property("IllStasis_StartHP"))) +  ") --> " + Msg );
}

boolean ShieldEquipped()
{
	boolean bFoundShield = false;
	string sItem;
	sItem = item_to_string(current_equipment($slot[off-hand]));
	bFoundShield = bFoundShield || (index_of(sItem, "buckler" )>=0);
	bFoundShield = bFoundShield || (index_of(sItem, "shield" )>=0);
	bFoundShield = bFoundShield || (index_of(sItem, "hors d'oeuvre tray" )>=0);
	bFoundShield = bFoundShield || (index_of(sItem, "box turtle" )>=0);
	bFoundShield = bFoundShield || (index_of(sItem, "coffin lid" )>=0);
	bFoundShield = bFoundShield || (index_of(sItem, "sewer turtle" )>=0);

	if (bVerbose) { Print("Offhand=" + sItem + "-> Shield=" + boolean_to_string(bFoundShield)); }

	return bFoundShield;
}

int CheckSkill(skill myskill)
//return 0=success, 1=insufficient mana, 2=do not have skill
{
    if (!have_skill(myskill))
    {
       return 2;
    }
    else
    {
		if (my_mp() < mp_cost(myskill) )
		{
		   return 1;
		}
	}
	return 0;
}

// max fumble damage if you're "hitting" with a weapon
int get_fumble()
{
	// expected fumble damage for the equipped weapon
	int damage = ceil(get_power(current_equipment($slot[weapon]))/10);         
	if (item_amount($item[goodfella contract])>0 && USE_GOODFELLA && my_familiar()!=$familiar[Penguin Goodfella])
	  //if you're not hitting with a weapon, you won't fumble
		 { damage = 0; }
	if (item_amount($item[anti-anti-antidote])>0 && USE_ANTIDOTE)
	  //if you're not hitting with a weapon, you won't fumble
		 { damage = 0; }
	if (item_amount($item[dictionary])>0 && !gbInValley)
		 { damage = 0; }
	if (item_amount($item[facsimile dictionary])>0 && !gbInValley)
		 { damage = 0; }
	if (have_skill($skill[shake hands]) )
		 { damage = 0; }
	return damage;
}


string StasisSafe(monster eek) {

	if(EFFECT_THRESHOLD=="low") 
        {
                // Trigger on low-impact effects, which generally affect a single stat
		if (eek == $monster[7-foot dwarf foreman])        return "finish";      // Grilled
		if (eek == $monster[disease-in-the-box])          return "finish";      // The Disease
 		if (eek == $monster[decent lumberjack])           return "finish";      // axe wound
		if (eek == $monster[lumberjack supervisor])       return "finish";      // axe wound
		if (eek == $monster[lumberjill])                  return "finish";      // axe wound
		if (eek == $monster[lumberjuan])                  return "finish";      // axe wound
		if (eek == $monster[conjoined zmombie])           return "finish";      // half-eaten brain
		if (eek == $monster[corpulent zobmie])            return "finish";      // half-eaten brain
   		if (eek == $monster[grave rober zmobie])          return "finish";      // half-eaten brain
       		if (eek == $monster[zombie waltzers])             return "finish";      // half-eaten brain
		if (eek == $monster[zmobie])                      return "finish";      // half-eaten brain
		if (eek == $monster[big creepy spider])           return "finish";      // hardly poisoned
		if (eek == $monster[completely different spider]) return "finish";      // hardly poisoned
		if (eek == $monster[mayonnaise wasp])             return "finish";      // hardly poisoned
		if (eek == $monster[mind flayer])                 return "finish";      // confused
	}

	if(EFFECT_THRESHOLD=="medium") 
        {
		// Trigger on medium-impact effects: Moderate poisonings, etc.
		if (eek == $monster[acid blob])                   return "finish";      // corroded weapon
		if (eek == $monster[whitesnake])                  return "finish";      // a little bit poisoned
		if (eek == $monster[dodecapede])                  return "finish";      // a little bit poisoned
		if (eek == $monster[spectral jellyfish])          return "finish";      // somewhat poisoned
		if (eek == $monster[swarm of killer bees])        return "finish";      // somewhat poisoned
  	        if (eek == $monster[empty suit of armor])         return "finishnow";   // tetanus
	}

	// Always trigger on high-impact effects  - Note cunctatitis is dealt with elsewhere

	if (eek == $monster[crusty hippy])                        return "finishnow";   // socialismydia
	if (eek == $monster[protagonist])                         return "finishnow";   // temporary amnesia
	if (eek == $monster[quantum mechanic])                    return "finishnow";   // teleportitis
	if (eek == $monster[empty suit of armor] 
                           && my_buffedstat(my_primestat())<76)   return "finishnow";   // tetanus

	// If we got here, no worries!  Stasis away, you filthy stasis monkey.
	
	return "safe";
}

int get_spell_bonus(string Spell_class, )
{
int spellbonus=0;
//start with skills
      if(Spell_class="sauce")
      {
 	if(have_skill($skill[intrinsic spiciness])) spellbonus=min(my_level(),10);
	if(have_skill($skill[immaculate seasoning])) spellbonus=spellbonus+10;
      }

// now active effects
       if(have_effect($effect[Aspect of the Twinklefairy])>0) spellbonus=spellbonus+5;
       if(have_effect($effect[Jackasses' Symphony of Destruction])>0) spellbonus=spellbonus+12;

// Well, that was short. Equipment should have more bonus possibility
       if(have_equipped($item[plexiglass pinky ring])) spellbonus=spellbonus+30 ;
       if(have_equipped($item[stainless steel scarf])) spellbonus=spellbonus+20 ;
       if(have_equipped($item[kickback cookbook])) spellbonus=spellbonus+20 ;
       if(have_equipped($item[rib of the bonerdagon])) spellbonus=spellbonus+15 ;
       if(have_equipped($item[star spatula])) spellbonus=spellbonus+15 ;
       if(have_equipped($item[silver shrimp fork])) spellbonus=spellbonus+14 ;
       if(have_equipped($item[oversized pizza cutter])) spellbonus=spellbonus+13 ;
       if(have_equipped($item[enchanted toothpick])) spellbonus=spellbonus+12 ;
       if(have_equipped($item[chopsticks])) spellbonus=spellbonus+12 ;
       if(have_equipped($item[baconstone pendant])) spellbonus=spellbonus+10 ;
       if(have_equipped($item[clockwork staff])) spellbonus=spellbonus+10 ;
       if(have_equipped($item[huge spoon])) spellbonus=spellbonus+10 ;
       if(have_equipped($item[iron pasta spoon])) spellbonus=spellbonus+10 ;
       if(have_equipped($item[knob goblin melon baller])) spellbonus=spellbonus+8 ;
       if(have_equipped($item[filthy pestle])) spellbonus=spellbonus+7 ;
       if(have_equipped($item[hairy staff])) spellbonus=spellbonus+7 ;
       if(have_equipped($item[linoleum crossbow])) spellbonus=spellbonus+7 ;
       if(have_equipped($item[linoleum sword])) spellbonus=spellbonus+7 ;
       if(have_equipped($item[linoleum staff])) spellbonus=spellbonus+7 ;
       if(have_equipped($item[projectile icemaker])) spellbonus=spellbonus+7 ;
       if(have_equipped($item[shuddersword])) spellbonus=spellbonus+7 ;
       if(have_equipped($item[9-ball])) spellbonus=spellbonus+5 ;
       if(have_equipped($item[jack flapper])) spellbonus=spellbonus+5 ;
       if(have_equipped($item[ring of increase damage])) spellbonus=spellbonus+5 ;
       if(have_equipped($item[shiny butcherknife])) spellbonus=spellbonus+5 ;
       if(have_equipped($item[knob goblin spatula])) spellbonus=spellbonus+4 ;
       if(have_equipped($item[basic meat foon])) spellbonus=spellbonus+3 ;
       if(have_equipped($item[bugbear beanie])&& have_equipped($item[bugbear bungguard])) spellbonus=spellbonus+3 ;
       if(have_equipped($item[clown wig])) spellbonus=spellbonus+3 ;
       if(have_equipped($item[gnollish pie server])) spellbonus=spellbonus+3 ;
       if(have_equipped($item[gnollish slotted spoon])) spellbonus=spellbonus+3 ;
       if(have_equipped($item[portable corkscrew])) spellbonus=spellbonus+3 ;
       if(have_equipped($item[eggbeater])) spellbonus=spellbonus+2 ;
       if(have_equipped($item[knob goblin tongs])) spellbonus=spellbonus+2 ;
       if(have_equipped($item[corn holder])) spellbonus=spellbonus+1 ;
       if(have_equipped($item[little paper umbrella])) spellbonus=spellbonus+1 ;

       //I'm going to ignore the concentration potions
       return spellbonus;
}

int get_melee_bonus()
{
int add_melee=0;
//start with skills
 	if(have_skill($skill[claws of the walrus])) add_melee=add_melee+4;
 	if(have_skill($skill[claws of the otter])) add_melee=add_melee+3;

// now active effects
       if(have_effect($effect[Twinkly Weapon])>0) add_melee=add_melee+3;
       if(have_effect($effect[Sharp Weapon])>0) add_melee=add_melee+5;
       if(have_effect($effect[Pronounced Potency])>0) add_melee=add_melee+5;
       if(have_effect($effect[Tenacity of the Snapper])>0) add_melee=add_melee+8;
       if(have_effect($effect[Rage of the Reindeer])>0) add_melee=add_melee+10;
       if(have_effect($effect[PaPowerful])>0) add_melee=add_melee+10;
       if(have_effect($effect[Engorged Weapon])>0) add_melee=add_melee+10;
       if(have_effect($effect[Aspect of the Twinklefairy])>0) add_melee=add_melee+5;
       if(have_effect($effect[Jackasses' Symphony of Destruction])>0) add_melee=add_melee+12;
       if(have_effect($effect[Ponderous Potency])>0) add_melee=add_melee+20;

// and equipment - note that this will not spot duplicate equipment
       if(have_equipped($item[flaming talons])) add_melee=add_melee+5 ;
       if(have_equipped($item[plexiglass pike pike])) add_melee=add_melee+25  ;
       if(have_equipped($item[stainless steel shillelagh])) add_melee=add_melee+20 ;
       if(have_equipped($item[batblade])) add_melee=add_melee+15 ;
       if(have_equipped($item[mohawk wig])) add_melee=add_melee+10 ;
       if(have_equipped($item[pitchfork])) add_melee=add_melee+9 ;
       if(have_equipped($item[ridiculously huge sword])) add_melee=add_melee+10 ;
       if(have_equipped($item[denim axe])) add_melee=add_melee+5 ;
       if(have_equipped($item[hamethyst necklace])) add_melee=add_melee+5 ;
       if(have_equipped($item[ring of increase damage])) add_melee=add_melee+5 ;
       if(have_equipped($item[9-ball])) add_melee=add_melee+5 ;
       if(have_equipped($item[ninja mop])) add_melee=add_melee+4 ;
       if(have_equipped($item[sabre teeth])) add_melee=add_melee+4 ;
       if(have_equipped($item[knob goblin elite polearm])) add_melee=add_melee+3 ;


       return add_melee;
}

int get_elemental(string what_type)
{
  int hot_damage=0;
  int cold_damage=0;
  int spooky_damage=0;
  int sleaze_damage=0;
  int stench_damage=0;
  int elemental=0;
  
//This will try to get all elemental effects. Since some apply to both, and some only Melee/Spells, it's all one function
  //hot first
         if(have_effect($effect[heart of orange])>0) hot_damage=hot_damage+5;
         if(have_equipped($item[5-ball])) hot_damage=hot_damage+5;
         if(have_effect($effect[hot blooded])>0) hot_damage=hot_damage+10;
         if(what_type="melee")
         {
           if(have_effect($effect[flaming weapon])>0) hot_damage=hot_damage+3;
           if(have_equipped($item[flaming talons])) hot_damage=hot_damage+5;
           if(have_equipped($item[demon whip])) hot_damage=hot_damage+3;
           if(have_equipped($item[icy-hot katana])) hot_damage=hot_damage+3;
         }
         if(what_type="sauce")
         {
         if(have_equipped($item[demonskin jacket])) hot_damage=hot_damage+5;
         if(have_equipped($item[foon of fulmination])) hot_damage=hot_damage+8;
         if(have_equipped($item[ram-battering staff])) hot_damage=hot_damage+10;
         if(have_equipped($item[Codex of Capsaicin Conjuration])) hot_damage=hot_damage+10 ;
         if(have_equipped($item[enchantlers])) hot_damage=hot_damage+10 ;
         }

  //cold
         if(have_effect($effect[cold blooded])>0) cold_damage=cold_damage+10;
         if(have_equipped($item[2-ball])) cold_damage=cold_damage+5;
         if(what_type="melee")
         {
           if(have_equipped($item[icy-hot katana])) cold_damage=cold_damage+3;
           if(have_equipped($item[projectile icemaker])) cold_damage=cold_damage+5;
           if(have_effect($effect[frigid weapon])>0) cold_damage=cold_damage+3;
         }
         if(what_type="sauce")
         {
         if(have_equipped($item[foon of frigidity])) cold_damage=cold_damage+8;
         if(have_equipped($item[Gazpacho's Glacial Grimoire])) cold_damage=cold_damage+10 ;
         }

  //spooky
         if(have_effect($effect[spooky demeanor])>0) spooky_damage=spooky_damage+10;
         if(have_equipped($item[3-ball])) spooky_damage=spooky_damage+5;
         if(have_effect($effect[dirge of dreadfulness])>0) spooky_damage=spooky_damage+12;
         if(what_type="melee")
         {
         if(have_effect($effect[spooky weapon])>0) spooky_damage=spooky_damage+3;
         if(have_effect($effect[snarl of the timberwolf])>0) spooky_damage=spooky_damage+10;
         if(have_equipped($item[clownskin harness])) spooky_damage=spooky_damage+2;
         if(have_equipped($item[lupine sword])) spooky_damage=spooky_damage+9;
         if(have_equipped($item[spiked femur])) spooky_damage=spooky_damage+6;
         if(have_equipped($item[shuddersword])) spooky_damage=spooky_damage+5;
         }
         if(what_type="sauce")
         {
         if(have_equipped($item[foon of fearfulness])) spooky_damage=spooky_damage+8;
         }

  //sleaze
         if(have_equipped($item[4-ball])) sleaze_damage=sleaze_damage+5;
         if(have_effect($effect[supafly])>0) sleaze_damage=sleaze_damage+10;            
         if(what_type="melee")
         {
           if(have_equipped($item[clownskin harness])) sleaze_damage=sleaze_damage+2;
           if(have_equipped($item[demon whip])) sleaze_damage=sleaze_damage+3;
           if(have_effect($effect[sleazy weapon])>0) sleaze_damage=sleaze_damage+3;
           if(have_effect($effect[amorous])>0) sleaze_damage=sleaze_damage+5;
         }
         if(what_type="sauce")
         {
         if(have_equipped($item[foon of fleshiness])) sleaze_damage=sleaze_damage+8;
         if(have_equipped($item[giant cheesestick])) sleaze_damage=sleaze_damage+11;
         }

  //stench
         if(have_effect($effect[stenchtastic])>0) stench_damage=stench_damage+10;
         if(have_equipped($item[6-ball])) stench_damage=stench_damage+5;
         if(what_type="melee")
         {
         if(have_effect($effect[stinky weapon])>0) stench_damage=stench_damage+3;
         if(have_equipped($item[demon whip])) stench_damage=stench_damage+3;
         }
         if(what_type="sauce")
         {
         if(have_equipped($item[foon of foulness])) stench_damage=stench_damage+8;
         if(have_equipped($item[smoldering staff])) stench_damage=stench_damage+11;
         }
// calculating elemental bonus for sauce before weaknesses, since that will be dealt with for the whole spell.
  if(what_type="sauce" && have_skill($skill[immaculate seasoning])) elemental=max(hot_damage, cold_damage);
  if(what_type="sauce" && !have_skill($skill[immaculate seasoning])) elemental=min(hot_damage, cold_damage);  //best to assume the worst

  //now to consider the weaknesses
  if(bVerbose) print("Monster defence is "+element_to_string(monster_defense_element()));
    if(monster_defense_element()= $element[hot])
    {
     stench_damage=stench_damage*2;
     sleaze_damage=sleaze_damage*2;
     hot_damage=1;
    }   
    if(monster_defense_element()= $element[cold])
    {
     hot_damage=hot_damage*2;
     spooky_damage=spooky_damage*2;
     cold_damage=1;
    }
    if(monster_defense_element()= $element[spooky])
    {
     stench_damage=stench_damage*2;
     hot_damage=hot_damage*2;
     spooky_damage=1;
    }
    if(monster_defense_element()= $element[sleaze])
    {
     cold_damage=cold_damage*2;
     spooky_damage=spooky_damage*2;
     sleaze_damage=1;
    }
    if(monster_defense_element()= $element[stench])
    {
     cold_damage=cold_damage*2;
     sleaze_damage=sleaze_damage*2;
     stench_damage=1;
    }
  if(what_type="melee") elemental = hot_damage+cold_damage+spooky_damage+sleaze_damage+stench_damage;
  if(dbug) print("You have "+int_to_string(elemental)+" elemental damage to add for "+what_type );
  return elemental;

}

int get_offhand()
{
 int offhand_weapon_damage=0;
 if(get_power(current_equipment($slot[off-hand]))>0 && !ShieldEquipped())
 {
  if(bVerbose) print("Weapon in offhand");
  offhand_weapon_damage=get_power(current_equipment($slot[off-hand]))/10;
 }
 return offhand_weapon_damage;
}

skill Choose_skill(int hp_target, boolean hitting_allowed)
{
        // LTS/TS formulae are from HCO forums, courtesy of Strangerer
	// Spell bonuses - sauce only, no check for cookbook or flavour of magic as these are unlikely!
	int spicebonus=get_spell_bonus("sauce");
	int pastabonus=get_spell_bonus("pasta");
        int spell_element = get_elemental("sauce");
	int expectdam=0;
	int my_myst=my_buffedstat($stat[mysticality]);

        skill To_use=$skill[none];
        
	boolean sauce_resistant=false;
	if(monster_defense_element()==$element[cold])
	{ 
          if(!have_skill($skill[immaculate seasoning]) && !have_equipped($item[Gazpacho's Glacial Grimoire]))
          {
            sauce_resistant=true;     //risk of doing minimal damage with sauce
            if(dbug)            print("Risk of doing minimal damage, ignoring sauce spells");
          }
         }
 	if(monster_defense_element()==$element[hot])
	{ 
          if(!have_skill($skill[immaculate seasoning]) && !have_equipped($item[Codex of Capsaicin Conjuration]))
          {
            sauce_resistant=true;     //risk of doing minimal damage with sauce
            if(dbug)            print("Risk of doing minimal damage, ignoring sauce spells");
          }
         }

        boolean sauce_weak=false;    //check if the spell you're casting hits a weakness - only if guaranteed
        if(monster_defense_element()==$element[sleaze] ||monster_defense_element()==$element[stench])
        { 
          if(have_skill($skill[immaculate seasoning]) || have_equipped($item[Gazpacho's Glacial Grimoire]))
          {
           sauce_weak=true;
           if(dbug) print("Monster is weak to your spells!");
          }
        }
        if(monster_defense_element()==$element[cold] ||monster_defense_element()==$element[spooky])
        { 
          if(have_skill($skill[immaculate seasoning]) || have_equipped($item[Codex of Capsaicin Conjuration]))
          {
           sauce_weak=true;
           if(dbug) print("Monster is weak to your spells!");
          }
        }

        int melee_bonus=get_melee_bonus();      //only for physical attacks
        int melee_elemental=get_elemental("melee");
        int offhand_damage=get_offhand();

	record kill_it { skill name; int spelldam; } ;
	kill_it [int] damage_dealers;
	damage_dealers [1].name = $skill[saucegeyser];		// 40 mp
	damage_dealers [1].spelldam = (my_myst*0.35)+35 + spicebonus + spell_element;
	damage_dealers [2].name = $skill[weapon of the pastalord]; 	// 35 mp
	damage_dealers [2].spelldam = (my_myst*.35)+32 + pastabonus;
	damage_dealers [3].name = $skill[wave of sauce];		// 23 mp
	damage_dealers [3].spelldam = min((my_myst*0.3)+20,50) + spicebonus + spell_element;
	damage_dealers [4].name = $skill[cone of whatever];		// 19 mp
	damage_dealers [4].spelldam = min((my_myst*.25)+16,46) + pastabonus;
	damage_dealers [5].name = $skill[saucestorm];		// 12 mp
	damage_dealers [5].spelldam = min((my_myst/5)+14,39) + spicebonus + spell_element;
	if(hitting_allowed && current_hit_stat() == $stat[muscle])
	{
	damage_dealers [6].name = $skill[lunging thrust-smack];          // 8 mp
	damage_dealers [6].spelldam =  (((get_power(current_equipment($slot[weapon]))/10)+melee_bonus)*3) + melee_elemental + min(0,(my_buffedstat($stat[muscle])-monster_defense()))+offhand_damage;
	}
	damage_dealers [7].name = $skill[extreme ray of something];	// 7 mp
	damage_dealers [7].spelldam = min((my_myst*.15)+8,28) + pastabonus;
	damage_dealers [8].name = $skill[minor ray of something];	// 4 mp
	damage_dealers [8].spelldam = min((my_myst*.07)+3,18) + pastabonus;
	damage_dealers [9].name = $skill[stream of sauce];		// 3 mp
	damage_dealers [9].spelldam = min((my_myst/10)+3,18) + spicebonus + spell_element;
	if(hitting_allowed && current_hit_stat() == $stat[muscle])
	{
 	damage_dealers [10].name = $skill[thrust-smack]; 	// 3 mp
 	damage_dealers [10].spelldam = (((get_power(current_equipment($slot[weapon]))/10)+melee_bonus)*2)+ melee_elemental + min(0,(my_buffedstat($stat[muscle])-monster_defense()))+offhand_damage;
         }
 //allowance for elemental spells here  - Sauce only
 if(sauce_resistant)
 {
	damage_dealers [1].spelldam = 1;           //Saucegeyser
	damage_dealers [3].spelldam = 1;           //Wave
	damage_dealers [5].spelldam = 1;           //Storm
	damage_dealers [9].spelldam = 1;           //Stream
 }
 if(sauce_weak)
 {
 	damage_dealers [1].spelldam = 2*((my_myst*0.35)+35 + spicebonus + spell_element);           //Saucegeyser
	damage_dealers [3].spelldam = 2*(min((my_myst*0.3)+20,50) + spicebonus + spell_element);    //Wave
	damage_dealers [5].spelldam = 2*(min((my_myst/5)+14,39) + spicebonus + spell_element);      //Storm
	damage_dealers [9].spelldam = 2*(min((my_myst/10)+3,18) + spicebonus + spell_element);      //Stream
 }


	skill possible;
	int possible_dam;

	foreach key in damage_dealers
	{
	possible = damage_dealers[key].name;
	possible_dam = damage_dealers[key].spelldam;
//        Print("Casting "+skill_to_string(damage_dealers[key].name)+" should do "+ int_to_string(damage_dealers[key].spelldam));
	if(checkSkill(possible)==0)
		{
		if(possible_dam >= hp_target)
			{
			To_use=possible;
			expectdam = possible_dam;
   		        if(bVerbose) print(skill_to_string(To_use)+" should do "+int_to_string(expectdam)+" damage.");
			}
		}
	}
	return To_use;

}


boolean CheckPhysicalResistance(monster eek)
{
	if (eek == $monster[chalkdust wraith])
		return true;
	if (eek == $monster[Ghost Miner])
		return true;
	if (eek == $monster[Snow Queen])
		return true;
	return false;
}


void Kill(monster eek) {

	// Guess at monster remaining HP, see which spell we have that can do as close 
	// to a one-hit kill as possible

	int hp_target=monster_hp();
	if(dbug) print("Kill: need to do " + hp_target + " points of damage in one turn.");
	boolean LTS_safe = true;
       //  eek==$monster[Apathetic Lizardman] ||  to be added back
	if(eek==$monster[Procrastination Giant] ||  eek==$monster[acid blob] || CheckPhysicalResistance(eek) || gbEnemyNoodled)
	{ 
          LTS_safe = false;
          if(dbug) Print("Don't hit it!");
          }

	skill whichSkill=$skill[none];

	Whichskill = Choose_skill(hp_target, LTS_safe);

	//If a 1-hit isn't possible, it's worth casting noodles - but only if we've at least 3 rounds to play with
	if(WhichSkill==$skill[none] && CheckSkill($skill[entangling noodles])==0 && bUsedNoodles==false && giRound<27)
	{
                if(dbug) Print("No 1-Hit Kill. Noodling");
		use_skill($skill[entangling noodles]);
		set_property("IllNeoStasis_UsedNoodles", "true");
		set_property("IllNeoStasis_EnemyNoodled", "true");
		return;
	}
	if(WhichSkill=$skill[none])	//no 1-hit kill, check for 2-hit
		{
		hp_target=hp_target/2;
		Whichskill = Choose_skill(hp_target, LTS_safe);
		}

        //We should have a skill now, for a 1 or 2-hit kill
	if(WhichSkill !=$skill[none])
	{
		if(dbug) print("Casting "+skill_to_string(WhichSkill));
		use_skill(WhichSkill);
	}
	else
	{
		if(CheckSkill($skill[stream of sauce])==0 && giRound<=27)	//allowing time to kill, hopefully!
		{
			if(dbug) print("Casting stream of sauce ... which is better than nothing.");
			use_skill($skill[stream of sauce]);
		}
		else
		{
			// Hmm.  Got CLEESH?
			if(CheckSkill($skill[cleesh])==0) 
                        {
                         whichSkill=$skill[cleesh];
                        }
			else 
                        {
                         cli_execute("Abort Kill it now!");
                        }
		}
	}	
}



int ExpectedMonsterDamage(monster eek)
//BaseMonsterDmg = (20% to 25%)*Atk + (Atk-Mox)
//Dam = (Base - DR) * DA * ER
{
 	 int iDam;
 	 int iAtk;
 	 int iMoxPenalty;
 	 int iDR;
	 iAtk = monster_attack();

	 iMoxPenalty = max(iAtk - my_buffedstat(gDefenceStat),0);
	 iDam = 0.25*iAtk + iMoxPenalty;
	 iDam = iDam - damage_reduction()-LeatherbackDR();
	 iDam = iDam - (iDam * damage_absorption_percent()/100);

	 iDam = iDam- (iDam * elemental_resistance(monster_attack_element())/100) ;
         if(bVerbose) print("You have "+int_to_string(elemental_resistance(monster_attack_element()))+"% elemental resistance");
	 // if (bVerbose) { Print("Expected:  (25% of " + iAtk + "+" + iMoxPenalty + "-(" + damage_reduction() + "+" + LeatherBackDR() + ")DR) * " + damage_absorption_percent() + "%DA = " + iDam); }

	 return iDam;
}

boolean MonsterCannotHit(monster eek)
//Test if mob can hit us
{
	return ((monster_attack() + OVERMOXIE_LEVEL) <= my_buffedstat($stat[moxie]) );
}

boolean PlayerCannotHit(monster eek)
//Test if we can hit the mob
{
	return (my_buffedstat(current_hit_stat()) < (monster_defense()+ 7)); //TODO check the 7
}

void PickPocket()
{
	print("Picking pocket...");
	visit_url("fight.php?action=steal");

}

boolean ThrowJunkItem()
{
	item JunkItem;
	JunkItem = $item[scroll of turtle summoning];
	if (bVerbose) { Print("Trying to throw junk..."); }

	if (item_amount(JunkItem)>0)
	{
		throw_item(JunkItem);
		return true;
	}
	JunkItem = $item[seal tooth];
	if (item_amount(JunkItem)>0)
	{
		throw_item(JunkItem);
		return true;
	}
	JunkItem = $item[spices];
	if (item_amount(JunkItem)>0)
	{
		throw_item(JunkItem);
		return true;
	}

	if (bVerbose) { Print("Failed to throw junk."); }
	return false;
}


void FinishHim(monster eek)
{
	if (dbug) { print("Finish Him!"); }
	if (gbInValley)
	//Best to use a dictionary if we can - free
	{
		if (item_amount($item[dictionary])>0)
		{
			if (bVerbose) { Print("Finish with dictionary"); }
			throw_item($item[dictionary]);
		}
		else
		{
			if (item_amount($item[facsimile dictionary])>0)
			{
				if (bVerbose) { Print("Finish with dictionary"); }
				throw_item($item[facsimile dictionary]);
			}
		}
	}
	else
	{
		 Kill(eek);
	}
}

void DontHurtHim(monster eek)
{
	if (bVerbose) { Print("Attack and miss"); }
	if (item_amount($item[anti-anti-antidote])>0 && USE_ANTIDOTE)
	{
	   throw_item($item[anti-anti-antidote]);
	}
	else
	{
		if (item_amount($item[goodfella contract])>0 && USE_GOODFELLA && my_familiar()!=$familiar[Penguin Goodfella])
		{
		   throw_item($item[goodfella contract]);
		}

		else
		{
			if (item_amount($item[dictionary])>0 && !gbInValley)
			{
				throw_item($item[dictionary]);
			}
			else
			{
				if (item_amount($item[facsimile dictionary])>0 && !gbInValley)
				{
					throw_item($item[facsimile dictionary]);
				}
				else
				{
					if (have_skill($skill[shake hands]) )
					{
					use_skill($skill[shake hands]);
					}
					else
					{
						if (buffed_hit_stat() - monster_defense() < -5)
						{
							#attack and miss
							attack();
						}
						else
						//nothing we can do except throw junk, or attack and hit
						{
							if( eek =$monster[procrastination giant] )
								{ kill(eek); }
							else {
								if (!ThrowJunkItem())
								 {	attack(); }
							}					

						}
					}
				}
			}
		}
	}
}


void main(int iRound, monster eek, string sText)
{
// Check this script is worth running!
 if(have_effect($effect[temporary amnesia])>0)
                { cli_execute("abort You've forgotten how to do this!"); }
 if(have_effect($effect[Jabañero Saucesphere])==0)
		{ cli_execute("abort Oops!  You forgot the sauce."); }

//Check if we're poisoned, and don't use our last anti-anti-antidote if we are
if(have_effect($effect[hardly poisoned at all])> 0 ||  have_effect($effect[somewhat poisoned])> 0 || have_effect($effect[a little bit poisoned])> 0)
 {
  if(item_amount($item[anti-anti-antidote])<=1)
  {
   USE_ANTIDOTE=FALSE;
  }
 }
	int iDamTaken=0;
	string sTemp;
	string sName;
	int iStart=0;
	int iEnd=0;


	string sAction;

	// Define correct defense stat
	if (ShieldEquipped() && have_skill($skill[hero of the half-shell]) &&
		( my_buffedstat($stat[muscle]) > my_buffedstat($stat[moxie]) ) )
	{
		gdefenceStat = $stat[muscle];
	    set_property("IllNeoStasis_Hero", "true");
		// if (dbug) { print("Hero!"); }
	}
	else
	{
		gdefenceStat = $stat[moxie];
	    set_property("IllNeoStasis_Hero", "false");
		// if (dbug) { print("Zero :("); }
	}


	//Sets appropriate health levels
	// Decide the expected monster damage - first 4 rounds based on calculation, 5th and on based on damage taken this fight 
	// Based on DarthDud's suggestions, added by BDrag0n
	int ExpectedDamage=ExpectedMonsterDamage(eek);
	if(iRound >= 5)
	{
		ExpectedDamage = string_to_int(get_property("IllNeoStasis_MaxDamTaken"));
                if(dbug) { Print ("Expected damage based on this fight is: "+int_to_string(ExpectedDamage)); }
	}	
	
	int MIN_HEAL_THRESHOLD = ExpectedDamage+get_fumble() + SAFETY_NET;  //lowest level to heal at

	int HEAL_THRESHOLD;
	if(my_maxhp()<OOC_HEAL_LEVEL)    {
		HEAL_THRESHOLD = my_maxhp()-15;
		if(have_effect($effect[purple tongue]) > 0)        // allow for purple tongue healing
			{ HEAL_THRESHOLD = HEAL_THRESHOLD-20; }
		if(have_effect($effect[Heart of Orange]) > 0)  // Allow for orange heart healing
			{ HEAL_THRESHOLD = HEAL_THRESHOLD-6; }
		if(HEAL_THRESHOLD < MIN_HEAL_THRESHOLD)      // don't want to drop below the minimum health!
			{ HEAL_THRESHOLD = MIN_HEAL_THRESHOLD; }
	} else {
		HEAL_THRESHOLD = MIN_HEAL_THRESHOLD;      // So if your max health is above the OOC_HEAL_THRESHOLD you want to allow minimal health at the end of battle
	}

	// if(dbug) print("Your heal threshhold is " + HEAL_THRESHOLD);



	// Start the round!
	giRound = iRound;
	print ("++++++++++++++++++++++++++++++++");
        print("Round " + iRound + " vs " + eek);
	#print(sText);
	print ("++++++++++++++++++++++++++++++++");

	gbInValley = (my_location() == $location[valley beyond orc chasm]);
	if (dbug) { print("Valley=" + boolean_to_string(gbInValley)); }
	int MaxDamTaken;

	if (iRound == 1)
	{
		giCurDelevel = 0;
		set_property("IllStasis_Delevel", "0");
		set_property("IllStasis_StartMP", my_mp());
		set_property("IllStasis_StartHP", my_hp());
		bUsedNoodles = false;
		set_property("IllNeoStasis_UsedNoodles", "false");
		gbEnemyNoodled = false;
		set_property("IllNeoStasis_EnemyNoodled", "false");
		set_property("IllNeoStasis_MaxDamTaken", "0");
	}
	else
	{
		giCurDelevel = string_to_int(get_property("IllStasis_Delevel"));
		//if (dbug) { print("giCurDelevel=" + giCurDelevel); }
		bUsedNoodles = string_to_boolean(get_property("IllNeoStasis_UsedNoodles"));
		gbEnemyNoodled = string_to_boolean(get_property("IllNeoStasis_EnemyNoodled"));
		MaxDamTaken=string_to_int(get_property("IllNeoStasis_MaxDamTaken"));

	}


	// Check damage taken

	iStart = index_of(sText, "You lose " );
	if (iStart > 0)
	{
		iEnd = index_of(sText, " hit point", iStart );
	}
	// if (dbug) { print("iStart = " + iStart + "iEnd = " + iEnd); }
	if (iStart > 0 && iEnd > 0)
	{
		sTemp = substring(sText,iStart+9,iEnd );
		iDamTaken = string_to_int(sTemp);
		if (dbug) { print("Took Dam:  " + iDamTaken); }
		if(iDamTaken > MaxDamTaken) { set_property("IllNeoStasis_MaxDamTaken", int_to_string(iDamTaken)); }
	}

	// Check Noodles status
	
	iStart = 0;
	iStart = index_of(sText, MSG_NOODLEBREAK);
	if (iStart > 0)
	{
		gbEnemyNoodled = false;
		set_property("IllNeoStasis_EnemyNoodled", "false");
	}

	// Report on current HP and MP threshholds

        // removed percentages because I prefer absolute numbers - BD
	//int iHPPct;
	//iHPPct = 100*my_hp()/my_maxhp();
	//int iMPPct = 100*my_mp()/my_maxmp();
	//if (dbug) { print("HP = " + iHPPct + "%  (HP=" + my_hp() + "/" + my_maxhp() + ")"); }
	//if (dbug) { print("MP = " + iMPPct + "%  (MP=" + my_mp() + "/" + my_maxmp() + ")"); }
	if (dbug) { print("HP=" + my_hp() + "/" + my_maxhp()); }
	if (dbug) { print("MP=" + my_mp() + "/" + my_maxmp()); }

	//Decide on our action, in reverse priority order

	sAction = "Miss"; //Default

	if (MonsterCannotHit(eek))
	{
		if (dbug) { print("Monster cannot hit..."); }

		if (PlayerCannotHit(eek))
		{
			if (dbug) { print("We cannot hit either...finish"); }
			sAction = "Finish";
		}
		else
		{
			sAction = "Attack";
		}
	}

	// Are we full on MP?  If so, we don't need to draw this out.

	if (my_MP()  >= MANA_MAX)
	{
		//
		if (dbug) { print("We're full on MP!"); }
		if (my_hp()< my_maxhp()-15 && CheckSkill($skill[saucy salve]) == 0)
		{
			// If we are below max HP, might as well burn some MP on healing
			sAction = "Salve";
		}
		else
		{
			sAction = "Finish";
		}
	}


	if (my_hp() < HEAL_THRESHOLD)
	{
		//We're hurting, heal if no higher priority action
		if (CheckSkill($skill[saucy salve]) == 0)
		{
			sAction = "Salve";
		}
	}

	if (giRound == 1 && my_primestat()==$stat[moxie] && index_of(sText, "You get the jump") >= 0)
	{
		sAction = "Pickpocket";
	}

	if (iDamTaken >= DAM_THRESHOLD ||string_to_int(get_property("IllNeoStasis_MaxDamTaken"))>= DAM_THRESHOLD || ExpectedMonsterDamage(eek)>=DAM_THRESHOLD)
	//Too painful!  End fight quickly
	{
		sAction = "Finish";
	}

	// Check to see if the monster is safe

	string safetest=StasisSafe(eek);
	if(safetest!="safe") {
		if (dbug) { print("Monster is not safe!  Result=" + safetest); }
		if(safetest=="finish") {
			sAction="Finish";
		} else {
                        if(safetest=="finishNOW")
                        {
                         if(gbEnemyNoodled)
                         {
                          sAction="Finish";
                         }
                         else
                         {
                          if(checkSkill($skill[entangling noodles])==0 && !bUsedNoodles)
                          {
                           sAction="Noodle";
                          }
                          else
                          {
                           sAction="Finish";
                          }
                         }
			}
		     }
		}



	if (ExpectedDamage > (my_hp() + SAFETY_NET))
	//danger of death - panic
	{
		if(my_maxhp()-my_hp()<=10) {
			sAction = "Salve";
		} else {
			if (dbug) { print("PANIC! : Noodled=" + gbEnemyNoodled + ", UsedNoodles=" + bUsedNoodles); }

			if (gbEnemyNoodled)
			{
				if (my_hp()+10>HEAL_THRESHOLD)
				{
					//heal back to safety level
					if (CheckSkill($skill[saucy salve]) == 0)
					{
						sAction = "Salve";
					}
				}
				else
				{
					sAction = "Finish";
				}
			}
			else
			{
				if (CheckSkill($skill[entangling noodles])==0 && !bUsedNoodles)
				{
					sAction = "Noodle";
				}
				else
				{
					sAction = "Finish";
				}
			}
		}
	}


	if (iRound >= 29)
	{
	   #long enough!
		sAction = "Finish";
	}

	ShowStatusMsg("Action = " + sAction);

	//And finally, perform our action
	if (sAction == "Attack") attack();
	if (sAction == "Finish") FinishHim(eek);
	if (sAction == "Salve") use_skill($skill[saucy salve]);
	if (sAction == "Cleesh") {
		if(CheckSkill($skill[cleesh]) == 0) use_skill($skill[cleesh]);
			else sAction="Finish";
	}
	if (sAction == "Miss") DontHurtHim(eek);
	if (sAction == "Pickpocket") Pickpocket();
	if (sAction == "Noodle")
	{
		use_skill($skill[entangling noodles]);
		set_property("IllNeoStasis_UsedNoodles", "true");
		set_property("IllNeoStasis_EnemyNoodled", "true");
	}
}
 

Attachments

  • NewAshStasis2.ash
    40.3 KB · Views: 85

gemelli

Member
So far, this is looking great! I'll try to find time to play with it over the next few days; my initial reactions are all based on reading, not running. That being said, here are a few things that jumped out at me from an initial review:

(1) get_spell_bonus(): Intrinsic spiciness and Immaculate seasoning only give bonuses to Sauceror spells. You might want to consider adding a what_type parameter to the function call (as you've done below in get_elemental) to handle this.

(2) Choose_skill(): Do you really need to pass WhichSkill and my_myst as parameters to this function? You start the function by setting WhichSkill to $skill[none], which I think eliminates any benefit to having it as a passed variable :) And of course, my_myst can be deduced by a native ASH function call from within this function. But overall, I really, really like this function. (Have you considered moving the CLEESH/stream fallback option selection from the end of the Kill() function to this one?)

(3) main(): This is partly my fault, but please remove the colon after the two instances of "abort:" at the start of the main function.

(4) Kill(): I'd add the Apathetic Lizardman and the Acid Blob as two more monsters you don't want to hit with physical attacks.

(5) StasisSafe(): I think this function can now be greatly simplified, since the only interesting results coming out of it should be "finish" or "safe." This applies to the handling of StasisSafe's results in main() as well.
 

BDrag0n

Member
[quote author=gemelli]
(1) get_spell_bonus(): Intrinsic spiciness and Immaculate seasoning only give bonuses to Sauceror spells.  You might want to consider adding a what_type parameter to the function call (as you've done below in get_elemental) to handle this.[/quote] Oops, I wasn't adding *any* spell bonus to pasta spells. Fixed.

[quote author=gemelli](2) Choose_skill(): Do you really need to pass WhichSkill and my_myst as parameters to this function?  You start the function by setting WhichSkill to $skill[none], which I think eliminates any benefit to having it as a passed variable :)  And of course, my_myst can be deduced by a native ASH function call from within this function.  But overall, I really, really like this function.  (Have you considered moving the CLEESH/stream fallback option selection from the end of the Kill() function to this one?)[/quote]
I guess not. WhichSkill being set to none at the start of the function was an attempt to prevent it looping if you've not enough mana to use any of the selected skills - haven't had a chance to test if that works yet!

I'm not moving the fallback options in here because the function is called twice, the second time is to look at a 2-hit kill if a 1-hit isn't possible. Moving the fallback options in here would mean it *always* returns something, so would never look at a 2-hit kill.

[quote author=gemelli](3) main(): This is partly my fault, but please remove the colon after the two instances of "abort:" at the start of the main function.[/quote] Done. I guess it's aesthetics - it looks better in the script with the colon, but better in the gCLI without ::)

[quote author=gemelli](4) Kill(): I'd add the Apathetic Lizardman and the Acid Blob as two more monsters you don't want to hit with physical attacks.[/quote] Acid blod added, but Mafia failed to recognise the Lizardman - I'll report that and add it back ASAP.

[quote author=gemelli](5) StasisSafe(): I think this function can now be greatly simplified, since the only interesting results coming out of it should be "finish" or "safe."  This applies to the handling of StasisSafe's results in main() as well.
[/quote]I've left "finishNOW" as well, since that noodles before trying to kill.

Changes have been edited into the post above.
 

BDrag0n

Member
[quote author=holatuwol link=topic=799.msg4329#msg4329 date=1177549558]

int monster_attack(): Added
int monster_defense(): Added
int monster_hp(): Added


[/quote]
I assume the above are meant to be "current" stats, bearing in mind current +ML? Quick testing shows that the monster_attack() at least is giving the same as monster_base_attack(). Monster_hp() does give the current value, I believe.
 

holatuwol

Developer
[quote author=BDrag0n link=topic=799.msg4370#msg4370 date=1177852646]I assume the above are meant to be "current" stats, bearing in mind current +ML?[/quote]

I forgot that ML adjusted those values. Fixed.
 

gemelli

Member
A few minor changes in this version:

# v2.1- Added tracker for damage dealt via spheres, reducing MP requirements for Kill(). Added
# "poke" action to address cases where we have full MP, full HP, and want to do something --
# previously, Kill() would be called at a potentially high MP cost. Added debug() function
# to simplify debugging calls.

I noticed that Kill() was defaulting to overkill spells a little too often for my tastes, so this was my attempt to rein that function in a bit :)

Let me know if you have any questions/comments.
 

Attachments

  • NeoStasis.ash.txt
    40.8 KB · Views: 90

macman104

Member
I just wanted to say that while I have not used, nor plan to use this script right now, it is by far one of the more impressive scripts, and I've really liked watching it develop.
 

BDrag0n

Member
[quote author=gemelli link=topic=799.msg4422#msg4422 date=1178213729]
A few minor changes in this version:
[/quote]
Yeah, the "poke" is a good call - I hadn't noticed because I've only *got* stream and LTS <g>.

Re: tracker for sphere damage - my understanding is that monster_hp() returns the monster's current HP, including damage done - so I'm not sure about this - surely it would result in double-counting damage from spheres?

That being said I've failed to track down a bug where Kill() drastically under-counted the damage to be done, which I had thought to be +ML related but now can't duplicate :-(
 

gemelli

Member
[quote author=BDrag0n link=topic=799.msg4424#msg4424 date=1178224541]Yeah, the "poke" is a good call - I hadn't noticed because I've only *got* stream and LTS .[/quote]
Trust me, the first time you cast Wave of Sauce on round 29 vs. a drunk goat, you will sit up and notice :D

Re: tracker for sphere damage - my understanding is that monster_hp() returns the monster's current HP, including damage done - so I'm not sure about this - surely it would result in double-counting damage from spheres?
Nope ... I just added a test line to the round info area -- print("Monster HP: "+monster_hp()); -- and ran the script in the Friars'.  Although I was dealing damage every round, monster_hp() did not change.  So that function seems to return the base HP for the monster, not current.

That being said I've failed to track down a bug where Kill() drastically under-counted the damage to be done, which I had thought to be +ML related but now can't duplicate :-(

Hm, I'll keep an eye out for that one.  Hopefully, the debug line I added near the front of Kill() should help a little.
 

illarion

Member
Had a little time to do some testing. This is for v2, since I hadn't seen 2.1 yet :)

v2 got stuck looping round and round. gCLI output was:

++++++++++++++++++++++++++++++++
Round 29 vs irritating series of random encounters
++++++++++++++++++++++++++++++++
Valley=false
HP=21/247 MP=71/112
You have 0% elemental resistance
Round: 29 (MP Change=48, HP Change=-122) --> Action = Finish
Finish Him!
Kill: need to do 140 points of damage in one turn.
Don't hit it!
Monster defence is none
You have 0 elemental damage to add for sauce
Monster defence is none
You have 5 elemental damage to add for melee
Monster defence is none
You have 0 elemental damage to add for sauce
Monster defence is none
You have 5 elemental damage to add for melee
Offhand=box turtle-> Shield=true IllNeoStasis_Hero => true
You have 0% elemental resistance
Expected damage based on this fight is: 12

First, 140 points to kill it is wrong - way wrong. (28 rounds of jala + jaba had gone off).
This implies that monster_hp() is not tracking this damage.

Second, the kill logic is obviously getting confused. I have LTS and TS, but no sauce spells - the correct behaviour would be to LTS if it will kill, or TS if not. (Given round 29, I've been stasising, and TS should be fine)

The only program flow that I can see leading to the "Don't hit it!" message is triggered either by specific monsters (not this one though), or the enemy being noodled. I can't tell if it is from the gCLI output (it overflowed), but the settings file suggests it.

Even if this is just bad luck (happening to noodle due to damage right when we ran out of rounds), LTS is still the correct course of action. I'd suggest removing the enemynoodled -> LTS_safe = false logic, except perhaps in the first 5 rounds or something?

----
Started looping again, against a protagonist this time. Definitely noodled - basically, the script doesn't know how to deal with a noodled opponent if you don't have sauce spells.
 

gemelli

Member
[quote author=holatuwol link=topic=799.msg4429#msg4429 date=1178239859]
What does sphere damage look like?
[/quote]

PHP:
Your Jabañero Saucesphere does 5 damage to your opponent, and infuses you with renewed energy.<center><Table><tr><td>[img]http://images.kingdomofloathing.com/itemimages/mp.gif[/img]</td><td valign=center class=effect>You gain 5 Muscularity Points.</td>

That's the code I'm parsing in v2.1, which detects Jabanero but not Jalapeno damage (I rarely use Jalapeno, so it isn't as important to me).
 

Veracity

Developer
Staff member
[quote author=holatuwol link=topic=799.msg4443#msg4443 date=1178303568]
When I perm Jabañero this coming run, I'll look into it.[/quote]
Great minds think alike; I bought Jabañero this run and will perm it when I ascend - in about a month, since I am adventuring my way to L30 and will be gone for a week in the middle. And then on to get other basic stasis skills... :)
 

BDrag0n

Member
[quote author=gemelli link=topic=799.msg4425#msg4425 date=1178227636]

Trust me, the first time you cast Wave of Sauce on round 29 vs. a drunk goat, you will sit up and notice :D [/quote] I'll believe it! <g>

[quote author=gemelli link=topic=799.msg4425#msg4425 date=1178227636]
Nope ... I just added a test line to the round info area -- print("Monster HP: "+monster_hp()); -- and ran the script in the Friars'.  Although I was dealing damage every round, monster_hp() did not change.  So that function seems to return the base HP for the monster, not current.
[/quote] Odd - the line print("Monster has "+monster_hp()+" HP left"); at the start of the round which I was using shows the monster HP decreasing every turn. Are you using the current SVN or the public release?

[quote author=gemelli link=topic=799.msg4425#msg4425 date=1178227636]
Hm, I'll keep an eye out for that one.  Hopefully, the debug line I added near the front of Kill() should help a little.
[/quote]
Ta. I need to spend more time on finding it, but RL is short of that right now.
 
Top