Smelltastic
Member
I was writing a script to obtain any mall-purchasable familiars I was missing, and realized that while it was fairly short and simple it was also using a fairly wide array of functions and would make a great example script. I noticed a couple people here lately who seem new to coding/scripting in general, so I added some comments.
Below, and attached, is acquire_familiars.ash. It will purchase and grow any familiars you don't have that cost no more than your autoBuyPriceLimit, and will display any other familiars that are under 10M for you to consider manually purchasing. It is heavily commented with the intent of being a learning tool for those new to ASH.
Below, and attached, is acquire_familiars.ash. It will purchase and grow any familiars you don't have that cost no more than your autoBuyPriceLimit, and will display any other familiars that are under 10M for you to consider manually purchasing. It is heavily commented with the intent of being a learning tool for those new to ASH.
Code:
// acquire_familiars.ash
// Notepad++ with the 'ash' user defined language HIGHLY recommended!
// Get Notepad++ from https://notepad-plus-plus.org/.
// Get the ASH user-defined language mod from Bale's post at: http://kolmafia.us/showthread.php?3164-How-do-you-write-an-ASH-file
// Automaticaly obtain any purchasable familiars that are less expensive than your autoBuyPriceLimit setting.
void acquire_familiars() {
// can_interact() returns TRUE if we can interact with other players and the mall.
if( !can_interact() ) {
abort("This script is useless in-run!");
}
// Note this script does not actually check for mall access - it will fail for new accounts under a certain level.
// We don't worry about it because some edge cases really just aren't worth accounting for.
boolean[familiar] expensives;
boolean[familiar] moderates;
// get_property(prop) always returns a string. It needs to be converted to the appropriate data type.
// Note that to_int( get_property("autoBuyPriceLimit") ) would also work. I generally prefer dot notation for type casting.
int buy_limit = get_property("autoBuyPriceLimit").to_int();
// Loop through all existing familiars. 'fam' will reference each one in turn.
foreach fam in $familiars[] {
// have_familiar( familiar ) is a method that returns TRUE if you already own the referenced familiar.
// So, "!have_familiar(fam)" does the opposite; TRUE only if you DON'T own the familiar.
// It could also be written as "!fam.have_familiar()".
// fam.hatchling is a property that returns the item the familiar is obtained from.
// item.tradeable returns TRUE if it can be purchased from the mall.
if( !have_familiar(fam) && fam.hatchling != $item[none] && fam.hatchling.tradeable ) {
// historical_price( item ) returns Mafia's stored price of an item, and will never check the mall.
// mall_price( item ) checks the mall for the price, but no more than once per day.
// Here we use the historical price if it's available, and check the mall only if it's not (returns 0).
int p = fam.hatchling.historical_price();
if( p <= 0 ) p = fam.hatchling.mall_price();
if( p <= 0 ) continue; // If the price is still 0, it isn't available from the mall for some reason.
if( p <= buy_limit ) {
// We use retrieve_item first in case we have one somewhere grabbable, i.e. hagnk's or a clan stash.
// retrieve_item will also purchase the item from the mall IF autoSatisfyWithMall is on.
// It will abort the script if it fails UNLESS we grab its return value, so we store it
// in 'nothing' because we don't actually need it.
boolean nothing = retrieve_item(1, fam.hatchling);
// If we didn't get the item and autoSatisfyWithMall is off, it's because we didn't even try to mallbuy.
if( item_amount(fam.hatchling) < 1 && ! get_property("autoSatisfyWithMall").to_boolean() ) {
buy(1, fam.hatchling);
}
// If we still didn't get the item, we probably don't have any meat left. Abort.
// Note that our 'if' doesn't need curly braces {} if we're only executing one statement.
if( item_amount(fam.hatchling) < 1 )
abort("Failed to acquire " + fam.hatchling.to_string() + " - do you have enough meat?");
// When I first wrote this, I used 'use', but it turns out there are hatchlings that have a different
// function when you use them. So instead I have to visit the 'grow' URL directly.
// I had to find this URL by looking at the [grow] link next to the item on the inventory page.
// Turned out it calls inv_familiar.php with the property "which" set to "3", and "whichitem" to the
// ID of the item in question. You can obtain an item's id by running it through to_int().
// Note that it returns the entire page, but we do NOT catch it this time; this is because we don't
// need it and would rather the script go ahead and abort if it fails for any reason.
visit_url("inv_familiar.php?pwd="+my_hash()+"&which=3&whichitem="+fam.hatchling.to_int().to_string());
//use( 1, fam.hatchling );
// Below we deal with any familiars we aren't purchasing.
// Prices above over 10M indicate Mr. Store or other expensive fams. We don't track those.
} else if( p > 10000000 ) {
continue;
// If the price is between 2M and 10M, we'll display it as 'Expensive' for possible manual purchase.
} else if( p > 2000000 ) {
expensives[fam] = true;
// If the price is below 2M but above autoBuyPriceLimit, we'll display it as 'Moderate' for possible manual purch.
} else {
moderates[fam] = true;
}
}
}
// Because we're visiting the URLs directly Mafia may not always know what all we've grown, so let's
// refresh the terrarium, just in case.
cli_execute("refresh familiars");
// If we tracked any expensive familiars, display them.
if( expensives.count() >= 1 ) {
print("");
print("--- Expensive Familiars ----");
foreach fam in expensives {
// Print the familiar, its hatchling, and the hatchling's price.
// The to_string function can accept a Java formatting argument. The example below adds separating commas to an integer.
// More examples of Java string formatting can be found at: https://dzone.com/articles/java-string-format-examples
print( fam.to_string() + ", " + fam.hatchling.to_string() + ": ~" + fam.hatchling.historical_price().to_string("%,d") + " meat" );
}
}
// If we tracked any moderate familiars, display those too.
if( moderates.count() >= 1 ) {
print("");
print("--- Moderate Familiars ----");
foreach fam in moderates {
print( fam.to_string() + ", " + fam.hatchling.to_string() + ": ~" + fam.hatchling.historical_price().to_string("%,d") + " meat" );
}
}
}
// When this script is called from the CLI, Mafia always looks for a main() function and runs that.
// If we import this into another script, however, we'll want to be able to call it easily.
// Therefore the primary use of this script is written as a separate function, which is called from main().
void main() {
acquire_familiars();
}
Attachments
Last edited: