T3: ActorState Switching

I have an NPC who is spontaneously changing from an InConversationState back to her previous state, which was an AccompanyingState, when the PC travels. I have set the attentionSpan of the InconversationState to nil. I would have expected that that would prevent TADS from switching her back to her previous state. But no.

What seems to be happening is that the library calls beforeTravel on the NPC, which calls beforeTravel on her InConversationState. This calls endConversation in the InConversationState. Somehow, and I’m not sure how, endConversation is firing setCurState on the NPC, and restoring her to her previous state in an inappropriate manner.

I can set previousState by hand, by setting it after I switch the NPC to her new state, so that it’s the current state. That will prevent the switching. But I’d rather understand what’s going on so I can override the method that is causing the trouble. The comments for activateState say, “We don’t remember prior states that aren’t conv-ready states.” But this seems not to be true, because the previous state was an AccompanyingState, not a ConversationReadyState. On the other hand, I don’t see how activateState could be causing the problem, because the comments appear accurately to describe the code.

Can anyone shed any light on this mystery? How can endConversation in an InConversationState be changing the NPC’s state to an AccompanyingState?

Sorry to be so abstract, but I’m trying to do the research and be specific, and when you research the specifics of the T3 library it does tend to get a bit abstract.

If I understand correctly, you are looking at the activateState method of InConversationState.

The relevant comment is above the one you’ve quoted:

What’s happening is that activateState sees that its previousState value is nil, and then unconditionally stores the old state, without checking whether it is a conversation state.

When you set previousState by hand, it’s no longer nil, and the behavior you want takes over: only conversation states will subsequently be stored.

You can override this by removing the nil check, or (for ease of maintenance) by reversing the logic at the end of the method.

modify InConversationState
    activateState(actor, oldState) {
        inherited(actor, oldState);
        if (!(oldState.ofKind(ConversationReadyState))) {
            previousState = getActor.curState;

I am pretty sure that the ‘actor’ value passed to this method is the NPC rather than the PC, but other methods in this class seem to use it differently. I’ve used getActor to be safe.

It might be OK to set previousState to nil, but the original activateState() method would guarantee a non-nil value in this property after a call, so the safest course is to do the same.