Register to post in forums, or Log in to your existing account
 

Play RetroMUD
Post new topic  Reply to topic     Home » Forums » zMUD General Discussion
Medakan
Novice


Joined: 15 Dec 2015
Posts: 41
Location: Seattle

PostPosted: Mon Jan 23, 2017 6:16 pm   

zMUD script rewrite
 
Anyone willing to share ideas and suggestions is greatly appreciated.

The original script can be found in this post: http://forums.zuggsoft.com/forums/viewtopic.php?t=38906

Background:
This script was originally written by Markus (a community member over at WoTmud).
The script sends a look command and then takes the room name, first line of the room description, and room exits and attempts to #TELEPORT map location to the correct room.

Why the rewrite?
Primarily as a learning experience, and an attempt to improve upon the original.
Format the script to follow naming conventions for my HoM script package I share with WoTmud community.
Attempt to increase script speed and reliability, sometimes original would fail.

What I attempted to do:
Break the script down into smaller sections (#ALIAS) that only get called when necessary, instead of a 100+ line trigger like in the original.
Capture every line of the room description instead of just the first line of the description, reformat captured description and %roomdesc to attempt to match.
When process gets down to the point where it can not precisely match, uses %random to guess.

Functions that are still a work in progress:
Help file for users.
Toggle command for users to turn messages on/off.
Command for users to easily change message colors.

Other ideas:
Use %mapfilter to limit %random matching in the findMatchExit alias to current zone only?


Code:
#CLASS {Mapper|Find}
#ALIAS find {
   #T+ {findRoomTrigger}
   #VAR findRoomDesc {}
   look
   #IF (@showFindMessage) {#SHOW {@findMXPcolor(@findColorSearch,"Searching map...")}}
   }
#ALIAS findMatchRoom {
   #IF (@showFindMessage) {findMessageRoom}
   #IF (%numitems(@findRoomByName)=1) {#TELEPORT @findRoomByName}
   #IF (%numitems(@findRoomByName)>1) {findMatchDesc}
   }
#ALIAS findMatchDesc {
   #VAR findRoomByDesc {}
   #FORALL @findRoomByName {#IF (%subchar(%subchar(%roomdesc(%i),%crlf,"")," |","")=%subchar(%subchar(@findRoomDesc,%crlf,"")," |","")) {#ADDITEM findRoomByDesc %i}}
   #IF (@showFindMessage) {findMessageDesc}
   #IF (%numitems(@findRoomByDesc)=1) {#TELEPORT @findRoomByDesc} {findMatchExit}
   }
#ALIAS findMatchExit {
   #VAR findRoomByExit {}
   #FORALL @findRoomByName {#IF (@findRoomExit=%sort(%roomexit(%i))) {#ADDITEM findRoomByExit %i}}
   #IF (@showFindMessage) {findMessageExit}
   #IF (%numitems(@findRoomByExit)=0) {
      #IF (%numitems(@findRoomByDesc)=0) {
         #IF (%ismember(%roomkey(),@findRoomByName)) {} {
            #TELEPORT %item(@findRoomByName,%random(1,%numitems(@findRoomByName)))
            }
         }
      }
   #IF (%numitems(@findRoomByExit)=1) {#TELEPORT @findRoomByExit}
   #IF (%numitems(@findRoomByExit)>1) {
      #IF (%numitems(@findRoomByDesc)=0) {
         #IF (%ismember(%roomkey(),@findRoomByName)) {} {
            #TELEPORT %item(@findRoomByExit,%random(1,%numitems(@findRoomByExit)))
            }
         } {
         #VAR findExitResults {}
         #FORALL @findRoomByDesc {#IF (%ismember(%i,@findRoomByExit)) {#ADDITEM findExitResults %i}}
         #TELEPORT %item(@findExitResults,%random(1,%numitems(@findExitResults)))
         }
      }
   }
#ALIAS findMessageRoom {
   #IF (%numitems(@findRoomByName)=0) {#SHOW %crlf {@findMXPcolor(@findColorFail,"Room name not found, check your map!")}}
   #IF (%numitems(@findRoomByName)=1) {#SHOW %crlf {@findMXPcolor(@findColorSuccess,"Room found! Setting map position.")}}
   #IF (%numitems(@findRoomByName)>1) {#SHOW %crlf {@findMXPcolor(@findColorSearch,"Multiple matches, searching descriptions...")}}
   }
#ALIAS findMessageDesc {
   #IF (%numitems(@findRoomByDesc)=0) {#SHOW %crlf {@findMXPcolor(@findColorFail,"Failed to match room description...")}}
   #IF (%numitems(@findRoomByDesc)=1) {#SHOW %crlf {@findMXPcolor(@findColorSuccess,"Description Found! Setting map position.")}}
   #IF (%numitems(@findRoomByDesc)>1) {#SHOW %crlf {@findMXPcolor(@findColorSearch,"Multiple matches, searching exits...")}}
   }
#ALIAS findMessageExit {
   #IF (%numitems(@findRoomByExit)=0) {
      #SHOW %crlf {@findMXPcolor(@findColorFail,"Failed to match room exits...")}
      #IF (%numitems(@findRoomByDesc)=0) {
         #IF (%ismember(%roomkey(),@findRoomByName)) {
            #SHOW %crlf {@findMXPcolor(@findColorSuccess,"Map position is already in room with matching room name. No action taken.")}
            } {
            #SHOW %crlf {@findMXPcolor(@findColorSuccess,"Setting map position to room with matching name (random).")}
            }
         } {}
      #IF (%numitems(@findRoomByDesc)>1) {
         #SHOW %crlf {@findMXPcolor(@findColorSuccess,"Setting map position to room with matching description (random).")}
         } {}
      } {}
   #IF (%numitems(@findRoomByExit)=1) {#SHOW %crlf {@findMXPcolor(@findColorSuccess,"Exits Found! Setting map position.")}}
   #IF (%numitems(@findRoomByExit)>1) {
      #SHOW %crlf {@findMXPcolor(@findColorSearch,"Multiple exits match...")}
      #IF (%numitems(@findRoomByDesc)=0) {
         #IF (%ismember(%roomkey(),@findRoomByName)) {
            #SHOW %crlf {@findMXPcolor(@findColorSuccess,"Map position is already in room with matching name and exits. No action taken.")}
            } {
            #SHOW %crlf {@findMXPcolor(@findColorSuccess,"Setting map position to room with matching name and exits (random).")}
            }
         } {
         #SHOW %crlf {@findMXPcolor(@findColorSuccess,"Setting map position to room with matching name and exits (random).")}
         }
      }
   }
#FUNCTION findMXPcolor {<color %1>%2</color>}
#VAR findColorFail {red darkgray}
#VAR findColorSearch {green darkgray}
#VAR findColorSuccess {blue darkgray}
#VAR findRoomByDesc {} {}
#VAR findRoomByExit {} {}
#VAR findRoomByName {} {}
#VAR findRoomDesc {} {}
#VAR findRoomExit {} {}
#VAR findRoomName {} {}
#VAR findExitResults {} {}
#VAR showFindMessage {1}
#TRIGGER "findRoomTrigger" {%e[36m{^Someone}([A-Z]*)%e[0m$} {
   #T+ {findExitTrigger}
   #VAR findRoomName {%replace("%1","'","''")}
   #VAR findRoomByName {%mapquery(NAME = '@findRoomName')}
   } "" {case|color|disable}
#COND {^*$} {
   #T+ {findLineTrigger}
   } "" {Within|Param=1}
#TRIGGER "findLineTrigger" {^*$} {
   #IF (%line =~ "^~[ obvious exits: * ~]$") {#T- {findLineTrigger}} {#ADDITEM findRoomDesc %line}
   } "" {disable}
#TRIGGER "findExitTrigger" {^~[ obvious exits: (*) ~]$} {
   #STATE findRoomTrigger 0
   #T- {findRoomTrigger}
   #T- {findExitTrigger}
   #VAR findRoomExit {%sort(%subchar(%lower(%1)," ","|"))}
   findMatchRoom
   } "" {case|disable|notrig}
#CLASS 0
Reply with quote
Vijilante
SubAdmin


Joined: 18 Nov 2001
Posts: 5182

PostPosted: Mon Jan 23, 2017 10:43 pm   
 
Code:
#ALIAS findMatchDesc {
   #VAR findRoomByDesc {}
   #FORALL @findRoomByName {#IF (%subchar(%subchar(%roomdesc(%i),%crlf,"")," |","")=%subchar(%subchar(@findRoomDesc,%crlf,"")," |","")) {#ADDITEM findRoomByDesc %i}}
   #IF (@showFindMessage) {findMessageDesc}
   #IF (%numitems(@findRoomByDesc)=1) {#TELEPORT @findRoomByDesc} {findMatchExit}
   }
Ugh! Have %mapquery do all the work; much better.
Code:
#ALIAS findMatchDesc {
   #VAR findRoomByDesc {%mapquery(%concat("(Desc = '", @findRoomDesc, "') AND (ObjId IN (", %replace(@findRoomByName, "|", ","), "))"))
   #IF (@showFindMessage) {findMessageDesc}
   #IF (%numitems(@findRoomByDesc)=1) {#TELEPORT @findRoomByDesc} {findMatchExit}
   }


Let's fix that trigger mess to make as much as possible be automatic.
Code:
#TRIGGER "findRoomTrigger" {%e[36m{^Someone}([A-Z]*)%e[0m$} {
   #T+ {findExitTrigger}
   #VAR findRoomName {%replace("%1","'","''")}
   #VAR findRoomByName {%mapquery(NAME = '@findRoomName')}
   } "" {case|color|disable}
#COND {} {
   #IF ([[%begins]](%line,  "[ obvious exits: ")) {#STATE findRoomTriigger 2}} {#ADDITEM findRoomDesc %line}
   } "" {looplines|param=50}
#COND {^~[ obvious exits: (*) ~]$} {
   findRoomDesc=%replace(@findRoomDesc,"|",%crlf)
   #T- {findRoomTrigger}
   #VAR findRoomExit {%sort(%subchar(%lower(%1)," ","|"))}
   findMatchRoom
   } "" {case|reparse}


You could use some #IF else chaining to make things a little faster. Change your check for (%numitems>1) to (%pos(@var,"|")!=-1), and do that check first then on an else to that #IF check for (@var=""); a final else for the only alternative. That removes extra function calls and saves from having to have %numitems examine everything when all you need to know is that it is more than 1.
_________________
The only good questions are the ones we have never answered before.
Search the Forums
Reply with quote
Medakan
Novice


Joined: 15 Dec 2015
Posts: 41
Location: Seattle

PostPosted: Wed Jan 25, 2017 11:43 pm   
 
Vijilante wrote:
Let's fix that trigger mess to make as much as possible be automatic.
Code:
#TRIGGER "findRoomTrigger" {%e[36m{^Someone}([A-Z]*)%e[0m$} {
   #T+ {findExitTrigger}
   #VAR findRoomName {%replace("%1","'","''")}
   #VAR findRoomByName {%mapquery(NAME = '@findRoomName')}
   } "" {case|color|disable}
#COND {} {
   #IF (%begins(%line,"[ obvious exits: ")) {#STATE findRoomTrigger 2} {#ADDITEM findRoomDesc %line}
   } "" {looplines|param=50}
#COND {^~[ obvious exits: (*) ~]$} {
   findRoomDesc=%replace(@findRoomDesc,"|",%crlf)
   #T- {findRoomTrigger}
   #VAR findRoomExit {%sort(%subchar(%lower(%1)," ","|"))}
   findMatchRoom
   } "" {case|reparse}



Couple questions about the above trigger (I also removed what I think are 4 typos in above quote):

First off the #COND {} doesn't work for me, I tried this in an earlier attempt because I read a similar example in the help files. This is why in my version I use the ^*$ pattern to capture an entire line. Couldn't get #COND {} to work for me. It never triggers so never moves to next state.

With the typos removed and if I add the ^*$ in the blank condition the trigger only captures the first line of the room desc. Any idea why? I couldn't get looplines to work for me in any previous attempt similar to this either.

I like the idea of setting the trigger up like this, but my version above is the only way I could get it to work through testing.

Any ideas?
Reply with quote
Medakan
Novice


Joined: 15 Dec 2015
Posts: 41
Location: Seattle

PostPosted: Thu Jan 26, 2017 2:37 am   
 
Vijilante wrote:
Code:
#ALIAS findMatchDesc {
   #VAR findRoomByDesc {}
   #FORALL @findRoomByName {#IF (%subchar(%subchar(%roomdesc(%i),%crlf,"")," |","")=%subchar(%subchar(@findRoomDesc,%crlf,"")," |","")) {#ADDITEM findRoomByDesc %i}}
   #IF (@showFindMessage) {findMessageDesc}
   #IF (%numitems(@findRoomByDesc)=1) {#TELEPORT @findRoomByDesc} {findMatchExit}
   }
Ugh! Have %mapquery do all the work; much better.
Code:
#ALIAS findMatchDesc {
   #VAR findRoomByDesc {%mapquery(%concat("(Desc = '", @findRoomDesc, "') AND (ObjId IN (", %replace(@findRoomByName, "|", ","), "))"))
   #IF (@showFindMessage) {findMessageDesc}
   #IF (%numitems(@findRoomByDesc)=1) {#TELEPORT @findRoomByDesc} {findMatchExit}
   }



Quick question about this part:

What happens here if multiple rooms have the same description? In the top version I use #ADDITEM to add to the findRoomByDesc variable just in case this happens. I'm not familiar with how %mapquerry AND ObjId IN works to know what I need to do to include for the possibility of duplicate descriptions. Vijilante's example will only place a single roomID in findRoomByDesc variable?
Reply with quote
Vijilante
SubAdmin


Joined: 18 Nov 2001
Posts: 5182

PostPosted: Fri Jan 27, 2017 11:55 am   
 
Use the blank pattern with looplines. Use a pattern of * with looppat.

%mapquery returns a list, so just as in your first %mapquery if multiple rooms match they will all be in the list. My assumption is that you are using the correct %roommode so that the first query will return values on the ObjId field. If you are using the vNum then I believe that field is named RefNum in the database. For a description of the IN operator in the SQL language go here.
_________________
The only good questions are the ones we have never answered before.
Search the Forums
Reply with quote
Medakan
Novice


Joined: 15 Dec 2015
Posts: 41
Location: Seattle

PostPosted: Fri Jan 27, 2017 4:34 pm   
 
I place the new version of the triggers in the script and the #COND {} does not fire...

Code:
* HP:Healthy MV:Full > look
Searching map...
Marsh Road
The road runs past an inn here, a two-story building of rough, green-veined
stone topped with pale green tiles. There are two large mounting blocks
directly in front of the inn. A painted wooden sign hangs above the door.
Marsh Road continues to the east and west.
[ obvious exits: E S W ]
South: A young woman walks by.
|1|.A dun mare is here, snorting angrily.

* HP:Healthy MV:Full >


@findRoomName captures the room name
@findRoomsByName has room ids in it

The #TRIGGER in settings is still enabled and set at the blank condition (state 1)

@findRoomDesc blank as is all the rest of the variables and as you can see above the rest of the messages never fire...

What am I doing wrong?
Reply with quote
Medakan
Novice


Joined: 15 Dec 2015
Posts: 41
Location: Seattle

PostPosted: Fri Jan 27, 2017 4:39 pm   
 
My version of the triggers...

Code:
* HP:Healthy MV:Fresh > look
Searching map...
Marsh Road
The road runs past an inn here, a two-story building of rough, green-veined
stone topped with pale green tiles. There are two large mounting blocks
directly in front of the inn. A painted wooden sign hangs above the door.
Marsh Road continues to the east and west.
[ obvious exits: E S W ]
South: Nieda Sidoro is keeping a sharp eye on her establishment.
A young woman walks by.
A dun mare is here, snorting angrily.

* HP:Healthy MV:Fresh >
 Multiple matches, searching descriptions...

 Description Found! Setting map position.


All applicable variables fill and I have full room desc in @findRoomDesc and you can see it fire through because messages show.
Reply with quote
Vijilante
SubAdmin


Joined: 18 Nov 2001
Posts: 5182

PostPosted: Sun Jan 29, 2017 10:39 am   
 
What works is what counts. I have never had a problem using a blank pattern with a loop lines trigger. If you look at the trigger state in the settings editor is its type set to loop lines?

I could have made a few mistakes in writing it out as I did. In fact, I think removing the "" for class is required on the #COND, which I see I forgot. I also see that I did not remove #T+ in the first state that no longer applies to anything.
_________________
The only good questions are the ones we have never answered before.
Search the Forums
Reply with quote
Medakan
Novice


Joined: 15 Dec 2015
Posts: 41
Location: Seattle

PostPosted: Tue Jan 31, 2017 4:13 am   
 
Got looplines to work with the blank condition by removing the "".

Thanks Vijilante!
Reply with quote
Display posts from previous:   
Post new topic   Reply to topic     Home » Forums » zMUD General Discussion All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

© 2009 Zugg Software. Hosted by Wolfpaw.net