Smithing bot? Need advice on workarounds and such.

Artscrafter

New member
A clannie of mine is looking to start up a smithing bot for our clan. The bot would go something like this:

(Pseudo)
Code:
While (true) {
   Check messages; parse kmails into an array of strings, one per kmail.
   For each kmail string: 
      {
      Verify that the sender is a member of the clan. // Question 1
      If not: { Parse items and return them to the sender. }
      Else: 
         {
         Parse items. // Question 2
         Find out what can be created from these items. // Question 3
         Create item(s) and send the finished product(s) back.
         }
      }
   }
   Delete messages.
   Pause for 60 seconds.
}

Question 1: How does one determine whether a given player is in the active character's clan? I'm aware that putting $clan into a buffbot's whitelist will allow all clan members to partake of that without the host having to constantly update, but is there any equivalent data type or method for a more general use?

Question 2: There's a handy extract_item(string) method that I've looked into, but the data type it returns is terrible for how I'd be using it - it's an array of ints where the index is a particular item. For example, if you parse a string that indicates receipt of two blue pixels, the way to find this out is to look at Returned_Array_Var[$item[blue pixel]] and see that its value is 2. Consequently, using this method to detect any of a large possible set of different items implies that I would have to check every possible smithable item's index and look for non-zero values. Is there any better way to do this?

Question 3: Is there any way to check whether two specific items can be smithed into something and what they make? Apart from checking creatable_amount results, since I want to allow the possibility that more than one request comes in between iterations of checking messages and I don't want one person's ingredients to interfere with another. At the moment I'm looking at writing a massive recipe lookup method that takes two items as inputs and checks them against a long, hardcoded string of if statements to return one item or a null - is there a better way to do this?
 

Nightmist

Member
[quote author=Artscrafter link=topic=769.msg3704#msg3704 date=1171411004]
*Snip*
[/quote]
First I'm going to start off with... *blank* Okay nevermind I'll go straight to the questions.

1. I personally can't think of anything that "auto-updates" without extra server hits right now.

2. Get familiar with "foreach" looping? (I assume thats what your meaning? The foreach will allow you to view the value of a "unknown key" in a map, so you don't have to loop through every single possible key.) (Or at least I think you call it a key? I'm thinking: "MapName[ KEY] = DONTKNOW")

3. Heh in other words, your looking for a createable_amount which only factors in certain items? (In this case the parsed items from question 2) At this current point of time the only thing I can think of is what you suggested. However apart from hardcoding it, generate the map when the script is started. You can do this my "file_to_map"ing internal datafiles. (I'm pretty sure smithing combinations are stored in a datafile.) Theres a messy more-complex-than-you-need example here: http://kolmafia.us/index.php/topic,759.0.html (Shameless advertising of own scripts). That one linked to merges two different datafiles but you should only need one? (I assume all the data needed to build a map with what you want is all in a single file) Come to think of it shouldn't you just be able to create a map of "item [item item] map" and just file_to_map it directly? (I suggest you get familiar with "foreach" looping before attempting to work with maps made from imported internal datafiles though)
 

zarqon

Well-known member
Question 1: I'm working on a treasurer/item bot for my clan as well, and I'm using this:

Code:
print("Loading clan members...");
string[int] get_clannies() {
   string orightml = visit_url("clan_detailedroster.php");
   orightml = substring(orightml,index_of(orightml,"showplayer.php")+14);
   string[int] clannies = split_string(orightml,"showplayer.php");
   foreach i in clannies
      clannies[i] = substring(clannies[i],index_of(clannies[i],"[b]")+3,index_of(clannies[i],"[/b]"));
   return clannies;
}
string[int] clan = get_clannies();
if (count(clan) == 0) abort("You ought to have a clan before running a clan-based bot.  Even a child of two knows this.");
print(count(clan)+" clan members detected.");
boolean is_clannie(string whozit) {
   foreach m in clan
      if (clan[m] == whozit) return true;
   return false;
}

Put that at the top and you'll be able to use is_clannie() anywhere.

Question 2. Much easier idea: require your clan members to include the name of the desired item as the kmail text. A little extra work for them, WAY easier to script. In the event that they don't specify anything, you could just try to put all of their items together (based on the type of item) and if it makes something send it back to them, if it doesn't, send back the items and tell them to specify the name.

A thought: when writing this, comparing extract_items() against get_ingredients() might be handy.

Question 3: can't think of an easy answer, but I can offer a possible way to isolate kmail ingredients:
1) put everything in your closet
2) based on the extract_items result, pull out only the items you got in that kmail.
3) any calculations from here should only use the items in your inventory (and possibly your equipped items)

Hope this helps somewhat. Good luck.
 

Paragon

Member
I know this may not be the most desired way to do things... but if your clannie kmailed with the name of the item that they were attempting to create in the msg title you could use that title to figure out what ingredianets you are looking for rather then having ingerdients and looking for a product. You could even make it so that you could make multiple items per msg as long as you had a seperator between the items you are trying to make.

so you send a kmail with a message or title like: [itemA] - [itemB] - [itemC]
then break them up with split string. Then foreach through each of them using int [item] get_ingredients(item) check if the ingredients were sent through the mail (by foreaching the returned int[item] get_ingredients(item) map to compare it to the returned extract_items() map) if they were sent then make the item otherwise skip that item, set a flag goto the next one and at the end write a message item X could not be made because of lack of ingredients and send any "left over" ingredients back to the sender.
 
Top