I think your best bet is to check each turn to see if the vampire has seen a cross, and change the state accordingly. There are quite a few different ways to go about this. Inside the actor itself, afterTravel can run checks immediately on entering a new location (if, say, you want the vampire’s description in the room to immediately appear as something like, “The vampire looks very upset.”) and idleTurn runs every turn that the vampire doesn’t take an action (but if you override idleTurn be sure to add ‘inherited;’ to the method, or the whole TADS Workbench will crash).
Within actorStates, takeTurn seems to do the same things as idleTurn (without the crashing), while afterAction runs every turn that the actor sees an action occuring (whether that action is taken by the player, the vampire, or yet another actor).
I’ve messed about with stuff like this before (and I probably will again), so I tried a little bit of experimental coding…
gameMain: GameMainDef
/* the initial player character is 'me' */
initialPlayerChar = me
;
startRoom: Room 'Start Room'
"This is the starting room. "
north=nextRoom
;
+hidingPlace: Container 'box' 'box';
++cross: Thing, Hidden 'cross' 'cross';
+ me: Actor;
+vampire: Person 'vampire' 'vampire'
canSeeCross=(vampire.canSee(cross) || vampire.canSee(cross2))
crossCheck()
{
if(canSeeCross && vampire.curState!=vampireCringing)
{
"<.p>The vampire hisses. <q>That cross! Hideous thing!</q>";
setCurState(vampireCringing); //set vampire to cringing state
}
else if(!canSeeCross && vampire.curState!=vampireStanding)
{
"<.p>The vampire relaxes. <q>The ambience is much nicer all of a sudden.</q>";
setCurState(vampireStanding); //return vampire to normal state
}
}
idleTurn() //called every turn by actor, unless it takes an action
{
inherited; //this does important stuff which we mustn't override
vampire.crossCheck();
}
;
++vampireCringing : AccompanyingState
specialDesc="The vampire seems very upset. "
accompanyTravel(leadActor, conn)
{
return leadActor == gPlayerChar;
}
afterAction() //called every turn someone takes an action, if the actor is in this actorState
{
vampire.crossCheck();
}
;
++vampireStanding : AccompanyingState
specialDesc="The vampire is here, elegant and darkly dressed."
isInitState = true
accompanyTravel(leadActor, conn)
{
return leadActor == gPlayerChar;
}
afterAction()
{
vampire.crossCheck();
}
;
//////////////////////NEXT ROOM//////////////////
nextRoom: Room 'Next Room'
south=startRoom
;
+cross2: Thing 'cross' 'cross'
;
This is only one possible (probably inelegant) solution. You could break up the two checks (can I see a cross/can I NOT see a cross) into the two different actorStates, for example, and remove the idleTurn stuff entirely. Then the vampire will only notice a cross in plain sight (or the absence of a cross) on the first actual turn after you enter a location. It all depends on the messages you write.
It’d also be nice to have like a vampireRepellant mix-in class that you could add to any crosses, garlic, rosaries, wolfsbane etc that you happen to implement. For that you could probably do a check like so:
//NB. I've not tested this code in its current form
local seenRepellant = nil;
foreach(local cur in vampire.location.contents)
{
if(cur.ofKind(vampireRepellant))
{
seenRepellant = cur;
return seenRepellant; //return that item
}
}
Which would also allow you to get the name of the item the vampire was worried about and stick it into messages. Again, there’s probably a better way to do that, but unless you’re doing anything really CPU intensive with your game, it would work.
For most of this stuff, I’ve referred to the TADS 3 Tour Guide. I know there’s lots of different manuals and tutorials, but that’s the one I look at the most often.
Hope this helps.