Feature - Implemented Track hacienda layout

zarqon

Well-known member
I've wanted for some time to write support for the choice adventures in the Island Barracks into BBB. Obviously in order to do this, some knowledge of what you have already encountered (and where) is necessary, and it must persist across script instances and logins. So I thought I would track the current hacienda progress in a mafia-like style using two properties, lastHaciendaReset and lastHaciendaLayout. Like the old Hidden City layout property, the lastHaciendaLayout property would be an 18-character string (default "000000000000000000") with each character representing one of the choice termini. As you explore the hacienda, those characters would be replaced depending on what you find:

F - fight
R - reward (the location-specific item, or in one case meat)
K - key
C - clue
f - unvisited fight (deduced when the other two locations in the room are R and K/C)
r - unvisited reward (deduced)
k - unvisited key/clue (deduced)

I ran into some major problems trying to implement this tracking, however. Mainly, there's no way to get the text of an automated noncombat. I actually wrote some 50 lines of code tracking everything, using the lastEncounter property, extract_items(), extract_meat(), and contains_text(), before I realized that I couldn't actually access the page text for the last-encountered choice.php.

That means our only options for tracking your Hacienda progress in a script are:

  1. Using visit_url() to adventure there (as slyz's lovely Nemesis script does), which sidesteps tons of mafia automation features like running your mood, recovery, configured before/after battle scripts, etc (if you want to keep them you have to spend a lot of code simply trying to duplicate mafia's existing functionality). This tracking also breaks if you do any of the exploration outside the script.
  2. Parsing of session_logs() after every turn. This has the benefit of working no matter how you adventure, and you don't have to re-invent the wheel as you do with visit_url()-ing your turns. However, the text returned from that function can be massive, so I suspect running lots of string-parsing on that between every combat would noticeably slow things down.
So I would like to suggest that mafia itself track the Hacienda, either in the form I suggested or in some other form. I would like to encourage a single layout property, though, rather than a property for each choice terminus (or two per as in slyz's script).

Find a fight? This room is F (may replace f).
Find a clue? Indicated room gets k (if not already K) and this room is C (may replace k).
Find a key? K (may replace k).
Find an item? R (may replace r, or F post-quest).
Other results could be ignored.

If this information were tracked, not only could BBB add automation for completing the (otherwise rather irksome) AT Nemesis quest, but mafia could also add helpful spoilers for relay players or even automate the acquisition of goals. And if he wanted to, slyz could stop reinventing the wheel and remove quite a lot of code from his script, while improving it at the same time (since it would lose tracking vulnerabilities).
 
Last edited by a moderator:

Darzil

Developer
If the wiki is correct and each room contains one with Fight, one with key or clue to key, and one with an item, we can learn quite a lot about what is going on.

I don't mind looking at it, but it'd be a while before I could test, as none of my characters are currently AT.
 

zarqon

Well-known member
I wrote the following to strip results from the session log and it's not actually all that slow:

PHP:
string log = session_logs(1)[0];
matcher choicebit;
int room;
for i from 413 to 418
   for j from 1 to 3 {
      room = (i - 413)*3 + j - 1;
      if ($strings[K,R,C] contains get_property("lastHaciendaLayout").char_at(room)) continue;  // known final results; skip
      choicebit = create_matcher("choice.php\\?pwd&whichchoice="+i+"&option="+j+"\\r(.*?)[$\\r]",log);
      if (!choicebit.find()) continue;
      print(i+"/"+j+": "+choicebit.group(1));
   }

But I've realized another issue with it: the session logs don't show clues found. If it did, I could actually write Hacienda tracking using this code.

EDIT: It yielded these results:

413/1: Round 0: zarqon
413/2: You acquire taco shell (5)
414/1: You acquire an item: silver salt-shaker
414/2: Round 0: zarqon
415/1: You acquire an item: fancy beef jerky
415/2: Round 0: zarqon
416/1: You acquire an item: sleep mask
417/1: Round 0: zarqon
417/2: You gain 163 Meat
418/1: Round 0: zarqon
418/2: You acquire an item: decanter of fine Scotch
418/3: You acquire an item: hacienda key

Which aside from showing that I've been rather unlucky so far, also shows that tracking at least the majority of situations is possible via session logs. As a partial implementation of this feature, perhaps you could log clues in the session log (and perhaps the CLI as well) when found?
 
Last edited:

Winterbay

Active member
The code in slyz' nemesis.ash script is pretty good at keeping track of the layout if you need some sort of starting point.
 

zarqon

Well-known member
Yeah, I gleaned some useful bits from that. That's a pretty awesome script.

As I've mentioned, I don't like the limitation of only being able to track progress by using that script (running just one adventure manually could screw it up), and I also wasn't fond of the property bloat (it adds 36 properties just to track your progress).

Here's the fruit of my scripting labor today: a function which handles tracking almost everything by reading your session log. It has one notable flaw at present: it can't handle clues (because the session log contains nothing for clues). It does, however, deduce the contents of the third location in a room when you explore two of them (deduced rooms are lowercase).

PHP:
void hacienda_tracking() {
   if (get_property("lastHaciendaReset").to_int() < my_ascensions() || get_property("lastHaciendaLayout").length() < 19) {
      set_property("lastHaciendaLayout","0000000000000000000");
      set_property("lastHaciendaReset",my_ascensions());
   }
   buffer hl;
   hl.append(get_property("lastHaciendaLayout"));
   if (get_property("questG04Nemesis") == "finished" && !contains_text(hl,"W")) {  // W for Puttin' on the Wax
      hl.replace(17,18,"W");
      set_property("lastHaciendaLayout",hl);
   }
   boolean save_room(int r, string value) {
      if (r < 0 || r > 18 || value.length() != 1 || value == char_at(hl,r)) return true;
      if ($strings[R,K,C,W] contains char_at(hl,r))
         return vprint("Room "+r+" already contains content: "+char_at(hl,r),-2);
      hl.replace(r,r+1,value);
      set_property("lastHaciendaLayout",hl);
      if (get_property("questG04Nemesis") != "finished") {  // deduce room when 2/3 are known
         int[string] cont;  
         for i from (value - (value % 3)) to (value - (value % 3) + 2) cont[to_lower_case(hl.char_at(i))] += 1;
         if (cont["0"] == 1) if (!(cont contains "f")) save_room(index_of(hl,"0",value - (value % 3)),"f");
          else if (!(cont contains "r")) save_room(index_of(hl,"0",value - (value % 3)),"r");
          else save_room(index_of(hl,"0",value - (value % 3)),"k");
      }
      return vprint("BBB: Hacienda room "+r+" set to '"+value+"'.","#F87217",4);
   }
   string log = session_logs(1)[0] + session_logs(2)[1];
   matcher cres; int room;
   vprint(hl,9);
   for i from 413 to 418
      for j from 1 to 3 {
         room = (i - 413)*3 + j - 1;
         cres = create_matcher("choice.php\\?(?:pwd&)?whichchoice="+i+"&option="+j+"(?:&pwd)?\\r(.*?)[$\\r]",log);
         while ($strings[F,0,f,r,k] contains hl.char_at(room) && cres.find()) {
            vprint(i+"/"+j+": "+cres.group(1),9);
            switch {
               case (index_of(cres.group(1),"Round 0:") == 1): save_room(room,"F"); break;
               case (index_of(cres.group(1),"hacienda key") > 15): save_room(room,"K"); break;
               case (create_matcher("You gain \\d+ Meat",cres.group(1)).find()):
               case (index_of(cres.group(1),"You acquire ") == 1): save_room(room,"R"); break;
               default: save_room(room,"C");
            }
         }
      }
}

I've also written BBB to take advantage of this. In order of preference, it will seek out the last 'k' (ungotten key/clue), then the last 0 (unexplored), then the last r (unvisited reward), then the last f or F (fight), then the last W (wax). What this means is that it will keep discovering new zones until they are all discovered, at which point it will go to fights. After completing the quest, each of those fight locations will become a reward location, so the F's and f's will change to R's and the only remaining goal will be the W (Puttin' on the Wax), which contains all the valid options you might want to pursue (skip or record).

If mafia logs clues encountered I'll be able to update the tracking to account for clues, and this will be optimal handling. Woohoo!

If mafia completely tracks it instead, I'll happily delete all of this and we'll have optimal handling as well. Woohoo!
 
Last edited:

Bale

Minion
I would also find this feature very helpful since I always track it manually.

If the wiki is correct and each room contains one with Fight, one with key or clue to key, and one with an item, we can learn quite a lot about what is going on.

I have done this quite a few time and I can guarantee that the wiki is correct.
 

zarqon

Well-known member
I have modified my script (and the above post) to deduce the third location in a room when two are known (during the quest only). Amazing how much of this was actually scriptable after all. I settled on 9 possible values:

0: unexplored
F: fight
K: key
C: clue
R: reward
W: puttin' on the wax (automatically assigned post-quest)
f,k,r: deduced contents are lowercase versions, i.e. if a room currently has RF0, the '0' will be set to 'k'.

All that's left is setting the clues, which would require mafia to log them. Something simple like "You find a clue: a small crowbar" would do very nicely as a stopgap between now and a full implementation. Hint, hint, nudge nudge. :)
 

Darzil

Developer
I'm working on it, stopped trying to fix syntax errors around midnight last night. Interestingly I also chose lowercase version for deduced content.

I also need to support pre/post quest differences.
 

Darzil

Developer
Well, totally untested (ok, it compiles and doesn't throw errors on startup), but here's a patch.

In theory, if I got all the logic right, it should record finding clues, record the visited locations, work with clues, make deductions about what will be found where, and provide appropriate spoliers. The layout will be updated upon Nemesis quest completion, and more deductions made if possible. Also relies on my understanding of wiki (before quest completion, each room contains key or clue, fight and reward, after quest completion each room contains key or clue and two rewards, unless claimed earlier).

Lots of ifs there, though, so not planning to release into the wild until either I or another can ascend AT and test.
 

Attachments

  • Hacienda.patch
    15.1 KB · Views: 31

Darzil

Developer
Still got to add spoilers for the first one, which will be just a total of keys/clues found/picked up so far.

My plan is to ascend again on Wednesday, probably, as Accordion Thief, so will probably be Thursday or Friday before I can test and rewrite this to get it all working. Sorry, grabbing the new Seal Clubber skills took priority!
 

Attachments

  • Hacienda.patch
    15.9 KB · Views: 34

zarqon

Well-known member
Fabulous!

I've been a bit ill and will be spending some time yet in aftercore, so won't be able to test anywhere near as soon as you.

I did look at your patch and noted two issues:

1) Does the haciendaLayout property reset on ascension? I didn't see anything indicating that it did, but that might just be my ignorance of the way mafia works. I'd expected a "lastHaciendaReset" property or somesuch.
2) Checking for "acquire an item" fails for the two rooms that contain multiple items, as I discovered myself when testing my tracking code. The message in that case is "You acquire X <plural name>", possibly with additional markup. You might change it to "You acquire ", I'm fairly sure that won't give false positives. Or if mafia has built-in item acquisition detection you could access, that might be easier.

Since I checked your patch to be sure we're using all the same letters, I'll go ahead with my tracking and choice selection update for BBB, and when this rolls out I can simply delete the redundant tracking. I do think that my session log parsing code was rather a neat trick while it lasted. :)
 

Darzil

Developer
On one, the line Preferences.resetToDefault( "haciendaLayout" ); in the quest database is triggered when you ascend, so this will reset it.

On two, thanks, will tweak it when I am ready for testing.
 

Darzil

Developer
r12826.

Extensively tested, but there are a lot of combinations, and I couldn't go back and retest rooms I'd already visited effectively.

Adds spoilers to non-combats, detailed ones for the halls and rooms, counts of keys gained and located in hall choice non-combat (pre-quest) or rewards gained and located (post-quest). Predicts what is in rooms based on logic documented in wiki. Recognises (and logs) clues.

haciendaLayout holds the currently known and worked out layout, using the following symbols:
K - Key known and taken
k - Key known and not taken
C - Clue known and taken
c - Clue known and not taken
u - Clue or Key, not taken
F - Fight known and has happened at least once
f - Fight known and not fought
R - Reward known and taken
r - reward known and not taken
0 - unknown
X - unknown, should be impossible

I'm not including tracking of Putting on the Wax, as it's always in the same place, and if I did, it wouldn't be clear if there was a reward there or not. It is included in the spoilers, however.
 
Top