Window problems

Okay so I’m running into a problem with the default SenseConnector solution to windows. Basically, when I have more than one window in a room commands become very ambiguous. I have a lot of windows and manually naming them all is sort of undesirable. I’d rather be able to dynamically describe them based on where they connect to. Since only one window ever exists, it is hard to create useful names for them. Regardless of which side of the window you’re on, it is named the same. For example if we have two rooms connected by an West<->East relationship, and we put a SenseConnector between them then we should be able to refer to the window as the “east window” when in the western room, and the “west window” when in the eastern room. I have tried to override vocabWords and name to be functions that return values based on which room the player is in, but it seems as though this happens very early on is used in parsing setup and so on and doesn’t want to be dynamically generated.

I really hope I have explained this well enough.

I’m not entirely sure I understand this, but is the problem that if you have a window between rooms, the other side of the west window in one room is called east window in a neighbouring room, so it’s awkward to refer to the east window of the first room since a SenseConnector is putting both east windows in scope?

If so, the solution may be to use an Occluder to remove windows from scope when they’re not in the player character’s location.

Thanks for reading Eric,

Actually I mean, that since a window is made up of a single object that has two locations, it only has one description. If I call the window ‘east window’ it will make sense while you’re in the west room, but when you’re in the east room, the name no longer makes sense. I’m wondering how can I change the name of a window (and its relevant vocabWords) based on which side of the window the player is on.

Are you using adv3 or adv3Lite. I don’t know the latter, but if you’re using adv3 you can easily change the vocabWords during the game using the functions cmdDict.addWord() and cmdDict.removeWord(). Information on how to use these is found on p. 165 of “Learning TADS 3.”

All you need to do is call these functions as part of the player’s movement from room to room.

I’m not sure what you mean by “only one window ever exists.” This seems like an unnecessary difficulty that you’re creating for yourself. Why not, indeed, have a bunch of windows? I would add that I don’t see any obvious reason why you need a single window to be in both rooms. Why not put a separate window object in each room? If the two window objects need to be opened and closed in sync, you could model this using the master object functionality of doors.

Jim,

The only reason I am supposing one-window-per-two-rooms is because this is how a SenseConnector (based off MultiLoc) works as far as I understand it. You create a single SenseConnector and add each of the rooms that the ‘window’ connects to the locationList attribute. I would much prefer a SenseConnector that worked like doors do, where you actually create two separate objects and link them via a masterObject attribute. If you know of a way to do that, or I am seriously confused please let me know! :slight_smile:

Thank you for the information on dynamic vocabWords.

This sounds like a situation where it may be easier to use a two-sided Door to represent the window and a separate object to function as the SenseConnector. But that depends on what functionality you need out of the window (e.g. whether it needs to open and close).

Alternatively, you could use ThingState objects to control what the window is called and what vocab it responds to:

eastWindowState: ThingState
  stateTokens = ['east', 'e']
  name = 'east window'
;

westWindowState: ThingState
   stateTokens = ['west', 'w']
;

window: SenseConnector, Fixture 'east e west w window*windows'
   name = getState.name
   allStates = [eastWindowState, westWindowState]
   getState = (gPlayerChar.isIn(westRoom) ? eastWindowState : westWindowState)

;

This isn’t tested and it probably needs further tweaking, but something along these lines may do what you want.

Yeah the main issue here, is that when using a lot of windows, the window simply cannot be referred to as both the east and west window simultaneously. While in the east-room, in addition to looking through the (now) west window, there might also be an actual east window in this room and this will cause ambiguity. Perhaps I can use the ThingState with dynamic vocabWords and get a good combination of techniques. Does anyone have a suggestion for how to change the vocabWords as the player enters/exits the rooms in the SenseConnector’s location list? Is there a way for the SenseConnector to “hook” this event?

Thanks for all the info.

Untested, but you might try overriding sayDepartingDir(dir, self) on gPlayerChar – that is, on the me object (assuming that gPlayerChar points to me). This method is called during travel by the describeDeparture method of the room. The parameter ‘self’ should, I think, refer to the room being departed from, and ‘dir’ refers to the direction of travel.

hmmmmmmm

The whole point of my ThingState suggestion was that you wouldn’t have to change the vocabWords. In my suggested code, the getState property of the window changes the window from one state to the other according to whether the player character is in the room to the west of the window or the room to the east of it. The window then automatically picks up its name from whichever ThingState it’s in, and its current ThingState determines whether it can be referred to as the east window or the west window. As I understand it this already does everything you need. The whole point of using ThingState here is that a ThingState filters the words that can be used to refer to an object.

Here is my current implementation of a window. It works pretty well… Any recommendations?

[code]#charset “us-ascii”
#include <adv3.h>
#include <en_us.h>

class Window: Occluder, SenseConnector, Fixture

name = getState.name

connectorMaterial = glass

firstLocation = nil
secondLocation = nil
firstDirection = nil
secondDirection = nil

connectedDesc = 'This one provides a view into <<otherLocation.theName>>.'

disconnectedDesc = 'For some reason the glass is so opaque you cannot see through it.'

viewDesc = '<<if connected>><<connectedDesc>><<else>><<disconnectedDesc>><<end>>'

desc() {
    inherited; "<<viewDesc>>";
} 

inRoomDesc() {
    return ' A <<getState.name>> provides a view into <<otherLocation.theName.toTitleCase>>.';
}

connected() {
    return (firstLocation != nil || secondLocation != nil);
}

getFirstState() { return getDirectionalState(firstDirection); }
getSecondState() { return getDirectionalState(secondDirection); }

allStates() {
    return [getFirstState(), getSecondState()];
}

getState() {
    if (gPlayerChar.isIn(firstLocation))
        return getFirstState();
    return getSecondState();
} 

locationList() {
    return [firstLocation, secondLocation];
}

otherLocation() {
    if (connected()) {
        if (gActor.isIn(firstLocation))
            return secondLocation;
        return firstLocation;
    }
}

occludeObj(obj, sense, pov) {
    if (obj.isIn(pov.location)) {
        return nil;
    }
    
    if (obj.isIn(otherLocation)) {
        if (obj.isApparent()) {
            return nil;
        }
    }
    return true;
}

getDirectionalState(direction) {
    switch (direction) {
        case northDirection:
            return northWindowState;
        case southDirection:
            return southWindowState;
        case westDirection:
            return westWindowState;
        case eastDirection:
            return eastWindowState;
        case northwestDirection:
            return northwestWindowState;
        case southwestDirection:
            return southwestWindowState;
        case northeastDirection:
            return northeastWindowState;
        case southeastDirection:
            return southeastWindowState;
    }
}

dobjFor(LookThrough) {
    check() {
        if (nil == connected()) {
            reportFailure('You can\'t seem to actually see through this window.');
            exit;
        }
    }
    action() {
        "You peer into the <<otherLocation.name>>. <<otherLocation.desc>>";
    }
}   

;

eastWindowState: ThingState
stateTokens = [‘east’, ‘e’]
name = ‘east window’
;

westWindowState: ThingState
stateTokens = [‘west’, ‘w’]
name = ‘west window’
;

northWindowState: ThingState
stateTokens = [‘north’, ‘n’]
name = ‘north window’
;

southWindowState: ThingState
stateTokens = [‘south’, ‘s’]
name = ‘south window’
;

southwestWindowState: ThingState
stateTokens = [‘southwest’, ‘s’]
name = ‘southwest window’
;

southeastWindowState: ThingState
stateTokens = [‘southeast’, ‘e’]
name = ‘southeast window’
;

northwestWindowState: ThingState
stateTokens = [‘northwest’, ‘w’]
name = ‘northwest window’
;

northeastWindowState: ThingState
stateTokens = [‘northeast’, ‘n’]
name = ‘northeast window’
;
[/code]