Bug - Fixed Remove certain unnecessary functions from ASH's runtime library

Veracity

Developer
Staff member
This Feature Request made we realize that ASH has some unnecessary functions in its runtime library.

We have the following functions to translate between certain ASH types and KoL's internal ID for objects of that type.

to_int(item) : yes
to_int(familiar) : yes
to_int(skill) : yes
to_int(effect) : yes

Each of the above also has the reverse translation:

to_item(int) : yes
to_familiar(int) : yes
to_skill(int) : yes
to_effect(int) : yes

These are useful functions, since scripts can use the object ID numbers to construct URLs to manipulate the appropriate objects.

Certain ASH types do not have a to_int translation, since there is no KoL ID number corresponding to them:

to_int(location) : no
to_int(monster) : no
to_int(coinmaster) : no

However, there are 4 ASH data types that have a to_int (and recently, a corresponding reverse translation function), even though such a number is arbitrarily assigned by ASH and is useless for actually interacting with KoL:

to_int(element) : yes
to_element(int) : yes
to_int(stat) : yes
to_stat(int) : yes
to_int(class) : yes
to_class(int) : yes
to_int(phylum) : yes
to_phylum(int) : yes

I would like to simplify ASH by removing those eight functions. They do not help scripts interact with KoL, since KoL uses no such numbers. They do not provide anything that a script cannot do itself without help from ASH.
 

Veracity

Developer
Staff member
Why not? They only have integers associated with the enum values - the string - because we have the set of values built into a table in ASH itself and we can easily translate the string representation of the object into a table index.

"monsters" and "locations" are defined outside of ASH in a data file and are maintained in hash tables or maps or lists or what have you elsewhere. Ditto for "coinmasters". There is a table of all coinmasters in CoinmasterRegistry.java. We could make that table the "natural" order of coinmasters - but why? Why is it useful to know that Big Brother is coinmaster #3? What can a program do better or easier with "coinmaster #3" vs. $coinmaster[ big brother ]? And what happens to such a program when I add a new coinmaster in front of Big Brother and Big Brother suddenly becomes coinmaster #4?

ASH's "switch" statement doesn't require integers. ASH (and KoLmafia and KoL) itself do not treat the data types I called out as integers. Why does ASH need to provide a way to translate "element #3" into $element[ sleaze ] (or whatever)? If your ASH program "knows" that mapping and passes around the integer 3 and then translates it via to_element to get "sleaze", your program will break if I go in and shuffle the table of elements - which I should be able to do, since the order is completely arbitrary. That is completely different from getting an inv_use.php URL, extracting the whichitem field from it, and using to_item on the resulting number to find out which item is being manipulated.

I would like a script writer to explain exactly how being able to do to_int( element) is useful and lets them do something they otherwise couldn't do. I want to see some Use Cases to justify keeping to_int for types for which there is no "natural" order, or one required by KoL itself.
 
Last edited:

Fluxxdog

Active member
I would like a script writer to explain exactly how being able to do to_int( element) is useful and lets them do something they otherwise couldn't do. I want to see some Use Cases to justify keeping to_int for types for which there is no "natural" order, or one required by KoL itself.
For element and phylum, I have to agree, there's nothing to really dictate order or numbers, which is what converting it to an integer would provide.
Classes, however, do have a predefined order, though the numbering in mafia seems odd from a certain point of view.
Code:
> ash foreach c in $classes[] print(c+"="+to_int(c))

Seal Clubber=0
Turtle Tamer=1
Pastamancer=2
Sauceror=3
Disco Bandit=4
Accordion Thief=5
Avatar of Boris=6
Returned: void
The wiki page Skills by Number shows that skills themselves have an order and orginization based on class. However, 1xxx skills are Seal Clubber, 2xxx are Turtle Tamer, etc. Avatar skills are 11xxx, not 6xxx. If to_int(class) is kept, it might be appropriate to solidly define their values. However, as $skill.class is a proxy field that returns a $class, there's really no need for class numbers.

to_int(stat): I've had several uses in my scripts. This is one of the simplest:
(stat_focus() determines which stat I'm trying to increase, based on several factors.)
Code:
set_property("louvreDesiredGoal",3+to_int(stat_focus()));
This adjusts my goal in the Louvre based on what stat I'm trying to increase. Because of mafia's internal coding, this makes it very easy to adjust as needed. Again with:
Code:
choice(402,to_int(stat_focus()));
Like the Louvre, it chooses the appropriate stat for "Don't Hold a Grudge" (Haunted Bathroom). While stats don't have assigned numbers in KoL in the strictest sense, there has been IMO an understood order of Muscle being First, Mysticality being Second, and Moxie being third.
 

holatuwol

Developer
I think Veracity's point is that because there's no KoL meaning to the numbers, there's no reason KoLmafia should give special numbers to them that scripters should rely on. If scripters need a meaning, they should create their own function that provides that meaning.

Let's say for example, KoL introduces a new stat "Maplesyrupicity" that appears above Muscle in the list of stats. Our natural fix would be to just add it right at index 0. But, what of to_int()? If each script comes up with its own meaning, they can handle it and add it as 4, ignoring the fact that KoLmafia made it 0.
 

Veracity

Developer
Staff member
Exactly.

As Fluxxdog points out, KoL itself numbers classes, with Seal Clubber as 1, Turtle Tamer as 2, Avatar of Boris as 11 and so on, which you can see in skill numberings (class * 1000 is the range of skills for the class) and in the JSON string returned by api.php and the string you submit to reincarnate from Valhalla. I think that's justification for us to have to_int() for classes - but the ints should be 1, 2, 3, 4, 5, 6, and 11.

Now, we do internally have some reliance on Mus/Mys/Mox being 0/1/2 - the whole "primeIndex" thing we do in KoLCharacter. Well, we rely on stats being numbered 0 1 and 2, so we can index arrays with them. But KoL does not reveal those numbers to you. Often, if KoL introduces a new set of 3 effects, say - one for each stat - they will be ordered Mus/Mys/Mox - but there are plenty of counterexamples.

So, I've changed my mind for classes, since those DO have KoL-visible standards. I still think the other types are arbitrary.

If scripters want a "standard" meaning, they can always use zlib, say, which was specifically created to provide commonly desired utility functions that KoLmafia itself does not provide. :)
 

holatuwol

Developer
10691 should make it easier to remove the ones where to_int() has no meaning, but I'll leave which ones those are up for debate.
 

Fluxxdog

Active member
Now, we do internally have some reliance on Mus/Mys/Mox being 0/1/2 - the whole "primeIndex" thing we do in KoLCharacter.
Wait, something's off...
Code:
> ash foreach s in $stats[] print(s+"="+to_int(s))

Muscle=1
Mysticality=2
Moxie=3
Returned: void

> ash to_int($stat[none])

Returned: -1
What happened to 0?
 

holatuwol

Developer
Heh, this is an example where the ASH to_int() is different from the way KoLmafia indexes. The ASH ones correspond to constants we'd added for zodiac signs, the ones KoLmafia uses internally in the arrays we use to record your stat values aren't related to those values at all.
 

StDoodle

Minion
For the record, I got a bit confused by the behavior of to_int() when I was overhauling the wiki. Couldn't quite grok which castings were "KoL's way" and which were specific to mafia. In other words, I'm all for removing any that aren't the former, as I think it just leads to similar confusions, and scripters thinking they can rely on such values as being "safe" when they aren't really dictated by KoL.

Of course, it's not as if KoL itself has never made changes that broke behavior that was previously considered "safe," but that's just the nature of the beast. ;)
 

zarqon

Well-known member
These numbers may be useless for interacting with KoL, but they are useful for interacting with the data itself, since when iterating values, for instance, odd numbers can be skipped. Likewise, using < and >, ranges can be skipped. Other mathematical operations can be performed which cannot be performed on typed constants.

I grepped my scripts folder, so I could be prepared to fix what this might break, and found some examples. First, one from RandBot:

PHP:
return to_skill(1000*(my_class().to_int())); // out of buffs? cast your trivial skill

That's a very handy way to get your class's trivial buff. Now, some instances in BatBrain:

PHP:
fvars["fweight"] = familiar_weight(my_familiar()) + weight_adjustment() + min(20,2*my_level())*to_int(to_int(my_class())+82 == to_int(my_fam()));

That's a handy way to account for the nemesis familiars being effectively Level*2 heavier for the appropriate class.

PHP:
return ceil(to_int(to_skill(to_int(excise(aid,"skill ",""))).class)/2.0).to_stat();  // classy gays

That actually uses two of the proposed functions for removal, to find out in a single formula which stat a given skill belongs to.

PHP:
foreach n,st in sts res.stats[to_stat(n+1)] = eval(st,fvars); break;

That iterates the results of a split_string() to assign the results to a float[stat] map, using one arbitrary integer to assign to another, for great handiness.

I think you may have noticed the word "handy" recurring above. That's my first argument for retaining them, an argument for the scripters.

My second argument is an argument for the devs concerning design and the appropriateness of associating integers with these types -- stats and classes do have an order specified by KoL. They are always listed in that order, despite no integer being explicitly associated with them. The integers associated with class skills follow that order as well. You'll also notice that all of my above examples used only these two types. The arbitrary integers associated with elements and phyla have yet to see a use for me personally. There may be such a use, but the case for retaining integers with phyla and elements is certainly weaker than the case for stats and classes, where a consistent order is clearly promulgated by KoL.

My last argument is for the users. Removing these functions from ASH may lead to confusion as scripts silently break -- scripts currently using to_type(int) for any of these types will simply start returning none, rather than the previous values, with no explanation that there was a change. Previously functional code will stop working as intended, despite being free of errors.

For those script authors using ZLib, if all eight of these are removed I will probably want to add at least stats and classes back into ZLib, so as to keep the handiness they have provided to my scripts thus far. So, for those authors, the only problem would be the transition period, wherein ZLib users who update one before the other (mafia or ZLib) will have problems and likely increase the ZLib thread by a few more pages. But for authors not importing ZLib, they will have to come here to find out what went wrong with their scripts -- if they even notice it went wrong!

Are any of these arguments compelling?

EDIT: Hmmm, many ninjas were afoot while I compiled this message. But the ninjas seem to agree with me, at least mostly. Also, as I was writing this I noticed that to_class(int) now returns 1-6 instead of 0-5, so I edited the above code snippets accordingly.
 
Last edited:

Veracity

Developer
Staff member
These numbers may be useless for interacting with KoL, but they are useful for interacting with the data itself, since when iterating values, for instance, odd numbers can be skipped. Likewise, using < and >, ranges can be skipped. Other mathematical operations can be performed which cannot be performed on typed constants.
Excellent. Now explain why the functions should be provided by KoLmafia, rather than by, for example, zlib.

I grepped my scripts folder, so I could be prepared to fix what this might break, and found some examples. First, one from RandBot:

PHP:
return to_skill(1000*(my_class().to_int())); // out of buffs? cast your trivial skill

That's a very handy way to get your class's trivial buff.
Uh huh. And if you are an Avatar of Boris, it will cast Mighty Axing, a combat skill.

Now, some instances in BatBrain:

PHP:
fvars["fweight"] = familiar_weight(my_familiar()) + weight_adjustment() + min(20,2*my_level())*to_int(to_int(my_class())+82 == to_int(my_fam()));

That's a handy way to account for the nemesis familiars being effectively Level*2 heavier for the appropriate class.
to_int(to_int(my_class())+82 == to_int(my_fam()))

I call that "tricky" - otherwise known as "incomprehensible" code. You are coercing a class to an integer - and classes are numbered 1,2,3,4,5,6,11 (does your code work as an Avatar of Boris? Well, that class has no familiars, so it is moot) and making a boolean comparison, and are then coercing the boolean to 0 or 1 and using that in arithmetic.

I consider that to be bad code.

You want to see if a familiar is your classes's Nemesis familiar? Rather than use hackery like the above, make a map from class -> familiar and load it with the 6 familiars.

PHP:
return ceil(to_int(to_skill(to_int(excise(aid,"skill ",""))).class)/2.0).to_stat();  // classy gays

That actually uses two of the proposed functions for removal, to find out in a single formula which stat a given skill belongs to.
More incomprehensible "tricky" code. How about a map from class -> stat?

PHP:
foreach n,st in sts res.stats[to_stat(n+1)] = eval(st,fvars); break;

That iterates the results of a split_string() to assign the results to a float[stat] map, using one arbitrary integer to assign to another, for great handiness.
I do not understand what you just said - or what your code is doing.

I think you may have noticed the word "handy" recurring above. That's my first argument for retaining them, an argument for the scripters.
Excellent. Put them in zlib!

My second argument is an argument for the devs concerning design and the appropriateness of associating integers with these types -- stats and classes do have an order specified by KoL.
Classes do, as discussed in the other thread, but stats do not.

They are always listed in that order, despite no integer being explicitly associated with them.
Wrong. Consider the following three successive status effects:

847 Spell Transfer Complete - Experience (Mysticality): +5
848 Overstimulated - Experience (Muscle): +5
849 Simulation Stimulation - Experience (Moxie): +5

I expect you would want to write "tricky" code to do "to_effect( 847 + to_int( stat ) )" to get the effect that boosts the stat - except that wouldn't work, would it, since stats are most certainly NOT always in the same order.

The integers associated with class skills follow that order as well.
Yes for class. There IS a KoL-assigned number for those - and we now use them. The numbers are 1, 2, 3, 4, 5, 6, and 11.

The arbitrary integers associated with elements and phyla have yet to see a use for me personally. There may be such a use, but the case for retaining integers with phyla and elements is certainly weaker than the case for stats and classes, where a consistent order is clearly promulgated by KoL.
And I am sure you could write a to_int( element), should you need one.

My last argument is for the users. Removing these functions from ASH may lead to confusion as scripts silently break -- scripts currently using to_type(int) for any of these types will simply start returning none, rather than the previous values, with no explanation that there was a change. Previously functional code will stop working as intended, despite being free of errors.
Silently break? I think the compile error preventing the script from executing would be pretty obvious.

For those script authors using ZLib, if all eight of these are removed I will probably want to add at least stats and classes back into ZLib, so as to keep the handiness they have provided to my scripts thus far. So, for those authors, the only problem would be the transition period, wherein ZLib users who update one before the other (mafia or ZLib) will have problems and likely increase the ZLib thread by a few more pages. But for authors not importing ZLib, they will have to come here to find out what went wrong with their scripts -- if they even notice it went wrong!
The compile errors would make it obvious.

Are any of these arguments compelling?
Not especially.

EDIT: Hmmm, many ninjas were afoot while I compiled this message. But the ninjas seem to agree with me, at least mostly. Also, as I was writing this I noticed that to_class(int) now returns 1-6 instead of 0-5, so I edited the above code snippets accordingly.
No, to_int( class) returns 1, 2, 3, 4, 5, 6, or 11.
 

holatuwol

Developer
Silently break? I think the compile error preventing the script from executing would be pretty obvious.
The compile error was only recently added. The lack of the compile error for things like locations is what prompted the other thread that spawned this one. :)

Additionally, since we haven't actually removed support for them yet, nobody's seeing compile errors at this time, so it's understandable that nobody knows that the scripts do not just silently break.
 
Last edited:

Fluxxdog

Active member
My second argument is an argument for the devs concerning design and the appropriateness of associating integers with these types -- stats and classes do have an order specified by KoL.
Classes do, as discussed in the other thread, but stats do not.
I think with Veracity's state of mind, the only way to keep stats off the chopping block is to find a coded case in KoL that defines Mus/Mys/Mox as 1/2/3 or similar, such as a "whichstat=" as part of a URL. If anything, what about PvP? You have to select 1 stat before jumping in to PvP, and even then, it's choosing an attack option, not necessarily a stat.
 

bumcheekcity

Active member
My only concern with this is that it's caused [or will cause[ confusion among people who aren't computer-literate as scripts break without obvious reason, and updating mafia obviously doesn't help.

While ADDING these functions would certainly seem a little strange, the fact that we've had them for ages, people have used them in many scripts and they're pretty useful in some (admittedly, pretty niche) circumstances, taking them away seem to just create unnecessary work for everyone.
 

zarqon

Well-known member
Excellent. Now explain why the functions should be provided by KoLmafia, rather than by, for example, zlib.

Because if I were a new scripter, I would find it perplexing that to_int() works for some types and not others. Because those numbers exist already, and it's inefficient to add functions to a library script to construct them again. I want to make use of something that exists, not build a slower copy of it and then use that.

But I get it. It's not about the scripters -- it's about the principle of not using arbitrary numbers. I'm glad you were at least persuaded to retain -- even improve -- the functionality for classes.

Uh huh. And if you are an Avatar of Boris, it will cast Mighty Axing, a combat skill.

That script is only run in aftercore, and usually only by classes with buffs.

classes are numbered 1,2,3,4,5,6,11

Which I saw after writing that post, as I mentioned.

You want to see if a familiar is your classes's Nemesis familiar? Rather than use hackery like the above, make a map from class -> familiar and load it with the 6 familiars.

Will that run faster than my "tricky" code? It's certainly longer.

I picked up the something*to_int(condition) habit from writing BatBrain's data files, which use modifier_eval() and thus the entire formula including conditionals must be contained in one expression. I must admit, I quite like the brevity and the fact that it saves declaring a placeholder variable, but it is hackish. Perhaps to your chagrin, I've noticed Bale is using that technique increasingly frequently as well, perhaps for the same reasons I do.

More incomprehensible "tricky" code. How about a map from class -> stat?

So now we need to build maps to replace the heretofore built-in indices you're removing? Since I don't really have a choice, I suppose I should learn to stop feeling bad about it, but it feels so bulky and inefficient -- and the kicker is that it was previously unnecessary. It's like you're taking away my toys.

I do not understand what you just said - or what your code is doing.

In more comprehensible code:

PHP:
float[stat] substatsgained;
string input = "1|0|0";
string[int] parts = split_string(input,"\\|");
foreach index,value in parts {
   substatsgained[to_stat(index+1)] = to_float(value);
}

If you have a faster way of doing this, I'm all ears. Adding replacement int <--> type functions to ZLib would be a step in the "slower" direction, methinks.

Classes do, as discussed in the other thread, but stats do not.

I disagree. I'm quite sure if you asked any KoL player what order the stats go in, they would tell you Muscle -> Mysticality -> Moxie. That's certainly the expectation that all coders -- the people who use ASH -- would have.

Consider the following three successive status effects:

That is irrelevant. Status effects are numbered as they are added -- not in any other meaningful order. Item numbers also contain multiple examples of groups of related items which do not have contiguous item numbers (often to the frustration of scripters).

Further, if you are normal, the order of those status effects bugs you -- because the order they were added is out of order!

I still claim that stats have an official order -- one nicely congruous to the six original classes -- and that order should be reflected in ASH.

Silently break? I think the compile error preventing the script from executing would be pretty obvious.

Ah yes, the heretofore unseen compile errors! :) Yes, that ought to do nicely to prevent confusion.

@bumcheek: Actually, five of the eight functions being considered for removal are fairly recent additions to ASH: four were in fact just added only a few days ago, and the fifth, to_int(phylum), was added when phyla were added. The only real loss here from an "already in use" standpoint would be classes and stats. Veracity has already conceded classes, so at this juncture stats would be the only loss. An error has also been added to prevent the user confusion to which I previously alluded.

EDIT:

I think with Veracity's state of mind, the only way to keep stats off the chopping block is to find a coded case in KoL that defines Mus/Mys/Mox as 1/2/3 or similar, such as a "whichstat=" as part of a URL.

You mean besides the charpane? Hmmm...

Code:
<form action=clan_viplounge.php><input type=hidden name=preaction value=poolgame><input type=hidden name=stance value=1><input class=button type=submit value="Play Aggressively"></form><form action=clan_viplounge.php><input type=hidden name=preaction value=poolgame><input type=hidden name=stance value=2><input class=button type=submit value="Play Strategically"></form><form action=clan_viplounge.php><input type=hidden name=preaction value=poolgame><input type=hidden name=stance value=3><input class=button type=submit value="Play Stylishly"></form>

That's got the 1-2-3, but doesn't actually spell out the stats. Eh, I can probably do better, but it's a start. The shower is also in the correct order, but that's even more implicit.

EDIT EDIT: Interestingly however, the CLI pool command uses stat names and numbers interchangeably; "pool moxie" is the same as "pool 3".
 
Last edited:

bumcheekcity

Active member
I understood that to_float(boolean) was removed. I confess to not having massives of time to devote to scripting, so I may be confusing two issues here.
 

holatuwol

Developer
Taking $element and $phylum out of the picture with 10702, so that the only one we're really talking about is $stat.
 
Top