Universal Recovery Script

Bale

Minion
Maybe generalize this to be:
cost = mallprice
onHandCost = max(autosell*2,100)< cost? cost: autosell
(i.e. value onhand items as autosell if it's minpriced in the mall)

The idea does have some merit. I'll mull it over.

Is there something in your script that does manaburning if the setting's on? Like, if manaburning is set to anything but "Do not rebalance", and you're restoring on 100/120 MP, and your most efficient MP restore restores 70-100MP, then manaburn to 50MP before using it. I don't use it, but it would improve efficiency.

Nope. Nothing in this script considers manaburning. Once again there is some merit to the idea, so I will mull it over.

You've given me some things to think about.
 

zarqon

Well-known member
I'm a fan of both Raijinili's proposals. I'm kind of surprised it didn't already use this logic for evaluating item values.

Here's a snippet of some code I use in my logout script which you may want to grab some bits from:

PHP:
int max_castable(skill sk) {      // returns how many times you can possibly cast a given skill (NOT based on current MP)
   switch (sk) {
      case $skill[Advanced Cocktailcrafting]: return 3 + 2*to_int(have_skill($skill[superhuman cocktailcrafting])) - to_int(get_property("cocktailSummons"));
      case $skill[Pastamastery]: return 3 + 2*to_int(have_skill($skill[transcendental noodlecraft])) - to_int(get_property("noodleSummons"));
      case $skill[Advanced Saucecrafting]: return 3 + 2*to_int(have_skill($skill[the way of sauce])) - to_int(get_property("reagentSummons"));
      case $skill[Rainbow Gravitation]: return 3 - to_int(get_property("prismaticSummons"));
      case $skill[Summon Hilarious Objects]: return to_int(get_property("grimoire1Summons") == "0");
      case $skill[Summon Tasteful Items]: return to_int(get_property("grimoire2Summons") == "0");
      case $skill[Summon Snowcones]:
      case $skill[Summon Stickers]:
      case $skill[Summon Sugar Sheets]: return 3 - to_int(get_property("tomeSummons"));
  // candyHeartSummons
   }
   return floor(my_maxmp() / mp_cost(sk));
}

// build list of castable skills
record tskill {
   skill nome;
   int type;
   int irr; int ele; int vent;
};
tskill[int] skills;
file_to_map("classskills.txt",skills);
print("Your castable skills:","blue");
foreach i,s in skills {
   if (!have_skill(s.nome) || (s.type > 4 || s.type < 1 || s.type == 2) ||       // only types 1,3,4 that you have
       max_castable(s.nome) == 0 || i == 45 ||                                   // casting limits, skip vent rage gland
       (s.type > 2 && to_effect(s.nome) != $effect[none] && have_effect(to_effect(s.nome)) > 2000)) {  // skip buffs you have too much of
      remove skills[i]; continue;
   }
   print(i+": "+s.nome + " ("+mp_cost(s.nome)+" MP) -- "+to_effect(s.nome));
}
boolean burn_to(int target) {     // only returns true if burning occurred!
   target = minmax(target,0,my_maxmp());
   if (target == my_maxmp()) return false;
   if (my_mp() <= target) return false;
   print("Burning down to "+target+" MP...");
   int init = my_mp();
   cli_execute("burn extra -"+target);
   if (my_mp() <= target) return true;
   int mpflag;
   repeat {
      mpflag = my_mp();
      foreach i,s in skills {
         if (i > 6000 && i < 6028 && (have_effect(to_effect(s.nome)) == 0 ||    // skip AT buffs you don't have or have too much of
            have_effect(to_effect(s.nome)) > 2000)) continue;
         if (max_castable(s.nome) > 0 && my_mp() >= mp_cost(s.nome)) use_skill(1,s.nome);
         if (my_mp() <= target) return true;
      }
   } until (mpflag == my_mp());
   return (my_mp() != init);
}

This is slow and server-unfriendly for burning a lot of MP on a just a few cheap skills -- it needs to be reworked to calculate everything predictively and then multicast. But it's a decent starting point.
 

Raijinili

Member
Actually, both ideas are just heuristics, and there are probably cases where it can make things worse, as is often the case with adding heuristics. Adding more heuristics for an unsolvable problem is usually how you do things, no?

For example, I just thought of an issue with this: would it mark NPC items as lower value than they actually are? The idea that something's value is less than the cost to replace it, if it SHOULD be replaced, is kind of iffy. I don't know a logical reason for distinguishing between NPC and mall items like that. I guess it's more logical (though more of a pain) to distinguish between drops (moths and shards) and things you specifically have to go out of your way to get (like NPC items).

And if you're intentionally buying min-price healers (though I guess you shouldn't if you're using this script), the heuristic would value them as twice as efficient as you thought they were when you bought them.

Nuns and free naps might also take on the logic of the sugar shard/moth, since they're free-but-limited, just like the shard.
 

tebee

Member
Having been working for a few days it decided to crash on one of my characters today with "Bad item value: "knob seltzer" (Universal_recovery.ash, line 701)"

I assume this should be "knob Goblin seltzer"

Incidentally this looks as if it run when you are in hardcore, my char wasn't.

Fixing this also found

Bad item value: "knob seltzer" (Universal_recovery.ash, line 947)
Bad item value: "Yendorian Express" (Universal_recovery.ash, line 987) +989
Bad item value: "medicinal herbs" (Universal_recovery.ash, line 1047)

Which left me a little confused shouldn't some of those partial match have worked?
 

slyz

Developer
Did you update to a recent revision? If so, which one?

EDIT: scratch that, I'm running r9163 and didn't have the problem:
Code:
> ash $item[knob seltzer]

Returned: Knob Goblin seltzer
fullness => 0
inebriety => 0
spleen => 0
notes =>
descid => 861990863
levelreq => 0
 
Last edited:

Bale

Minion
Bad item value: "knob seltzer" (Universal_recovery.ash, line 947)
Bad item value: "Yendorian Express" (Universal_recovery.ash, line 987) +989
Bad item value: "medicinal herbs" (Universal_recovery.ash, line 1047)

I've noticed that under some unclear circumstances mafia's partial matching fails. Most of the time those lines work perfectly. If you quit and restarted mafia the script would work again. I don't know why this is.
 

lostcalpolydude

Developer
Staff member
I've noticed that under some unclear circumstances mafia's partial matching fails. Most of the time those lines work perfectly. If you quit and restarted mafia the script would work again. I don't know why this is.

The script could handle those situations anyway by using full item names. You never know when KoL will add new items that make those shortened names match something completely different.
 

Bale

Minion
I agree. I already added the full names just for the heck of it in case such a problem pops up again. I'm not rolling out a release for that though.
 

Raijinili

Member
I don't know if you know this, but your script's 20-second pause makes outgoing (maybe also incoming) chat buffer, and as a stack rather than a queue.

I'm not thinking enough whether this belongs as a bug report, because I don't know what you're using to pause.
 

Bale

Minion
Then Theraze was honestly puzzled because he knows nothing about a second pause and neither do I. Can you explain when/why this script has a 20 second pause? Is there something in the CLI that would give someone a hint why this script paused?

Also, what unexpected and unwanted behavior with chat is occurring? I'm quite curious to discover how there is some interaction. I can't imagine how my script can do anything that would interfere with chat so please inform me!
 

Theraze

Active member
Yes... any script that uses the zlib update notification have a 20 second pause. If that's the complaint that Raijinili has, he can either remove the update notification, or update. Either will fix the update-pause issue.

However, his post 1231 suggests one of the following: some other non-update part of UR is causing a 20 second pause, he wants Bale to come to his computer and download the updated version of UR for him, or he wants Bale to give him a version without update notification. Options 2 and 3 are somewhat crazy, so that leaves some mystery 20 second pause in his script which hasn't been fully described yet...
 

slyz

Developer
The point isn't that the pause is happening, it's the fact that his chat seems stuck during the countdown. I have never experienced this though, so maybe I misunderstood. It probably deserve its own bug report.
 

Theraze

Active member
Does a wait() execution pause chat normally? If you run ashq wait(60) through the gCLI and someone chats, do you see it, or does it pause? I don't have anyone reliable to talk to and test it.
 

Bale

Minion
I've never seen wait() cause a pause in chat. And he specifically stated in post 1231 that it is not paused because he needs an update. Let's wait for Raijinili to give us more information before jumping to conclusions.
 

bumcheekcity

Active member
Code:
Request 1 of 37 (Woods: Hidden Temple) in progress...

[54] Hidden     Temple
Encounter: Rolling Stone Trap
You lose 53 hit points

Restoring     MP! Currently at 0 of 104 HP, 0 of 64 MP, current meat: 1148 ... Target MP     = 10.
Visiting Doc Galaktik...

Restore 10 MP at Doc     Galaktik's
You gain 10 Muscularity Points
You spent 170 Meat
Cure     purchased.
Casting Tongue of the Walrus 1 times...
You gain 33 hit     points
You lose an effect: Beaten Up
Tongue of the Walrus was     successfully cast.

Curing Beaten Up in the Hidden Temple is, I suggest, a tad unnecessary. Is this the script or mafia auto-removing malignant effects?

If I turn off autoremove malignant effects, will the UR script remove them at appropriate places instead?
 
Top