following npc's

HELP!

I am trying to get a npc to move along a track – when the pc enters room 1 the npc moves from nil to room 1, then room 2, 3, 4, 3, 2, 1 and back into nil with the pc following, who may or may not fail to spot the npc. I will be using a random fuse to move the npc into the adjoining room 5 for the pc to follow and find out what the npc does in room 5. It sounds obtuse but makes sense in the context of the game. The object being, instead of using the npc tourguide method, to have the pc fail or succeed in getting the information in room 5. I tried the example in the manual but all the npc did was bounce between one room and another when the pc entered; pc enters room 1, npc moves to room 2, pc moves to room 2, npc moves to room 1, not room 3, also tried starting the pc in room 4 and moving to room 1, same thing happened. Can anyone help?

Without seeing your code it’s difficult to know where it’s breaking down.

Have you thought of using an AgendaItem for the NPC? I don’t know if that would work in this case – it’s been a couple of years since I did any T3 – but maybe if you recode it as an AgendaItem, you’ll spot the bug.

The code is as per learning tads 3 page 237 all I did was add the extra rooms, reset idx to routeList.indexOf() (which may be wrong if the idx is now set to the last item in the list), and I removed isDone so the whole thing is repeated, if this worked then I would use a check on the fuse to set isDone to true so it repeats a set number of times.

+ bobWanderAgenda: AgendaItem isReady = (bob.curState == bobWalking) initiallyActive = true agendaOrder = 10 routeList = [highStreet, northStreet, southPark, northPark] invokeItem() { local idx = routeList.indexOf(bob.getOutermostRoom); if(idx && idx < routeList.length()) { local dest = routeList[++idx]; bob.scriptedTravelTo(dest); if(idx >= routeList.length()) isDone = true; } } ;

It would be more useful to see your code, rather than the code from “Learning TADS 3,” as I have a copy of that already.

From your description of the edits you’ve made in that code, I don’t understand how your edits relate to the design concept you initially set forth. For instance, “then back into nil with the PC following.” Surely that’s not what you meant to say. I’m also wondering what happens if the player follows the NPC back and forth through rooms 1 to 4, but then does not follow the NPC into room 5 to observe what happens there. Won’t the whole cycle need to be repeated until the PC gets the right idea?

Puzzle design is sometimes a compromise between our original, more literary vision of the scene on the one hand and, on the other hand, what it’s practical to code. If you want the player to follow the NPC into room 5, you might be better advised simply to put room 5 on the NPC’s route list.

With respect to your idea of having the NPC go up and down through rooms 1, 2, 3, 4, 3, 2, 1, etc., you’ll need to do more than reset idx. Think about the logic. You need a separate, persistent variable (one that’s not local to the method – let’s call it wanderDirection, and let’s say it’s either 1 or -1) to keep track of whether the NPC is progressing upward through the room list (1-2-3-4) or downward (4-3-2-1). If wanderDirection is 1 and idx is room 4, then you first need to switch the wanderDirection to -1. And conversely. If wanderDirection is -1 and idx is room 1, you need to switch wanderDirection to 1. You would then add the value of wanderDirection:

idx = idx + wanderDirection; local dest = routeList[idx];

…and so forth. That should cause the NPC to pace back and forth. As far as getting him to go to room 5 with a fuse? I don’t know. Everything depends on how you’ve set it up.

Thanks for coming back to me on this. There is no code because I got fed up trying to make it work and deleted it, which is why I asked the question in the first place. Sorry about the saying the pc would move into nil, my mistake.

I agree with your point about writing code that works and trying to write code that follows a particular idea, which in this case may be more trouble that it’s worth.

The problem with the idx in the sample is it does not do what is should; make the npc move through the agenda list, if it did that then the problem is fixed. I’m sorry but I don’t understand the concept of changing the value of another variable to match the movement, the npc should move right through the agenda list and finish at room 1 with idx set to the end of the list. My fuse should set the npc off, with a random check to move into room 5 and set a checksum to record the action, then at room 1, into nil, if the checksum is nil then whole thing is repeated with (hopefully) the idx reset as the npc enters the new actor state as per the code, if not nil, then the fuse is stopped. If pc knows what has happened he can tell the other npc who told him to do this, and continue with the next task, which is the whole point of the exercise.

As to the pc knowing what to do, he is told by another npc at another point in the game, so he knows to follow this npc through the rooms, with the possibility of the npc moving to one of several other rooms, as test so he keeps track, if he fails to do so, then end of game.

On the other hand the solution may be to use my original idea to inform the pc about what has happened, a sort of electronic post-it, but I though it would be more interesting to have the pc do some leg work. I will have another hack at it and see if I can make any progress using your idea for wanderDirection. Sorry for the long winded reply.

re the code for the wandering npc, copy and run this and you see what I mean about bouncing between rooms.

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

versionInfo: GameID
IFID = ‘64633ec6-ae02-509a-26a4-b76b69540da8’
name = ‘Your New Game Title’
byline = ‘by Your Name’
htmlByline = ‘by
Your Name

version = ‘1’
authorEmail = ‘Your Name your-email@host.com
desc = ‘Put a brief “blurb” about your game here.’
htmlDesc = ‘Put a brief “blurb” about your game here.’
;

gameMain: GameMainDef
initialPlayerChar = me
;

roomZero: Room ‘room zero’
“”
east = roomOne
;

  • me: Actor
    ;

roomOne : Room ‘room one’
“”
west = roomZero
east = roomTwo
;

  • bob : Person ‘bob’ ‘bob’
    “”
    isHim = true
    isProperName = true
    ;

++ bobWanderAgenda: AgendaItem
isReady = true
initiallyActive = true
agendaOrder = 10
routeList = [roomOne, roomTwo, roomThree, roomFour, roomThree, roomTwo, roomOne]
invokeItem()
{
local idx = routeList.indexOf(bob.getOutermostRoom);
if(idx && idx < routeList.length())
{
local dest = routeList[++idx];
bob.scriptedTravelTo(dest);
if(idx >= routeList.length()) isDone = true;
}
}
;

roomTwo : Room ‘room two’
“”
west = roomOne
east = roomThree
;

roomThree : Room ‘room three’
“”
west = roomTwo
east = roomFour
;

roomFour : Room ‘room four’
“”
west = roomThree
;

// special room
roomFive : Room ‘room five’
“”
;[/code]

Ah, yes. The problem (I just compiled and ran your code) is that this line:

local idx = routeList.indexOf(bob.getOutermostRoom);

misfires when your routeList includes the series [roomThree, roomFour, roomThree]. In that situation, indexOf is always going to find the FIRST instance of roomThree in the list. It’s never going to find the second one. That’s why my original suggestion, of using a simple list [roomOne, roomTwo, roomThree, roomFour] and a wanderDirection property (a property of the AgendaItem) will work, while your method won’t.

This code causes Bob to follow route 1-2-3-4-3-2-1-2-3-4-3-2-1-etc.:

++ bobWanderAgenda: AgendaItem isReady = true initiallyActive = true agendaOrder = 10 wanderDirection = 1 routeList = [roomOne, roomTwo, roomThree, roomFour] invokeItem() { local idx = routeList.indexOf(bob.getOutermostRoom); if (idx == 1) wanderDirection = 1; else if (idx == 4) wanderDirection = -1; idx = idx + wanderDirection; local dest = routeList[idx]; bob.scriptedTravelTo(dest); } ;

As usual the problem is easily solved. I was thinking of doing it another and more complicated way. Thank you.

I was under the impression that indexOf() returned an integer value and just increased until the end of the list is reached. So can I ask, why does the item in the agenda list matter to the index of the list?

It returns an integer, yes. But there’s no mechanism that causes it to move forward (increase) from the previous thing it found, because every time you enter that method indexOf() starts at the beginning of the list. It starts with item 1 in the list and moves forward until it finds a match. If a given item is present multiple times in the list, indexOf() will never find the second one, no matter how often you call it.

It returns the position of its argument in the list. It’s an information-giving routine only. A list does not have any notion of “current item”. It just has items in it, and each one has a unique position in the list (first, second, etc.) So “current index” does not make sense to a list.

Thanks for telling me how routeList() works, now I know what to do in the future.

I’ve manage to modify your code to fit the game and it works fine. No doubt I will be asking questions again in the future. Thank you for your help.

Thanks for telling me how routeList() works, now I know what to do in the future.

I’ve manage to modify your code to fit the game and it works fine. No doubt I will be asking questions again in the future. Thank you for your help.

I modified your example so the npc follows two routes, one for each agenda.

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

versionInfo: GameID
IFID = ‘64633ec6-ae02-509a-26a4-b76b69540da8’
name = ‘Your New Game Title’
byline = ‘by Your Name’
htmlByline = ‘by
Your Name

version = ‘1’
authorEmail = ‘Your Name your-email@host.com
desc = ‘Put a brief “blurb” about your game here.’
htmlDesc = ‘Put a brief “blurb” about your game here.’
;

gameMain: GameMainDef
initialPlayerChar = me
;

houseBarrier : TravelBarrier
canTravelerPass(traveler) {return housePass.isIn(traveler); }
explainTravelBarrier(traveler) { "You can’t go into other peoples houses. "; }
;

roomZero: Room ‘room zero’
east = roomOne
;

roomOne : Room ‘room one’
east = roomTwo
;

  • peters : Person ‘sir richard peters’ ‘peters’
    isHim = true
    isProperName = true
    wander1 = true
    wander2 = nil
    ;
    ++ housePass : Component
    ;

// first peters route from edenbridge to mod, modify rooms as required
// second peters will be the same but a different route to clanricade gardens
++ petersWanderAgenda1: AgendaItem
isReady = peters.wander1
initiallyActive = true
wanderDirection = 1
petersRoute1 = 1
routeList = [roomOne, roomTwo, roomThree, roomFour, roomFive, roomSix, roomSeven]
invokeItem()
{
local idx = routeList.indexOf(peters.getOutermostRoom);
if (idx == 1) wanderDirection = 1;
else if (idx == 7) wanderDirection = -1;
idx = idx + wanderDirection;
local dest = routeList[idx];
peters.scriptedTravelTo(dest);
petersRoute1 ++;
if(petersRoute1 == 13)
{
petersRoute1 = 1;
peters.wander1 = nil;
peters.wander2 = true;
}
}
;

++ petersWanderAgenda2: AgendaItem
isReady = peters.wander2
initiallyActive = true
wanderDirection = 1
petersRoute2 = 1
routeList = [roomOne, roomTwo, roomThree, roomFour, roomFive, roomSix, roomSeven, roomEight, roomNine, roomTen]
invokeItem()
{
if(peters.isIn(roomOne)) newsPaper.moveInto(peters);
local idx = routeList.indexOf(peters.getOutermostRoom);
if (idx == 1) wanderDirection = 1;
else if (idx == 10) wanderDirection = -1;
idx = idx + wanderDirection;
local dest = routeList[idx];
peters.scriptedTravelTo(dest);
petersRoute2 ++;
if(petersRoute2 == 19)
{
petersRoute2 = 1;
peters.wander1 = true;
peters.wander2 = nil;
}
}
;

roomTwo : Room ‘room two’
west = roomOne
east = roomThree
;

roomThree : Room ‘room three’
east = roomFour
west = roomTwo
;

roomFour : Room ‘room four’
west : OneWayRoomConnector { -> roomThree travelBarrier = houseBarrier }
east = roomFive
;

  • me : Actor
    ;

roomFive : Room ‘room five’
west = roomFour
east = roomSix
;

roomSix : Room ‘room six’
east = roomSeven
west = roomFive
;

roomSeven : Room ‘room seven’
west = roomSix
east = roomEight
;

roomEight : Room ‘room eight’
west = roomSeven
east = roomNine
;

roomNine : Room ‘room nin’
east = roomTen
west = roomEight
;

roomTen : Room ‘room ten’
west = roomNine
;

[/code]