|
Anaristos Sorcerer
Joined: 17 Jul 2007 Posts: 821 Location: California
|
Posted: Fri Jul 22, 2011 2:52 am
A scoping mystery |
Let's examine the following user function:
Code: |
#LOCAL param
;;
$p1 = "[1;33m|119" // yellow | full services
$p2 = "[1;31m|22" // red | limited services
$p3 = "[1;90m|22" // grey | limited services
;;
$o = 2 // offset from edge of window
$y = 4 // current window row
;;
#WINDOW @rWind {@cup( $y, 1)@ced( 0)} // clear the window from the left edge of the current row to the end
;;
#LOOP @vpTop,@vpEnd {
$format = "&" + (5 + @vpLen - %len( @vpList.%i.Name)) + "s"
$room = @vpList.%i.Room
#IF (%walk( $room)) {$param = $p1} {#IF ($room != %mapvnum( )) {$param = $p2} {$param = $p3}}
#WINDOW @rWind {@cup( $y, $o)@cw" Room: "$param.1<send '@sendcl( $room, $param.2)' '@senddl( $room, $param.2)'>@vpList.%i.Name</send>@cw" "%format( $format, "Zone: ")@cb@vpList.%i.Zone@rc}
$y = $y + 1
}
;;
#RETURN
|
Specifically, let's focus on the following lines of code:
Code: |
$room = @vpList.%i.Room
#IF (%walk( $room)) {$param = $p1} {#IF ($room != %mapvnum( )) {$param = $p2} {$param = $p3}}
|
The function displays a formatted list of rooms on a window. The function displays a subset of the entire list which has been divided into frames of fixed (user-specified) number of lines, so in fact, this function is a scroller. The isolated line of code is charged with determining if the room can be walked from the current location. Depending on what %walk returns, a color is assigned to that particular display line.
As you may have noticed, the window is painted using the #WINDOW command. The window named in the command is not the session window and the function is called from a script which is invoked by a button owned by the displaying window, so in essence,
this function and all the associated scripts are running under the display window, not the session window (main window).
A problem arises because when the above code is executed as is, the walk function returns a null, even though there is a path to the room from the current location.
However, if the above code is changed to this:
Code: |
$room = @vpList.%i.Room
#EXECWIN @hWind {#IF (%walk( $room)) {$param = $p1} {#IF ($room != %mapvnum( )) {$param = $p2} {$param = $p3}}}
|
hWind contains the name of the session window and rWind contains the name of the display window.
the function works like a charm.
So this is a scoping mystery. It is a mystery because the parameter to the walk is a local variable containing an integer value. There is no addressing concern here, and what's more, there is no addressing that the function needs perform anyway. However, the function will not work if it is executed out of scope. This is equivalent to a function that adds 2 local numbers failing because it's not running in a pre-determined context. There is no context here, or rather, the function parameter is context-independent and the function itself lies in the mapper's native code, which can't be the problem because, if it were, the function would not work running in the session window's context either.
I will not make the claim that this is a bug, but I would be very interested to know why it works this way. |
|
_________________ Sic itur ad astra. |
|
|
|
Zugg MASTER
Joined: 25 Sep 2000 Posts: 23379 Location: Colorado, USA
|
Posted: Fri Jul 22, 2011 4:15 pm |
I think I understand this.
All of the mapper functions use the "current Location" object. This is the location displayed by the #LOC command. Each Window has it's own connection to the map. Normally only the main session window has a map associated with it, along with a location.
Your script is executed within whatever window has the button you are clicking on (as you described). Those child windows probably do not have any location object or map connection.
Remember that with the new mapper, each window can have it's own location allowing you to track multiple characters and to allow multiple session windows to share the same map.
What I would probably do is to put your #EXECWIN code into a function within the Session window itself and then call it using the @//SessionWindow/Function($room,$param) syntax and see if that also works. Your #EXECWIN solution is fine except that it prevents CMUD from compiling that line of code (it gets compiled and executed at runtime). By putting a function that does the %walk calculation into the main session window, you get the speed of compiled code and it *should* execute with the proper map connection and location info.
Another possibility is to move the Map Object from your main session window into a shared package and then enable access to that package from each of your child windows. But that might be more complicated and more buggy than the above solution.
Another possible solution is to put the line:
#MODULE SessionWindowName
just before the %walk line to see if that properly switches context to the main session window where the map location object is stored. |
|
|
|
|
|
|
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
|
|