Zlib: Difference between revisions

From Kolmafia
Jump to navigation Jump to search
imported>Zarqon
→‎String Functions: Update equals()
 
(50 intermediate revisions by 4 users not shown)
Line 3: Line 3:
This page details the use of functions in a script library. The information here is only useful to those who have followed the included steps to make use of these functions; they are not built-in to KoLmafia.
This page details the use of functions in a script library. The information here is only useful to those who have followed the included steps to make use of these functions; they are not built-in to KoLmafia.
}}
}}
== About Zarqon's Useful Function Library ==
== About ZLib ==
Behold, a single function library containing most of zarqon's most useful functions, which will be used by most of his scripts. He grew tired of tweaking a function that was in multiple scripts and making sure he had changed them all. ''It would be nice'', he thought in his customary italics, ''to have it in just one place''.
ZLib is a function library intended to make life easier for both script authors and script users. A more detailed introduction, as well as instructions on installing it and other details, can be found in the [http://kolmafia.us/showthread.php?2072 ZLib thread].


In choosing which functions to include, he has tried to select only those functions which are a) super useful, or 2) needed by another of the included functions. It's a bit less efficient in terms of individual scripts, but in terms of repeated code across a family of scripts it is far simpler.
== String Functions ==
 
== Functions ==


{{HideLink|excise}}{{Function|
{{HideLink|excise}}{{Function|
Line 22: Line 20:
This function returns a portion of the {{pspan|source}} string, from after the first occurrence of {{pspan|start}} to just before the first occurrence of {{pspan|end}}. If either {{pspan|start}} or {{pspan|end}} are missing, it will return an empty string. You can also supply either {{pspan|start}} or {{pspan|end}} as blank strings to specify the actual start or end of the {{pspan|source}} string.
This function returns a portion of the {{pspan|source}} string, from after the first occurrence of {{pspan|start}} to just before the first occurrence of {{pspan|end}}. If either {{pspan|start}} or {{pspan|end}} are missing, it will return an empty string. You can also supply either {{pspan|start}} or {{pspan|end}} as blank strings to specify the actual start or end of the {{pspan|source}} string.


{{HideLink|normalized}}{{Function|
{{HideLink|equals}}{{Function|
name=normalized|
name=equals|
return_type=string|
return_type=boolean|
parameter1={{Param|string|mixvar}}|
parameter1={{Param|string|s1}}|
parameter2={{Param|string|type}}|
parameter2={{Param|string|s2}}|
p1desc={{pspan|mixvar}} is the string to normalize|
p1desc={{pspan|s1}} is a string.|
p2desc={{pspan|type}} is the datatype to normalize to|
p2desc={{pspan|s2}} is the string to compare with {{pspan|s1}}.|
}}
Returns {{pspan|mixvar}}, normalized to the specified KoLmafia {{pspan|type}}, which can be any primitive type or ASH datatype constant. For example, normalized("badger", "familiar") would return "Astral Badger".  It can also normalize comma-delimited lists of any of these types if you specify "list of type" for {{pspan|type}}.  For example, normalized("bloop, dair go, possess") would return "Blooper, Dairy Goat, Possessed Silverware Drawer".
 
{{HideLink|rnum}}{{Function|
name=rnum|
return_type=string|
parameter1={{Param|int|n}}|
}}
{{Function|
name=rnum|
return_type=string|
parameter1={{Param|float|n}}|
}}
{{Function|
name=rnum|
return_type=string|
parameter1={{Param|float|n}}|
parameter2={{Param|int|place}}|
p1desc={{pspan|n}} is a number|
p2desc={{pspan|place}} is the number of decimal places to round to|
}}
Returns your number {{pspan|n}} as a human-readable string. For ints, this means it adds commas where appropriate. For floats, it also rounds to the nearest {{pspan|place}} after the decimal. Default {{pspan|place}} for the float-only version is 2, although it may display fewer digits if they are 0's. Examples: rnum(12580) => "12,580", rnum(3.14152964,3) => "3.142", rnum(4.00008) => "4", rnum(123456789.87654321) => "123,456,789.88". Recommended as a substitute for to_string().
 
{{HideLink|set_avg}}{{Function|
name=set_avg|
return_type=void|
parameter1={{Param|float|to_add}}|
parameter2={{Param|string|which_prop}}|
p1desc={{pspan|to_add}} is the data point to add|
p2desc={{pspan|which_prop}} is the property to add data to|
}}
}}
Useful for adding spading to scripts. Adds one more statistic to an average value being stored in a property. For example, calling this script three times with the values 2, 4, and 6 for {{pspan|to_add}} would result in the property {{pspan|which_prop}} containing "4.0:3", with 4.0 being the average of the three numbers added and 3 being the amount of numbers averaged.
Compares two strings case-sensitively.


{{HideLink|get_avg}}{{Function|
Note: This function was invented when string comparison operators (<code>==</code> and <code>!=</code>) were case-insensitive. As of [https://kolmafia.us/threads/16180-when-parsing-a-bounty-object-in-ash-make-case-insensitive-string-compariso.18981/ r16180], ASH strings are compared case-sensitively, which makes this function no longer necessary.
name=get_avg|
return_type=float|
parameter1={{Param|string|which_prop}}|
p1desc={{pspan|which_prop}} is the property to access|
}}
Returns an average value set by set_avg().
 
{{HideLink|eval}}{{Function|
name=eval|
return_type=float|
parameter1={{Param|string|expression}}|
parameter2={{Param|float [string]|values|ag=t}}|
p1desc={{pspan|expression}} is the base expression|
p2desc={{pspan|values}} is a map of values to replace|
}}
By Jason Harper. Evaluates {{pspan|expression}} as a math expression, and allows you to substitute {{pspan|values}} for variables, as described in much greater detail here. A brief version of this documentation is also included in ZLib. (NB: This section needs more infoz.)


{{HideLink|vprint}}{{Function|
{{HideLink|vprint}}{{Function|
Line 93: Line 45:
parameter3={{Param|int|level}}|
parameter3={{Param|int|level}}|
p1desc={{pspan|message}} and {{pspan|color}} are used as in the function {{f|print}}|
p1desc={{pspan|message}} and {{pspan|color}} are used as in the function {{f|print}}|
p2desc={{pspan|level}} is a verbosity reference|
p2desc={{pspan|level}} controls the return value and specifies the verbosity level of the message|
}}
}}
Wrapper for print() and abort(), prints message depending on vars["verbosity"] setting. It has a boolean return value so it can replace { print(message); return t/f; }
This function is an enhanced version of the ASH function {{f|print}}.  The {{pspan|message}} and optional {{pspan|color}} parameters are exactly like in print(), but the {{pspan|level}} parameter gives you a lot of additional control. Specifically, it allows you to control the return value, specify the verbosity level of the output, and maybe even abort the script.
if level == 0: abort with message
if level > 0: prints message if verbosity >= level, returns true
if level < 0: prints message if verbosity >= abs(level), returns false


First, level controls the return value -- if level is positive, vprint will return true; if negative, it will return false. If level is 0, vprint() will abort with the specified message. You can see now that vprint already replaces both abort() and error(). I recommend using it in place of abort() in case a savvy user wishes to avoid or otherwise handle aborts somehow.
First, the return value.  If level is positive, it returns true.  If negative, it returns false. If level is 0, vprint() will abort with the specified message. You can see now that vprint effectively replaces both {{f|abort}} and print. I recommend it as your go-to function anytime you need to show anything in the CLI, for any reason.


So this takes care of my annoyance with needing brackets and two commands just to return a boolean along with user feedback. How about the verbosity issue?
Having a boolean return value (as opposed to ASH's print returning void) allows you to include helpful information in your script easily, without needing to significantly edit your code.  For example:
{{CodeSample|
code=
<syntaxhighlight>
// add debugging info to an if check:
if (somevar == 2 && vprint("somevar equals 2",10)) dosomething();
// add additional info to a return true/false:
if (everythingsgreat) return vprint("Everything's great!",7);
  else return vprint("Everything is not great.",-7);
</syntaxhighlight>}}


Ladies and gentlemen, there is now a new ZLib setting "verbosity" (integer). If the absolute value of level is more than verbosity, the message will not be printed. This allows users to control the chattiness of scripts, and allows authors to include debug print statements which can be shown by setting verbosity high.
Secondly, level represents the verbosity of the message.  ZLib includes a script setting called "verbosity". Users can adjust this value to specify how verbose they want scripts to be.  If they set it to 1, they want the script to print almost nothing -- only the most important messages.  If they set it to 10, they want it to print a lot of details.  The level of each vprint command thus determines whether or not the message will actually be printed.  If the absolute value of level is more than verbosity, the message will not be printed. For example, a user with the default verbosity of 3 would not see any of the example messages given above.  This allows users to control the chattiness of scripts, and allows authors to include helpful debugging print statements which can be shown by setting verbosity high.


'''Recommendations for Verbosity Levels in vprint()'''
'''Recommendations for Verbosity Levels in vprint()'''
Line 123: Line 81:
This will allow users who want extra levels of detail printed to see that detail without cluttering the CLI for users who don't prefer to see all the details. In addition, it allows users to specify a verbosity of 0 to see ONLY mafia output (no script output at all), which could prove handy.
This will allow users who want extra levels of detail printed to see that detail without cluttering the CLI for users who don't prefer to see all the details. In addition, it allows users to specify a verbosity of 0 to see ONLY mafia output (no script output at all), which could prove handy.


There is also a version of vprint() without the color parameter. The default color is black for positive values of level, and red for negative values. So, basically you don't need to use the version with color unless you want to specify a different color or override the default colors.
The color parameter is optional. If you omit it, the default color is black for positive values of level, and red for negative values. Usually, you won't be calling vprint() with the color parameter, unless you want to specify a different color or override the default colors.


{{HideLink|vprint_html}}{{Function|
{{HideLink|vprint_html}}{{Function|
Line 135: Line 93:
Same as vprint() above, but wraps {{f|print_html}}.
Same as vprint() above, but wraps {{f|print_html}}.


{{HideLink|abs}}{{Function|
{{HideLink|normalized}}{{Function|
name=abs|
name=normalized|
return_type=int|
return_type=string|
parameter1={{Param|string|mixvar}}|
parameter2={{Param|string|type}}|
}}{{Function|
name=normalized|
return_type=string|
parameter1={{Param|string|mixvar}}|
parameter2={{Param|string|type}}|
parameter3={{Param|string|glue}}|
p1desc={{pspan|mixvar}} is the string to normalize|
p2desc={{pspan|type}} is the datatype to normalize to, which can be any primitive type or any typed constant.  You can also specify "list of <type>", for a comma-delimited list of the given type.|
p3desc={{pspan|glue}} is only relevant for lists of a type.  You can specify the delimiter (which could be necessary if dealing with list entries that have commas in them).  Defaults to ", ".|
}}
Returns {{pspan|mixvar}}, normalized to the specified KoLmafia {{pspan|type}}. For example, normalized("badger", "familiar") would return "Astral Badger".  It can also normalize comma-delimited lists of any of these types if you specify "list of <type>" for {{pspan|type}}.  For example, normalized("bloop, dair go, possess", "list of monster") would return "Blooper, Dairy Goat, Possessed Silverware Drawer".
 
{{HideLink|join}}{{Function|
name=join|
return_type=string|
parameter1={{Param|string [int]|pieces|ag=t}}|
parameter2={{Param|string|glue}}|
p1desc={{pspan|pieces}} is a map of strings which you want to join into a single string.|
p2desc={{pspan|glue}} is the string to put between the pieces.|
}}
This function is the opposite of the ASH function {{f|split_string}}.  It joins {{pspan|pieces}} together, inserting {{pspan|glue}} between each piece, and returns the assembly as a single string.  Useful for working with comma-delimited lists (or anything-delimited lists, actually).
 
{{HideLink|list_contains}}{{Function|
name=list_contains|
return_type=boolean|
parameter1={{Param|string|stringlist}}|
parameter2={{Param|string|needle}}|
}}
{{Function|
name=list_contains|
return_type=boolean|
parameter1={{Param|string|stringlist}}|
parameter2={{Param|string|needle}}|
parameter3={{Param|string|glue}}|
p1desc={{pspan|stringlist}} is a glue-delimited string list such as returned by join().|
p2desc={{pspan|needle}} is the entry to check for.|
p3desc={{pspan|glue}} is optional (defaults to ", ") and represents the delimiter for the list.|
}}
Returns true if {{pspan|list}} contains {{pspan|needle}}.  Avoids false positives which could result from using contains_text().
 
{{HideLink|list_add}}{{Function|
name=list_add|
return_type=string|
parameter1={{Param|string|stringlist}}|
parameter2={{Param|string|add}}|
}}
{{Function|
name=list_add|
return_type=string|
parameter1={{Param|string|stringlist}}|
parameter2={{Param|string|add}}|
parameter3={{Param|string|glue}}|
p1desc={{pspan|stringlist}} is a glue-delimited string list such as returned by join() above.|
p2desc={{pspan|add}} is the entry to add to the list.|
p3desc={{pspan|glue}} is optional (defaults to ", ") and represents the delimiter for the list.|
}}
Adds unique entry {{pspan|add}} to a {{pspan|glue}}-delimited {{pspan|list}}, and returns the modified list.  If the entry already exists in the list, another entry will not be added.  For example, list_add("a, b, c","d") would return "a, b, c, d", but list_add("a, b, c", "a") would return "a, b, c", since the entry "a" already exists.
 
{{HideLink|list_remove}}{{Function|
name=list_remove|
return_type=string|
parameter1={{Param|string|stringlist}}|
parameter2={{Param|string|del}}|
}}
{{Function|
name=list_remove|
return_type=string|
parameter1={{Param|string|stringlist}}|
parameter2={{Param|string|del}}|
parameter3={{Param|string|glue}}|
p1desc={{pspan|stringlist}} is a glue-delimited string list such as returned by join() above.|
p2desc={{pspan|del}} is the entry to remove from the list.|
p3desc={{pspan|glue}} is optional (defaults to ", ") and represents the delimiter for the list.|
}}
Removes {{pspan|del}} from {{pspan|glue}}-delimited {{pspan|list}}, and returns the modified list.  It will remove all instances of {{pspan|del}}.  For example, list_remove("a, b, c","a") would return "b, c", and list_remove("a, a, b, b, c, c", "a") would return "b, b, c, c".
 
{{HideLink|rnum}}{{Function|
name=rnum|
return_type=string|
parameter1={{Param|int|n}}|
parameter1={{Param|int|n}}|
}}
}}
{{Function|
{{Function|
name=rnum|
return_type=string|
parameter1={{Param|float|n}}|
}}
{{Function|
name=rnum|
return_type=string|
parameter1={{Param|float|n}}|
parameter2={{Param|int|place}}|
p1desc={{pspan|n}} is a number|
p2desc={{pspan|place}} is the number of decimal places to round to|
}}
Returns your number {{pspan|n}} as a human-readable string, appropriate to the user's computer's region. For ints, this means it adds grouping separators where appropriate. For floats, it also rounds to the nearest {{pspan|place}} after the decimal. Default {{pspan|place}} for the float-only version is 2, although it may display fewer digits if they are 0's. Examples: rnum(12580) => "12,580", rnum(3.14152964,3) => "3.142", rnum(4.00008) => "4", rnum(123456789.87654321) => "123,456,789.88".  Recommended as a substitute for to_string(int).
== Number Functions ==
{{HideLink|abs}}{{Function|
name=abs|
name=abs|
return_type=float|
return_type=float|
parameter1={{Param|float|n}}|
parameter1={{Param|float|n}}|
p1desc={{pspan|n}} is a number of either int or float type.|
p1desc={{pspan|n}} is any number.|
}}
}}
Returns the absolute value of the number {{pspan|n}} in the same datatype as supplied.
Returns the absolute value of the number {{pspan|n}}.  Don't worry if you are working with integers, it will still work just fine.  This function already exists in many programming languages; ZLib makes it handily available in ASH.


{{HideLink|minmax}}{{Function|
{{HideLink|minmax}}{{Function|
Line 158: Line 214:
p3desc={{pspan|max}} is the maximum return value|
p3desc={{pspan|max}} is the maximum return value|
}}
}}
Returns {{pspan|a}}, but no less than {{pspan|min}} and no more than {{pspan|max}}.
Returns {{pspan|a}}, but no less than {{pspan|min}} and no more than {{pspan|max}}. Another function common to many languages.
 
{{HideLink|set_avg}}{{Function|
name=set_avg|
return_type=void|
parameter1={{Param|float|to_add}}|
parameter2={{Param|string|which_prop}}|
p1desc={{pspan|to_add}} is the data point to add|
p2desc={{pspan|which_prop}} is the property to add data to|
}}
Useful for adding spading to scripts. Adds one more statistic to an average value being stored in a property. For example, calling this function three times with the values 2, 4, and 6 for {{pspan|to_add}} would result in the property {{pspan|which_prop}} containing "4.0:3", with 4.0 being the average of the three numbers added and 3 being the amount of numbers averaged.
 
{{HideLink|get_avg}}{{Function|
name=get_avg|
return_type=float|
parameter1={{Param|string|which_prop}}|
p1desc={{pspan|which_prop}} is the property to access|
}}
Returns an average value set by set_avg().
 
{{HideLink|eval}}{{Function|
name=eval|
return_type=float|
parameter1={{Param|string|expression}}|
parameter2={{Param|float [string]|values|ag=t}}|
p1desc={{pspan|expression}} is the base expression|
p2desc={{pspan|values}} is a map of values to replace|
}}
By Jason Harper. Evaluates {{pspan|expression}} as a math expression, and allows you to substitute {{pspan|values}} for variables, as described in much greater detail here. Brief documentation is also included in ZLib. (NB: This section needs more infoz.)
 
== Script Functions ==


{{HideLink|check_version}}{{Function|
{{HideLink|check_version}}{{Function|
name=check_version|
name=check_version|
return_type=string|
return_type=string|
parameter1={{Param|string|software}}|
parameter1={{Param|string|soft}}|
parameter2={{Param|string|property}}|
parameter2={{Param|string|proj}}|
parameter3={{Param|int|thread}}|
p1desc={{pspan|soft}} is the script name, which must match the page source of the {{pspan|thread}} being parsed|
p2desc={{pspan|proj}} is the name of the SVN project name to check.|
p3desc={{pspan|thread}} is the script's thread number on kolmafia.us|
}}
{{Function|
name=check_version|
return_type=string|
parameter1={{Param|string|soft}}|
parameter2={{Param|string|prop}}|
parameter3={{Param|string|this_version}}|
parameter3={{Param|string|this_version}}|
parameter4={{Param|int|thread}}|
parameter4={{Param|int|thread}}|
p1desc={{pspan|software}} is the script name, which must match the page source of the {{pspan|thread}} being parsed|
p1desc={{pspan|soft}} is as above.|
p2desc={{pspan|property}} is used as part of the name of the property saved to user preferences|
p2desc={{pspan|prop}} is used as part of the name of the property saved to user preferences.|
p3desc={{pspan|this_version}} is the version of the script currently running|
p3desc={{pspan|this_version}} is the version of the script currently running|
p4desc={{pspan|thread}} is the script's thread-number on kolmafia.us|
p4desc={{pspan|thread}} is as above.|
}}
}}
Server-friendly once-daily version-checking. If the user hasn't checked yet today, visits the specified {{pspan|thread}} on the kolmafia.us forums to find the current version of your script. The thread must include <nowiki>"<b></nowiki>{{pspan|software}} {{pspan|version}}<nowiki></b>"</nowiki> for the version info to be successfully parsed (using the thread's script's version, which may differ from {{pspan|this_version}}). Optionally, you may include <nowiki>"[requires revision XXXX]"</nowiki> in the post if you want to indicate a required minimum revision of mafia. If a new version is available, alerts the user in large text and provides an update link, then waits for a sufficiently annoying interval in case the user wishes to abort operation to go update the script. The return value is a blank string unless an update is found, in which case it is a <nowiki><div id='versioninfo'></nowiki> containing the update message. This allows this function to work equally well for relay scripts. The current version is stored to a daily property, standardized to <nowiki>"_version_"+</nowiki>{{pspan|property}}. Example:
Server-friendly once-daily version-checking. There are two versions of this function, one for SVN and one for forum threads.  The three-parameter SVN version uses mafia's SVN client to check if a previously checked-out SVN project is current and if not, it updates it automatically, meaning the script will be current the next time it runs.  In the event that a user has checked the option for mafia to automatically update all projects on login, it detects that the script has updated and prints an informative message with a link to the script's kolmafia.us thread -- and if the project is hosted on SourceForge, an additional link to the changelog there.
 
For the four-parameter forum thread version, it visits the specified {{pspan|thread}} on the kolmafia.us forums to find the current version of your script. The thread must include <nowiki>"<b></nowiki>{{pspan|soft}} {{pspan|version}}<nowiki></b>"</nowiki> for the version info to be successfully parsed. Optionally, you may include <nowiki>"[requires revision XXXX]"</nowiki> somewhere in your post if you want to indicate a required minimum revision of mafia. If a new version is available, it alerts the user in large text and provides an update link.
 
The return value of both versions is a blank string unless an update is/was found, in which case it is a <nowiki><div class='versioninfo'></nowiki> containing the update message. This allows this function to work equally well for relay scripts. The current version/revision (and the last date checked) is stored in a data file "zversions.txt". Example:
{{CodeSample|
{{CodeSample|
code=
code=
Line 192: Line 292:
name=setvar|
name=setvar|
return_type=void|
return_type=void|
parameter1={{Param|string|name}}|
parameter1={{Param|string|varname}}|
parameter2={{Param|string|default}}|
parameter2={{Param|mixed|dfault}}|
p1desc={{pspan|name}} is the name of the setting|
p2desc={{pspan|dfault}} can be any primitive or ASH type (e.g. item, effect, coinmaster, etc.), but not an array, map, or record.|
}}
}}
{{Function|
This function ensures that a ZLib script setting called {{pspan|name}} exists.  If not, it adds it and the default value specified in {{pspan|dfault}} to vars_defaults.txt.  Also, if the setting has been changed from its default value, it normalizes the value according to the type of {{pspan|dfault}}, but otherwise does nothing.  Note that this function is for initializing defaults, not for editing existing settings.  That is done by calling ZLib in the CLI or running a setting editor tool such as Prefref Plus.
name=setvar|
 
return_type=void|
{{HideLink|getvar}}{{Function|
parameter1={{Param|string|name}}|
name=getvar|
parameter2={{Param|boolean|default}}|
return_type=string|
}}
parameter1={{Param|string|varname}}|
{{Function|
p1desc={{pspan|name}} is the setting to retrieve the value of|
name=setvar|
return_type=void|
parameter1={{Param|string|name}}|
parameter2={{Param|int|default}}|
}}
{{Function|
name=setvar|
return_type=void|
parameter1={{Param|string|name}}|
parameter2={{Param|float|default}}|
}}
{{Function|
name=setvar|
return_type=void|
parameter1={{Param|string|name}}|
parameter2={{Param|item|default}}|
}}
{{Function|
name=setvar|
return_type=void|
parameter1={{Param|string|name}}|
parameter2={{Param|location|default}}|
}}
{{Function|
name=setvar|
return_type=void|
parameter1={{Param|string|name}}|
parameter2={{Param|monster|default}}|
}}
{{Function|
name=setvar|
return_type=void|
parameter1={{Param|string|name}}|
parameter2={{Param|element|default}}|
}}
{{Function|
name=setvar|
return_type=void|
parameter1={{Param|string|name}}|
parameter2={{Param|familiar|default}}|
}}
{{Function|
name=setvar|
return_type=void|
parameter1={{Param|string|name}}|
parameter2={{Param|skill|default}}|
}}
{{Function|
name=setvar|
return_type=void|
parameter1={{Param|string|name}}|
parameter2={{Param|effect|default}}|
}}
}}
{{Function|
This function returns the value of the specified script setting.  Authors are encouraged to use this rather than a direct vars[] lookup, since values which have not been changed from the default will eventually not be present in vars[].
name=setvar|
return_type=void|
parameter1={{Param|string|name}}|
parameter2={{Param|stat|default}}|
}}
{{Function|
name=setvar|
return_type=void|
parameter1={{Param|string|name}}|
parameter2={{Param|class|default}}|
p1desc={{pspan|name}} is the name of the setting|
p1desc={{pspan|default}} is the default value|
}}
This sets per-character script variables (but only the first time, after that the stored value will be used, rather than {{pspan|default}}). Several interesting possibilities now present themselves to users and script authors.


==== For Users ====
==== For Users ====


* Script settings are now all saved in one place, separate from mafia settings. I've read more than one post wishing that script-defined settings and mafia settings would be separate. This provides a solution.
* Script settings are now all saved in one place, separate from mafia properties. I've read more than one post wishing that script-defined settings and mafia properties would be separate. This provides a solution.
* Script settings are independent from scripts. This means that you will no longer need to edit scripts to adjust your setttings. Further, when you download a script update, the script will use your saved settings and you won't need to reset them!
* Script settings are independent from scripts. This means that you will no longer need to edit scripts to adjust your settings. Further, when you download a script update, the script will still use your saved settings and you won't need to reset them.
* To see all of your current settings, type "zlib vars" in the CLI. To change a setting, type "zlib settingname = value". If you're adjusting threshold, you can use "up" or "down" as the value to adjust your threshold relatively. This is almost exactly as convenient as mafia settings (possibly more so since you don't need to open a text file to find setting names!).
* To see all of your current settings, type "zlib vars" in the CLI. You can also type "zlib <whatever>" to see a list of current settings and values containing <whatever>.  To change a setting, type "zlib settingname = value". If you're adjusting threshold, you can use "up" or "down" as the value to adjust your threshold relatively. This is almost exactly as convenient as mafia properties (possibly more so since you don't need to open a text file to find setting names!).
* If for some reason you prefer to open a text file, ZLib settings are stored in a file called vars_myname.txt in your data directory.
* If for some reason you prefer to open a text file, all ZLib setting default values are stored in vars_defaults.txt in your data directory.  Your character's ZLib settings that have been changed from default are stored in a file called vars_myname.txt in your data directory.
* Scripts that use this feature will add more settings, but not until after you run them once. Script documentation should tell you which settings to change to get your desired behavior.
* Scripts that use Zlib script settings will initialize the settings -- saving their default value and type in vars_defaults.txt -- when you run them for the first time.  Attempting to edit a nonexisting setting won't work, so you'll need to run a script once (then, usually, mash the ESC key before it actually does anything) before you can configure it. Script documentation should tell you which settings to change to get your desired behavior.


==== For Script Authors ====
==== For Script Authors ====


* Script settings may now be used across scripts, in exactly the same way that mafia settings are. Basically, this works almost exactly like mafia settings, except that new settings can only be created by setvar() or manually editing the file ("zlib nonexistentsetting = value" will fail).
* Use setvar() to initialize a setting that your script will reference.  To reference the setting, use getvar() and convert from string to whichever type the setting is supposed to be.  Accessing vars[] or vardefaults[] directly is not recommended, as a value may exist in one but not the other, or both.
* Script settings may now be used across scripts, in exactly the same way that mafia properties are. Basically, this works almost exactly like mafia properties, except that new settings can only be created by setvar() or manually editing the file ("zlib nonexistentsetting = value" will fail).
* Settings are only stored if you run a script that defines/uses them. So your settings file will not contain any extraneous unused settings.
* Settings are only stored if you run a script that defines/uses them. So your settings file will not contain any extraneous unused settings.
* Script authors can now test for a setting's existence, which means you can check to see if a user has used a given script. It's almost as good as a script_exists() function. This can allow scripts to work together with other scripts, if they exist!
* Script authors can now test for a setting's existence in vardefaults[], which means you can check to see if a user has used a given script. It's almost as good as a script_exists() function. This can allow scripts to work together with other scripts, if they exist!
* Scripts with overlapping or related functionality can be designed to access a single shared setting, in much the same way that my scripts have until now all shared a "threshold" mafia setting. Changing a single setting can now change the behavior of every script that accesses that setting.
* Scripts with overlapping or related functionality can be designed to access a single shared setting, in much the same way that my scripts have until now all shared a "threshold" mafia setting. Changing a single setting can now change the behavior of every script that accesses that setting.
* Settings are intended to be set only by users, not scripts.  If you want a persistent variable that a script will use, consider static variables.  However, there may be cases where a script needs to edit a setting (i.e. a relay script specifically for editing settings).  To alter a setting, change the map entry directly with vars["propertyToChange"] = newValue, followed by updatevars() to update the map with the new setting.  If you don't use updatevars(), the change will not stick.


==== Functional Details ====
==== Functional Details ====


When importing ZLib, it loads a map of your script settings from vars_myname.txt. It is a basic string[string] map called vars. To access a script setting within an ASH script, use vars[varname]. To check if a setting exists you can simply use if (vars contains varname).
When importing ZLib, it loads the setting defaults from vars_defaults.txt and a map of your script settings that have been changed from vars_myname.txt. To access a script setting within an ASH script, use getvar(varname).


When a script calls setvar("threshold",4), ZLib checks to see if a variable called "threshold" already exists in vars. If so, the existing value is not changed. If not, it sets it to 4 and saves the map back to vars_myname.txt.
When a script calls setvar("threshold",4), ZLib checks to see if a setting called "threshold" already exists. If so, since dfault is an integer, it ensures that the value is an integer using normalize() (saving changes if necessary), but unless normalization changed the value, nothing else happens. If "threshold" does not exist, it initializes its default value to 4, its type to int, and saves those defaults back to vars_defaults.txt. The setting may now be accessed by getvar() or edited using ZLib in the CLI.
 
The dfault parameter can be any primitive or ASH type ($item, $effect, etc), but not a map, array, or record.
 
At present, nothing is done with types and they could all have just been strings, but I have some plans involving a remote server containing setting documentation, where it would be quite useful to have data types saved along with the variablenames.


==== Choosing Setting Names ====
==== Choosing Setting Names ====
Line 305: Line 339:


2. Prefix your setting names with a script identifier. For example, here are some of my One-Click Wossname script settings:
2. Prefix your setting names with a script identifier. For example, here are some of my One-Click Wossname script settings:


{{CodeSample|
{{CodeSample|
Line 311: Line 344:
<syntaxhighlight>
<syntaxhighlight>
setvar("ocw_warplan","optimal");
setvar("ocw_warplan","optimal");
setvar("is_100_run",false);
setvar("ocw_change_to_meat",true);
setvar("ocw_change_to_meat",true);
setvar("ocw_nunspeed",false);
setvar("ocw_nunspeed",false);
Line 318: Line 350:
setvar("ocw_m_default","");
setvar("ocw_m_default","");
</syntaxhighlight>}}
</syntaxhighlight>}}
Those settings which are specific to OCW are prefixed with "ocw_" so as to be found together in the settings file. However, some of the settings are usable across scripts, and are not so prefixed. For example, I intend to use the "is_100_run" variable in every script that swaps familiars, so as to avoid tainting a 100% run. Likewise, the "defaultoutfit" will be used by nearly all of my adventuring scripts that swap outfits (MacGuffin, OCW).
Those settings which are specific to OCW are prefixed with "ocw_" so as to be found together in the settings file. However, some of the settings are usable across scripts, and are not so prefixed. For example, the "defaultoutfit" is used by nearly all of my adventuring scripts that swap outfits, so no prefix is given.
 
== Adventuring Functions ==
 
{{HideLink|be_good}}{{Function|
name=be_good|
return_type=boolean|
parameter1={{Param|string|johnny}}|
}}
{{Function|
name=be_good|
return_type=boolean|
parameter1={{Param|item|johnny}}|
}}
{{Function|
name=be_good|
return_type=boolean|
parameter1={{Param|familiar|johnny}}|
}}
{{Function|
name=be_good|
return_type=boolean|
parameter1={{Param|skill|johnny}}|
p1desc={{pspan|johnny}} is the thing you want to check|
}}
This function, originally created to check whether items were allowed in the Bees Hate You path (hence the name), has been expanded to an all-purpose check to see whether something is acceptable in your current path.  For example, in a Trendy path, or any of the newer paths that have similar restrictions, outdated items would not be_good.  Likewise, during Bees Hate You, a familiar containing a 'b' would not be_good.  In Fistcore, anything you hold in your hands is not allowed.  In an Avatar of Boris run, your normal permed skills are not active.  And so forth.
 
{{HideLink|qprop}}{{Function|
name=qprop|
return_type=boolean|
parameter1={{Param|string|test}}|
p1desc={{pspan|test}} is a basic logical expression using a quest property|
}}
Simplifies checking mafia's quest tracking properties ("prefref quest" in the CLI will reveal them).  You should supply {{pspan|test}} like so:
 
<quest property> <logical operator> <possible property value>
 
For instance:
To check that a quest is complete: qprop("questLXXSomequest == finished")
To check that a quest has reached or passed "step2": qprop("questLXXSomequest >= step2")
To check that a quest is not complete: qprop("questLXXSomequest != finished")
To check that a quest hasn't reached step3 yet: qprop("questLXXSomequest < step3")
 
The function converts these text properties to numbers internally, so to save the function a completely insignificant amount of milliseconds (and more importantly yourself a little typing) you can also just use numbers directly instead of text values, where "step3" is 3, "unstarted" is -1, "started" is 0, and "finished" is 999. Thus, the last example above would also work as qprop("questLXXSomequest < 3").
 
One more bit of shorthand: you can supply only the property name by itself to check whether the quest is finished. The first example above would also work as qprop("questLXXSomequest").
 
{{HideLink|mall_val}}{{Function|
name=mall_val|
return_type=int|
parameter1={{Param|item|it}}|
parameter2={{Param|float|expirydays}}|
parameter3={{Param|boolean|combatsafe}}|
p1desc={{pspan|it}} is the item being valued.|
p2desc={{pspan|expirydays}} is optional, default 0.  It represents the age at which {{f|historical_price}} is no longer valid, after which {{f|mall_price}} is used.|
p3desc={{pspan|combatsafe}} is optional, default false. If true, the function will avoid calling mall_price and use only historical_price, regardless of age.|
}}
The ASH functions {{f|mall_price}}, {{f|historical_price}}, and {{f|historical_age}} are often combined to save server hits when checking for the price of multiple items.  Scripts will use the historical price if it is fairly recent, or hit the server with mall_price if it is too old.  This function wraps all of that up, and even adds a flag for getting item values during combat (when you don't have mall access).  You'll generally call this with only one of the two parameters.
 
If you want to only use historical_price: mall_val(someitem, true)
If you want to only use mall price: mall_val(someitem,0)
If you want to use historical prices no more than 2 days old, otherwise use mall price: mall_val(someitem,3)
 
{{HideLink|sell_val}}{{Function|
name=sell_val|
return_type=int|
parameter1={{Param|item|it}}|
parameter2={{Param|float|expirydays}}|
parameter3={{Param|boolean|combatsafe}}|
p1desc={{pspan|it}} is the item being valued.|
p2desc={{pspan|expirydays}} is the same as in mall_val() above.|
p3desc={{pspan|combatsafe}} is also as in mall_val() above.|
}}
This function is concerned with the meat you could realistically expect to get from selling the item.  It returns mall_val, unless the mall value is at minimum, meaning it's junk which probably won't sell.  In that case it returns the item's autosell value.


{{HideLink|have_item}}{{Function|
{{HideLink|have_item}}{{Function|
Line 326: Line 431:
p1desc={{pspan|to_lookup}} is the item to count|
p1desc={{pspan|to_lookup}} is the item to count|
}}
}}
A residual function, used by the following and probably in several other scripts. Returns the amount of an item you have both in your inventory and equipped. Functionally equivalent to the built-in function {{f|available_amount}}, except that its parameter is a string. (Zarqon please verify.)
A residual function, used by the following and probably in several other scripts. Returns the amount of an item you have both in your inventory and equipped. Similar but not equivalent to the ASH function {{f|available_amount}}, since this function completely ignores your closet and storage.
 
{{HideLink|braindrop}}{{Function|
name=braindrop|
return_type=item|
parameter1={{Param|monster|patient}}|
p1desc={{pspan|patient}} is the monster under inquiry|
}}
Returns the brain dropped by {{pspan|patient}} in Zombiecore.  All five types of brains are properly accounted for, as well as monsters that drop no brains.  Will always return $item[none] outside of Zombiecore.
 
{{HideLink|kadrop}}{{Function|
name=kadrop|
return_type=float|
parameter1={{Param|monster|m}}|
p1desc={{pspan|m}} is the monster under inquiry|
}}
Returns the amount of ka dropped by {{pspan|m}} as Ed the Undying, accounting for priest servants and the crown of Ed.  Will always return 0 outside of Edcore.
 
{{HideLink|is_goal}}{{Function|
name=is_goal|
return_type=boolean|
parameter1={{Param|stat|whichstat}}|
p1desc={{pspan|whichstat}} is the stat to check|
}}
The ASH function {{f|is_goal}} takes an item parameter and returns true if the given item is a goal.  ZLib extends that function by also including a version which accepts a stat as a parameter.  Stats can be goals when a user or script sets "level X" or "X muscle" as a goal.
 
{{HideLink|isxpartof}}{{Function|
name=isxpartof|
return_type=float|
parameter1={{Param|item|child}}|
parameter2={{Param|item|ancestor}}|
p1desc={{pspan|child}} is the ingredient/component you want to check.|
p2desc={{pspan|ancestor}} is the concoction you want to check.|
}}
In the sentence "child is X part of ancestor", this function returns X.  It assumes the minimum amount of other ingredients necessary.  For example, isxpartof($item[white pixel], $item[digital key]) returns 0.033333335 (1/30), since 30 white pixels are needed to make a digital key. However, isxpartof($item[red pixel], $item[digital key]) returns 0.03125 (1/32), assuming 1 each of green and blue pixels and 29 other white pixels (rather than 30 each RGB pixels -- 1/90).  This function is used by has_goal(item) but may have uses in your own script.


{{HideLink|has_goal}}{{Function|
{{HideLink|has_goal}}{{Function|
Line 344: Line 483:
p1desc={{pspan|check_me}} is the item, monster or locationto check|
p1desc={{pspan|check_me}} is the item, monster or locationto check|
}}
}}
At the base of this function is the item parameter version, which returns the chance that the item {{pspan|check_me}} is or results in a goal. If is_goal(item) == true or it's a bounty item, returns 1.0. Otherwise, returns the chance that you would get a goal from using the item. For example, with a goal of black pepper, has_goal($item[black picnic basket]) would return 0.58. Many thanks to aqualectrix for creating and sharing the container items results map.
At the base of this function is the item parameter version, which returns the chance that the item {{pspan|check_me}} is or results in a goal. If the item is itself a goal, returns 1.0. Otherwise, returns what percentage of a goal the item is, which could be nonzero in two cases: 1) you could get a goal by using the item (returns the chance of success), or 2) the item is an ingredient of a goal. For example, with a goal of black pepper, has_goal($item[black picnic basket]) would return 0.58.


When supplied a monster as the parameter for {{pspan|check_me}}, returns the percent chance that encountering the given monster will result in a goal, taking into account +items, pickpocket availability (and +pickpocket), and Torso. For instance, with no +item and black pepper as a goal, has_goal($monster[black widow]) would return 0.087 (0.58 basket contains pepper * 0.15 basket drop rate). Also note that it will add multiple goals together, so with white pixels as a goal, a Blooper would return 2.1.
When supplied a monster as the parameter for {{pspan|check_me}}, returns the percent chance that encountering the given monster will result in a goal, taking into account +items, pickpocket availability (and +pickpocket), and Torso. For instance, with no +item and black pepper as a goal, has_goal($monster[black widow]) would return 0.087 (0.58 basket contains pepper * 0.15 basket drop rate). Also note that it will add multiple goals together, so with white pixels as a goal, a Blooper would return 2.1.


When supplied a location as the parameter for {{pspan|check_me}}, returns the chance that adventuring at a given location will yield a goal. For our black pepper example, has_goal($location[black forest]) would return 0.0174 (0.2 black widow appearance rate * 0.087 chance that a widow has black pepper). Presently this accounts for combat frequency modifiers but not Olfaction, and it will be off for areas with noncombats that grant goals, because it assumes that all noncombats do not yield items.
When supplied a location as the parameter for {{pspan|check_me}}, returns the chance that adventuring at a given location will yield a goal. For our black pepper example, has_goal($location[black forest]) would return 0.0174 (0.2 black widow appearance rate * 0.087 chance that a widow has black pepper). Presently this accounts for combat frequency modifiers but not Olfaction, and it will be off for areas with noncombats that grant goals, because it assumes that all noncombats do not yield items.
These functions also have an optional boolean parameter, usespec.  If supplied as true, these functions will use speculative values.  (See "whatif")


{{HideLink|obtain}}{{Function|
{{HideLink|obtain}}{{Function|
Line 366: Line 507:
p1desc={{pspan|qty}} is the quantity of the item or choice adventure desired|
p1desc={{pspan|qty}} is the quantity of the item or choice adventure desired|
p2desc={{pspan|condition}} is the item or choice adventure to use as a goal|
p2desc={{pspan|condition}} is the item or choice adventure to use as a goal|
p3desc={{pspan|location}} is the place to adventure to obtain your goal|
p3desc={{pspan|place}} is the location to adventure to obtain your goal|
p4desc={{pspan|filter}} is an optional combat filter used the same as in {{f|adventure}}|
p4desc={{pspan|filter}} is an optional combat filter used the same as in {{f|adventure}}|
}}
}}
Line 396: Line 537:
name=my_defstat|
name=my_defstat|
return_type=int|
return_type=int|
parameter1={{Param|boolean|usespec}}|
p1desc={{pspan|usespec}} is optional.  If true, uses speculative values rather than real values.|
}}
}}
Returns the value of your buffed defense stat, taking into account Hero of the Half-Shell.
Returns the value of your buffed defense stat, taking into account Hero of the Half-Shell.
Line 405: Line 548:
p1desc={{pspan|where}} is the location to check for safe moxie|
p1desc={{pspan|where}} is the location to check for safe moxie|
}}
}}
int get_safemox(location wear)
Using mafia's location/monster data, returns the safe moxie of a given zone {{pspan|where}}.
Using mafia's location/monster data, returns the safe moxie of a given zone {{pspan|where}}.


Line 433: Line 575:
}}
}}
Returns your heaviest familiar of a given type (currently possible: items, meat, produce, stat, delevel). If your ZLib "is_100_run" setting is anything other than $familiar[none], returns that familiar (so you don't have to make the check in your script).
Returns your heaviest familiar of a given type (currently possible: items, meat, produce, stat, delevel). If your ZLib "is_100_run" setting is anything other than $familiar[none], returns that familiar (so you don't have to make the check in your script).
== Kmail Functions ==
{{HideLink|load_kmail}}{{Function|
name=load_kmail|
return_type=void|
parameter1={{Param|string|calledby}}|
p1desc={{pspan|calledby}} is optional and allows you to specify the name of the script calling this function, which will be submitted when the script visits api.php. The default value is "ZLib-powered-script".|
}}
This function parses your kmail inbox in a single server hit and loads it into the global variable "mail", which is of type kmessage[int].  A kmessage is a record type, with the following fields:
{{CodeSample|
code=
<syntaxhighlight>
record kmessage {
  int id;                  // message id
  string type;              // possible values observed thus far: normal, giftshop
  int fromid;              // sender's playerid (0 for npc's)
  int azunixtime;          // KoL server's unix timestamp
  string message;          // including items/meat gained
  int[item] items;          // items included in the message
  int meat;                // meat included in the message
  string fromname;          // sender's playername
  string localtime;        // your local time according to your KoL account, human-readable string
};
</syntaxhighlight>}}
Thus, after calling this function your inbox is very easy to work with.  You can foreach over each message if you like, accessing the fields for details.
{{HideLink|process_kmail}}{{Function|
name=process_kmail|
return_type=void|
parameter1={{Param|string|functionname}}|
p1desc={{pspan|functionname}} specifies the name of a function designed to parse kmail.|
}}
If you liked load_kmail(), you'll like this even better.  First off, this function loads your kmail into the mail variable if you haven't already done so.  Next, it calls a function named {{pspan|functionname}} on each kmail message.  The function must be at top level, accept a single kmessage parameter, and return a boolean.  For each kmail in your inbox, if the called function returns true, that message will be deleted once all messages have been processed.
Here's a simple example which will delete all messages from your lovely Pen Pal:
{{CodeSample|
code=
<syntaxhighlight>
boolean no_penpal(kmessage m) {
  return (m.fromname == "Your Pen Pal");
}
process_kmail("no_penpal");
</syntaxhighlight>}}


{{HideLink|send_gift}}{{Function|
{{HideLink|send_gift}}{{Function|
Line 439: Line 626:
parameter1={{Param|string|recipient}}|
parameter1={{Param|string|recipient}}|
parameter2={{Param|string|message}}|
parameter2={{Param|string|message}}|
parameter3={{Param|int_meat}}|
parameter3={{Param|int|meat}}|
parameter4={{Param|int [item]|goodies|ag=t}}|
parameter4={{Param|int [item]|goodies|ag=t}}|
}}
}}
Line 463: Line 650:
parameter1={{Param|string|recipient}}|
parameter1={{Param|string|recipient}}|
parameter2={{Param|string|message}}|
parameter2={{Param|string|message}}|
parameter3={{Param|int_meat}}|
parameter3={{Param|int|meat}}|
parameter4={{Param|int [item]|goodies|ag=t}}|
}}
}}
{{Function|
{{Function|
Line 471: Line 657:
parameter1={{Param|string|recipient}}|
parameter1={{Param|string|recipient}}|
parameter2={{Param|string|message}}|
parameter2={{Param|string|message}}|
parameter3={{Param|int_meat}}|
parameter3={{Param|int|meat}}|
parameter4={{Param|int [item]|goodies|ag=t}}|
}}
}}
{{Function|
{{Function|
Line 486: Line 673:
p4desc={{pspan|goodies}} is an optional map of items & amounts to send|
p4desc={{pspan|goodies}} is an optional map of items & amounts to send|
p5desc={{pspan|inside_note}} is an optional inside message if sent as a gift|
p5desc={{pspan|inside_note}} is an optional inside message if sent as a gift|
}}
{{Function|
name=kmail|
return_type=boolean|
parameter1={{Param|kmessage|km}}|
p1desc={{pspan|km}} allows you to send a kmail supplied in kmessage format.  The only thing unusual here is that the "fromname" field will be used as the recipient.  The other fields will be used appropriately to call the above kmail function.|
}}
}}
Sends a kmail to player {{pspan|recipient}}, returning true if the kmail is successfully sent. Handles splitting the {{pspan|message}} into multiple messages if the number of item types in {{pspan|goodies}} is too large. Returns the result of send_gift() if the intended {{pspan|recipient}} is unable to receive the {{pspan|message}} due to being in HC or somesuch. Note that you can also specify the {{pspan|inside_note}} to be used inside gifts in that case. Use "\n" to specify a new line in the {{pspan|message}}.
Sends a kmail to player {{pspan|recipient}}, returning true if the kmail is successfully sent. Handles splitting the {{pspan|message}} into multiple messages if the number of item types in {{pspan|goodies}} is too large. Returns the result of send_gift() if the intended {{pspan|recipient}} is unable to receive the {{pspan|message}} due to being in HC or somesuch. Note that you can also specify the {{pspan|inside_note}} to be used inside gifts in that case. Use "\n" to specify a new line in the {{pspan|message}}.
== Making use of Zlib ==
To include this library in your script, first you must download it from the location provided below and make sure it is in your /scripts directory (or a sub-directory thereof). Then, simply add the following towards the top any script in which you wish to have access to these functions:
{{CodeSample|
code=
<syntaxhighlight>
import "zlib.ash";
</syntaxhighlight>}}
Then all these functions will be available in your script. Have fun!
== More Information ==
<p>See the thread for ZLib on the mafia forum [http://kolmafia.us/showthread.php?2072 here].</p>


[[Category:Scripting]][[Category:ASH Function Libraries]]
[[Category:Scripting]][[Category:ASH Function Libraries]]

Latest revision as of 06:21, 28 July 2021

Attention KoLmafia Users!

This page details the use of functions in a script library. The information here is only useful to those who have followed the included steps to make use of these functions; they are not built-in to KoLmafia.

About ZLib

ZLib is a function library intended to make life easier for both script authors and script users. A more detailed introduction, as well as instructions on installing it and other details, can be found in the ZLib thread.

String Functions

excise

string excise(string source ,string start ,string end )

  • The original source string
  • start after this string
  • end before this string

This function returns a portion of the source string, from after the first occurrence of start to just before the first occurrence of end. If either start or end are missing, it will return an empty string. You can also supply either start or end as blank strings to specify the actual start or end of the source string.


equals

boolean equals(string s1 ,string s2 )

  • s1 is a string.
  • s2 is the string to compare with s1.

Compares two strings case-sensitively.

Note: This function was invented when string comparison operators (== and !=) were case-insensitive. As of r16180, ASH strings are compared case-sensitively, which makes this function no longer necessary.


vprint

boolean vprint(string message ,int level )

boolean vprint(string message ,string color ,int level )

  • message and color are used as in the function print()
  • level controls the return value and specifies the verbosity level of the message

This function is an enhanced version of the ASH function print(). The message and optional color parameters are exactly like in print(), but the level parameter gives you a lot of additional control. Specifically, it allows you to control the return value, specify the verbosity level of the output, and maybe even abort the script.

First, the return value. If level is positive, it returns true. If negative, it returns false. If level is 0, vprint() will abort with the specified message. You can see now that vprint effectively replaces both abort() and print. I recommend it as your go-to function anytime you need to show anything in the CLI, for any reason.

Having a boolean return value (as opposed to ASH's print returning void) allows you to include helpful information in your script easily, without needing to significantly edit your code. For example:

// add debugging info to an if check:
if (somevar == 2 && vprint("somevar equals 2",10)) dosomething();
// add additional info to a return true/false:
if (everythingsgreat) return vprint("Everything's great!",7);
   else return vprint("Everything is not great.",-7);


Secondly, level represents the verbosity of the message. ZLib includes a script setting called "verbosity". Users can adjust this value to specify how verbose they want scripts to be. If they set it to 1, they want the script to print almost nothing -- only the most important messages. If they set it to 10, they want it to print a lot of details. The level of each vprint command thus determines whether or not the message will actually be printed. If the absolute value of level is more than verbosity, the message will not be printed. For example, a user with the default verbosity of 3 would not see any of the example messages given above. This allows users to control the chattiness of scripts, and allows authors to include helpful debugging print statements which can be shown by setting verbosity high.

Recommendations for Verbosity Levels in vprint()

0: abort error

+/- 1: absolutely essential (and non-cluttering) information -- use very sparingly, since a verbosity of 1 is basically "silent mode"

+/- 2: important and useful info -- this should generally be your base level for your most important messages

+/- 4: interesting but non-essential information

+/- 6: info which an overly curious person might like to see on their CLI

+/- 10: details which are only helpful for debugging, such as "begin/end functionname()" or "current value of variable: value"


This will allow users who want extra levels of detail printed to see that detail without cluttering the CLI for users who don't prefer to see all the details. In addition, it allows users to specify a verbosity of 0 to see ONLY mafia output (no script output at all), which could prove handy.

The color parameter is optional. If you omit it, the default color is black for positive values of level, and red for negative values. Usually, you won't be calling vprint() with the color parameter, unless you want to specify a different color or override the default colors.


vprint_html

boolean vprint_html(string message ,int level )

  • message is used as in the function print_html()
  • level is a verbosity reference

Same as vprint() above, but wraps print_html().


normalized

string normalized(string mixvar ,string type )

string normalized(string mixvar ,string type ,string glue )

  • mixvar is the string to normalize
  • type is the datatype to normalize to, which can be any primitive type or any typed constant. You can also specify "list of <type>", for a comma-delimited list of the given type.
  • glue is only relevant for lists of a type. You can specify the delimiter (which could be necessary if dealing with list entries that have commas in them). Defaults to ", ".

Returns mixvar, normalized to the specified KoLmafia type. For example, normalized("badger", "familiar") would return "Astral Badger". It can also normalize comma-delimited lists of any of these types if you specify "list of <type>" for type. For example, normalized("bloop, dair go, possess", "list of monster") would return "Blooper, Dairy Goat, Possessed Silverware Drawer".


join

string join(string [int]  pieces ,string glue )

  • pieces is a map of strings which you want to join into a single string.
  • glue is the string to put between the pieces.

This function is the opposite of the ASH function split_string(). It joins pieces together, inserting glue between each piece, and returns the assembly as a single string. Useful for working with comma-delimited lists (or anything-delimited lists, actually).


list_contains

boolean list_contains(string stringlist ,string needle )

boolean list_contains(string stringlist ,string needle ,string glue )

  • stringlist is a glue-delimited string list such as returned by join().
  • needle is the entry to check for.
  • glue is optional (defaults to ", ") and represents the delimiter for the list.

Returns true if list contains needle. Avoids false positives which could result from using contains_text().


list_add

string list_add(string stringlist ,string add )

string list_add(string stringlist ,string add ,string glue )

  • stringlist is a glue-delimited string list such as returned by join() above.
  • add is the entry to add to the list.
  • glue is optional (defaults to ", ") and represents the delimiter for the list.

Adds unique entry add to a glue-delimited list, and returns the modified list. If the entry already exists in the list, another entry will not be added. For example, list_add("a, b, c","d") would return "a, b, c, d", but list_add("a, b, c", "a") would return "a, b, c", since the entry "a" already exists.


list_remove

string list_remove(string stringlist ,string del )

string list_remove(string stringlist ,string del ,string glue )

  • stringlist is a glue-delimited string list such as returned by join() above.
  • del is the entry to remove from the list.
  • glue is optional (defaults to ", ") and represents the delimiter for the list.

Removes del from glue-delimited list, and returns the modified list. It will remove all instances of del. For example, list_remove("a, b, c","a") would return "b, c", and list_remove("a, a, b, b, c, c", "a") would return "b, b, c, c".


rnum

string rnum(int n )

string rnum(float n )

string rnum(float n ,int place )

  • n is a number
  • place is the number of decimal places to round to

Returns your number n as a human-readable string, appropriate to the user's computer's region. For ints, this means it adds grouping separators where appropriate. For floats, it also rounds to the nearest place after the decimal. Default place for the float-only version is 2, although it may display fewer digits if they are 0's. Examples: rnum(12580) => "12,580", rnum(3.14152964,3) => "3.142", rnum(4.00008) => "4", rnum(123456789.87654321) => "123,456,789.88". Recommended as a substitute for to_string(int).

Number Functions

abs

float abs(float n )

  • n is any number.

Returns the absolute value of the number n. Don't worry if you are working with integers, it will still work just fine. This function already exists in many programming languages; ZLib makes it handily available in ASH.


minmax

float minmax(float a ,float min ,float max )

  • a is the original number
  • min is the minimum return value
  • max is the maximum return value

Returns a, but no less than min and no more than max. Another function common to many languages.


set_avg

void set_avg(float to_add ,string which_prop )

  • to_add is the data point to add
  • which_prop is the property to add data to

Useful for adding spading to scripts. Adds one more statistic to an average value being stored in a property. For example, calling this function three times with the values 2, 4, and 6 for to_add would result in the property which_prop containing "4.0:3", with 4.0 being the average of the three numbers added and 3 being the amount of numbers averaged.


get_avg

float get_avg(string which_prop )

  • which_prop is the property to access

Returns an average value set by set_avg().


eval

float eval(string expression ,float [string]  values )

  • expression is the base expression
  • values is a map of values to replace

By Jason Harper. Evaluates expression as a math expression, and allows you to substitute values for variables, as described in much greater detail here. Brief documentation is also included in ZLib. (NB: This section needs more infoz.)

Script Functions

check_version

string check_version(string soft ,string proj ,int thread )

  • soft is the script name, which must match the page source of the thread being parsed
  • proj is the name of the SVN project name to check.
  • thread is the script's thread number on kolmafia.us

string check_version(string soft ,string prop ,string this_version ,int thread )

  • soft is as above.
  • prop is used as part of the name of the property saved to user preferences.
  • this_version is the version of the script currently running
  • thread is as above.

Server-friendly once-daily version-checking. There are two versions of this function, one for SVN and one for forum threads. The three-parameter SVN version uses mafia's SVN client to check if a previously checked-out SVN project is current and if not, it updates it automatically, meaning the script will be current the next time it runs. In the event that a user has checked the option for mafia to automatically update all projects on login, it detects that the script has updated and prints an informative message with a link to the script's kolmafia.us thread -- and if the project is hosted on SourceForge, an additional link to the changelog there.

For the four-parameter forum thread version, it visits the specified thread on the kolmafia.us forums to find the current version of your script. The thread must include "<b>soft version</b>" for the version info to be successfully parsed. Optionally, you may include "[requires revision XXXX]" somewhere in your post if you want to indicate a required minimum revision of mafia. If a new version is available, it alerts the user in large text and provides an update link.

The return value of both versions is a blank string unless an update is/was found, in which case it is a <div class='versioninfo'> containing the update message. This allows this function to work equally well for relay scripts. The current version/revision (and the last date checked) is stored in a data file "zversions.txt". Example:

check_version("Hardcore Checklist","checklist","1.2.7",1045);


load_current_map

boolean load_current_map(string map_name ,aggregate destination )

  • map_name is the name of the map, without the file extension
  • destination is a previously-declared map to load with data

Acts as a wrapper for the built-in file_to_map() with automatic update capability. The first time the function is called for a given map each day, it will check Zarqon's Map Manager to see if an update for the given map_name is available, and if so will load from there. Otherwise, it merely loads it from disk. (Note: you should not include a file extension, such as ".txt" in the map_name parameter.)


setvar

void setvar(string varname ,mixed dfault )

  • name is the name of the setting
  • dfault can be any primitive or ASH type (e.g. item, effect, coinmaster, etc.), but not an array, map, or record.

This function ensures that a ZLib script setting called name exists. If not, it adds it and the default value specified in dfault to vars_defaults.txt. Also, if the setting has been changed from its default value, it normalizes the value according to the type of dfault, but otherwise does nothing. Note that this function is for initializing defaults, not for editing existing settings. That is done by calling ZLib in the CLI or running a setting editor tool such as Prefref Plus.


getvar

string getvar(string varname )

  • name is the setting to retrieve the value of

This function returns the value of the specified script setting. Authors are encouraged to use this rather than a direct vars[] lookup, since values which have not been changed from the default will eventually not be present in vars[].

For Users

  • Script settings are now all saved in one place, separate from mafia properties. I've read more than one post wishing that script-defined settings and mafia properties would be separate. This provides a solution.
  • Script settings are independent from scripts. This means that you will no longer need to edit scripts to adjust your settings. Further, when you download a script update, the script will still use your saved settings and you won't need to reset them.
  • To see all of your current settings, type "zlib vars" in the CLI. You can also type "zlib <whatever>" to see a list of current settings and values containing <whatever>. To change a setting, type "zlib settingname = value". If you're adjusting threshold, you can use "up" or "down" as the value to adjust your threshold relatively. This is almost exactly as convenient as mafia properties (possibly more so since you don't need to open a text file to find setting names!).
  • If for some reason you prefer to open a text file, all ZLib setting default values are stored in vars_defaults.txt in your data directory. Your character's ZLib settings that have been changed from default are stored in a file called vars_myname.txt in your data directory.
  • Scripts that use Zlib script settings will initialize the settings -- saving their default value and type in vars_defaults.txt -- when you run them for the first time. Attempting to edit a nonexisting setting won't work, so you'll need to run a script once (then, usually, mash the ESC key before it actually does anything) before you can configure it. Script documentation should tell you which settings to change to get your desired behavior.

For Script Authors

  • Use setvar() to initialize a setting that your script will reference. To reference the setting, use getvar() and convert from string to whichever type the setting is supposed to be. Accessing vars[] or vardefaults[] directly is not recommended, as a value may exist in one but not the other, or both.
  • Script settings may now be used across scripts, in exactly the same way that mafia properties are. Basically, this works almost exactly like mafia properties, except that new settings can only be created by setvar() or manually editing the file ("zlib nonexistentsetting = value" will fail).
  • Settings are only stored if you run a script that defines/uses them. So your settings file will not contain any extraneous unused settings.
  • Script authors can now test for a setting's existence in vardefaults[], which means you can check to see if a user has used a given script. It's almost as good as a script_exists() function. This can allow scripts to work together with other scripts, if they exist!
  • Scripts with overlapping or related functionality can be designed to access a single shared setting, in much the same way that my scripts have until now all shared a "threshold" mafia setting. Changing a single setting can now change the behavior of every script that accesses that setting.
  • Settings are intended to be set only by users, not scripts. If you want a persistent variable that a script will use, consider static variables. However, there may be cases where a script needs to edit a setting (i.e. a relay script specifically for editing settings). To alter a setting, change the map entry directly with vars["propertyToChange"] = newValue, followed by updatevars() to update the map with the new setting. If you don't use updatevars(), the change will not stick.

Functional Details

When importing ZLib, it loads the setting defaults from vars_defaults.txt and a map of your script settings that have been changed from vars_myname.txt. To access a script setting within an ASH script, use getvar(varname).

When a script calls setvar("threshold",4), ZLib checks to see if a setting called "threshold" already exists. If so, since dfault is an integer, it ensures that the value is an integer using normalize() (saving changes if necessary), but unless normalization changed the value, nothing else happens. If "threshold" does not exist, it initializes its default value to 4, its type to int, and saves those defaults back to vars_defaults.txt. The setting may now be accessed by getvar() or edited using ZLib in the CLI.

Choosing Setting Names

The file of script settings will contain all script settings, sorted alphabetically. Also, there is no way to detect if a setting is unused, so if you decide to change the name, the old setting will never be deleted. Please think carefully about your setting names. If you have a setting named "setting1", a user will probably not have a clue which script that is for or what it does. True, this can be overcome with documentation, but it is far better to have settings that make sense just by looking at them.

Recommendations:

1. Use a name that clearly identifies what the setting is/does.

2. Prefix your setting names with a script identifier. For example, here are some of my One-Click Wossname script settings:


setvar("ocw_warplan","optimal");
setvar("ocw_change_to_meat",true);
setvar("ocw_nunspeed",false);
setvar("defaultoutfit","current");
setvar("ocw_f_default","zombie");
setvar("ocw_m_default","");

Those settings which are specific to OCW are prefixed with "ocw_" so as to be found together in the settings file. However, some of the settings are usable across scripts, and are not so prefixed. For example, the "defaultoutfit" is used by nearly all of my adventuring scripts that swap outfits, so no prefix is given.

Adventuring Functions

be_good

boolean be_good(string johnny )

boolean be_good(item johnny )

boolean be_good(familiar johnny )

boolean be_good(skill johnny )

  • johnny is the thing you want to check

This function, originally created to check whether items were allowed in the Bees Hate You path (hence the name), has been expanded to an all-purpose check to see whether something is acceptable in your current path. For example, in a Trendy path, or any of the newer paths that have similar restrictions, outdated items would not be_good. Likewise, during Bees Hate You, a familiar containing a 'b' would not be_good. In Fistcore, anything you hold in your hands is not allowed. In an Avatar of Boris run, your normal permed skills are not active. And so forth.


qprop

boolean qprop(string test )

  • test is a basic logical expression using a quest property

Simplifies checking mafia's quest tracking properties ("prefref quest" in the CLI will reveal them). You should supply test like so:

<quest property> <logical operator> <possible property value>

For instance: To check that a quest is complete: qprop("questLXXSomequest == finished") To check that a quest has reached or passed "step2": qprop("questLXXSomequest >= step2") To check that a quest is not complete: qprop("questLXXSomequest != finished") To check that a quest hasn't reached step3 yet: qprop("questLXXSomequest < step3")

The function converts these text properties to numbers internally, so to save the function a completely insignificant amount of milliseconds (and more importantly yourself a little typing) you can also just use numbers directly instead of text values, where "step3" is 3, "unstarted" is -1, "started" is 0, and "finished" is 999. Thus, the last example above would also work as qprop("questLXXSomequest < 3").

One more bit of shorthand: you can supply only the property name by itself to check whether the quest is finished. The first example above would also work as qprop("questLXXSomequest").


mall_val

int mall_val(item it ,float expirydays ,boolean combatsafe )

  • it is the item being valued.
  • expirydays is optional, default 0. It represents the age at which historical_price() is no longer valid, after which mall_price() is used.
  • combatsafe is optional, default false. If true, the function will avoid calling mall_price and use only historical_price, regardless of age.

The ASH functions mall_price(), historical_price(), and historical_age() are often combined to save server hits when checking for the price of multiple items. Scripts will use the historical price if it is fairly recent, or hit the server with mall_price if it is too old. This function wraps all of that up, and even adds a flag for getting item values during combat (when you don't have mall access). You'll generally call this with only one of the two parameters.

If you want to only use historical_price: mall_val(someitem, true) If you want to only use mall price: mall_val(someitem,0) If you want to use historical prices no more than 2 days old, otherwise use mall price: mall_val(someitem,3)


sell_val

int sell_val(item it ,float expirydays ,boolean combatsafe )

  • it is the item being valued.
  • expirydays is the same as in mall_val() above.
  • combatsafe is also as in mall_val() above.

This function is concerned with the meat you could realistically expect to get from selling the item. It returns mall_val, unless the mall value is at minimum, meaning it's junk which probably won't sell. In that case it returns the item's autosell value.


have_item

int have_item(string to_lookup )

  • to_lookup is the item to count

A residual function, used by the following and probably in several other scripts. Returns the amount of an item you have both in your inventory and equipped. Similar but not equivalent to the ASH function available_amount(), since this function completely ignores your closet and storage.


braindrop

item braindrop(monster patient )

  • patient is the monster under inquiry

Returns the brain dropped by patient in Zombiecore. All five types of brains are properly accounted for, as well as monsters that drop no brains. Will always return $item[none] outside of Zombiecore.


kadrop

float kadrop(monster m )

  • m is the monster under inquiry

Returns the amount of ka dropped by m as Ed the Undying, accounting for priest servants and the crown of Ed. Will always return 0 outside of Edcore.


is_goal

boolean is_goal(stat whichstat )

  • whichstat is the stat to check

The ASH function is_goal() takes an item parameter and returns true if the given item is a goal. ZLib extends that function by also including a version which accepts a stat as a parameter. Stats can be goals when a user or script sets "level X" or "X muscle" as a goal.


isxpartof

float isxpartof(item child ,item ancestor )

  • child is the ingredient/component you want to check.
  • ancestor is the concoction you want to check.

In the sentence "child is X part of ancestor", this function returns X. It assumes the minimum amount of other ingredients necessary. For example, isxpartof($item[white pixel], $item[digital key]) returns 0.033333335 (1/30), since 30 white pixels are needed to make a digital key. However, isxpartof($item[red pixel], $item[digital key]) returns 0.03125 (1/32), assuming 1 each of green and blue pixels and 29 other white pixels (rather than 30 each RGB pixels -- 1/90). This function is used by has_goal(item) but may have uses in your own script.


has_goal

float has_goal(item check_me )

float has_goal(monster check_me )

float has_goal(location check_me )

  • check_me is the item, monster or locationto check

At the base of this function is the item parameter version, which returns the chance that the item check_me is or results in a goal. If the item is itself a goal, returns 1.0. Otherwise, returns what percentage of a goal the item is, which could be nonzero in two cases: 1) you could get a goal by using the item (returns the chance of success), or 2) the item is an ingredient of a goal. For example, with a goal of black pepper, has_goal($item[black picnic basket]) would return 0.58.

When supplied a monster as the parameter for check_me, returns the percent chance that encountering the given monster will result in a goal, taking into account +items, pickpocket availability (and +pickpocket), and Torso. For instance, with no +item and black pepper as a goal, has_goal($monster[black widow]) would return 0.087 (0.58 basket contains pepper * 0.15 basket drop rate). Also note that it will add multiple goals together, so with white pixels as a goal, a Blooper would return 2.1.

When supplied a location as the parameter for check_me, returns the chance that adventuring at a given location will yield a goal. For our black pepper example, has_goal($location[black forest]) would return 0.0174 (0.2 black widow appearance rate * 0.087 chance that a widow has black pepper). Presently this accounts for combat frequency modifiers but not Olfaction, and it will be off for areas with noncombats that grant goals, because it assumes that all noncombats do not yield items.

These functions also have an optional boolean parameter, usespec. If supplied as true, these functions will use speculative values. (See "whatif")


obtain

boolean obtain(int qty ,string condition ,location place )

boolean obtain(int qty ,string condition ,location place ,string filter )

  • qty is the quantity of the item or choice adventure desired
  • condition is the item or choice adventure to use as a goal
  • place is the location to adventure to obtain your goal
  • filter is an optional combat filter used the same as in adventure()

Attempts to get qty (minus existing) of condition, either by purchasing (if you have the KoLmafia preference set), pulling from Hangk's, or adventuring at the specified place. It also works with choice adventures.


use_upto

boolean use_upto(int qty ,item thing ,boolean purchase )

  • qty is the quantity to use
  • thing is the item to use
  • purchase is true if KoLmafia should purchase extras if you don't already have qty

Gets (if purchase is true) and uses qty of the item(s) thing if possible. Otherwise, uses as many as you have up to qty.


resist

boolean resist(element resist_it ,boolean really )

  • resist_it is the element to resist
  • really is true to actually attemp resistance, false to check only

Returns whether you are able to resist a given element resist_it, or if really is true, attempts to actually achieve that resistance (casting buffs, changing gear, or equipping your Exotic Parrot) and returns its success.


my_defstat

int my_defstat(boolean usespec )

  • usespec is optional. If true, uses speculative values rather than real values.

Returns the value of your buffed defense stat, taking into account Hero of the Half-Shell.


get_safemox

int get_safemox(location where )

  • where is the location to check for safe moxie

Using mafia's location/monster data, returns the safe moxie of a given zone where.


auto_mcd

boolean auto_mcd(int check_me )

boolean auto_mcd(monster check_me )

boolean auto_mcd(location check_me )

  • check_me is the int, monster or location to check

If your ZLib setting "automcd" is true, automatically adjusts your mind-control device for maximum stat gains based on safe moxie and your ZLib "threshold" setting. Does not adjust for MCD-sensitive areas (certain bosses, Slime Tube), or areas with no known combats. Returns true unless KoLmafia is unable to do so, even though the script thinks it should be capable (still returns true if you can't currently access an mcd-changing device).


best_fam

familiar best_fam(string type )

  • type is the type of familiar ability to check for

Returns your heaviest familiar of a given type (currently possible: items, meat, produce, stat, delevel). If your ZLib "is_100_run" setting is anything other than $familiar[none], returns that familiar (so you don't have to make the check in your script).

Kmail Functions

load_kmail

void load_kmail(string calledby )

  • calledby is optional and allows you to specify the name of the script calling this function, which will be submitted when the script visits api.php. The default value is "ZLib-powered-script".

This function parses your kmail inbox in a single server hit and loads it into the global variable "mail", which is of type kmessage[int]. A kmessage is a record type, with the following fields:

record kmessage {
   int id;                   // message id
   string type;              // possible values observed thus far: normal, giftshop
   int fromid;               // sender's playerid (0 for npc's)
   int azunixtime;           // KoL server's unix timestamp
   string message;           // including items/meat gained
   int[item] items;          // items included in the message
   int meat;                 // meat included in the message
   string fromname;          // sender's playername
   string localtime;         // your local time according to your KoL account, human-readable string
};


Thus, after calling this function your inbox is very easy to work with. You can foreach over each message if you like, accessing the fields for details.


process_kmail

void process_kmail(string functionname )

  • functionname specifies the name of a function designed to parse kmail.

If you liked load_kmail(), you'll like this even better. First off, this function loads your kmail into the mail variable if you haven't already done so. Next, it calls a function named functionname on each kmail message. The function must be at top level, accept a single kmessage parameter, and return a boolean. For each kmail in your inbox, if the called function returns true, that message will be deleted once all messages have been processed.

Here's a simple example which will delete all messages from your lovely Pen Pal:

boolean no_penpal(kmessage m) {
   return (m.fromname == "Your Pen Pal");
}
process_kmail("no_penpal");


send_gift

boolean send_gift(string recipient ,string message ,int meat ,int [item]  goodies )

boolean send_gift(string recipient ,string message ,int meat ,int [item]  goodies ,string inside_note )

  • recipient is the player to send to
  • message is the outside message
  • meat is the amount of meat to send
  • goodies is a map of items & amounts to send
  • inside_note is an optional inside message

Sends a gift to a player. Able to split large amounts of items. Returns true if the package is sent and false if not. See kmail() below.


kmail

boolean kmail(string recipient ,string message ,int meat )

boolean kmail(string recipient ,string message ,int meat ,int [item]  goodies )

boolean kmail(string recipient ,string message ,int meat ,int [item]  goodies ,string inside_note )

  • recipient is the player to send to
  • message is the outside message
  • meat is the amount of meat to send
  • goodies is an optional map of items & amounts to send
  • inside_note is an optional inside message if sent as a gift

boolean kmail(kmessage km )

  • km allows you to send a kmail supplied in kmessage format. The only thing unusual here is that the "fromname" field will be used as the recipient. The other fields will be used appropriately to call the above kmail function.

Sends a kmail to player recipient, returning true if the kmail is successfully sent. Handles splitting the message into multiple messages if the number of item types in goodies is too large. Returns the result of send_gift() if the intended recipient is unable to receive the message due to being in HC or somesuch. Note that you can also specify the inside_note to be used inside gifts in that case. Use "\n" to specify a new line in the message.