Professional Documents
Culture Documents
55)
A tutorial by Ayath The Loafer greatly assisted by Nereng
August 2004 / May 2005
Ambient city by Nereng slightly assisted by Ayath
Appendix about waypoints by Baron of Gateford (updated May 27th)
(Thank you for allowing us to include it in X2 Ambient City)
This is NOT the end all and be all documentation for the ambient system. It is a sort of
walkthrough and also a tutorial where some points are explained and highlighted.
(I know it is a long document, but you can probably skip large parts)
Thank you for input and help: Heung Wei Lo and Hanor.
Special thanks to Nereng, who has done a lot towards testing out ideas and presenting new ways to
use the ambient system as well as designing the Ambient City demo. It was also Nereng who first
took up the challenge of the Lamppost Job and sparked my interest in the X2 Ambient System.
And a thank you goes to Firefairy for bug-testing Ambient City.
Baron of Gateford has kindly agreed to let us include his excellent tutorial on Waypoints in this
document. I am sure this will enhance your scripting greatly.
Throughout this document I will assume that you create copies of the creatures rather than painting
them in the area and then change their scripts and tags. This is because you will be creating generic
creatures that you can paint in the area and THEN change appropriately. Of course this will have all
your NPCs look alike, but this is a tutorial for the ambient system not a tutorial for creature
creation.
For your convenience I have created a demo module with the basic system demonstrated. You have
to reset the starting point to see the different areas. Nereng has made Ambient City to
demonstrate his ideas. He has commented in the scripts and the objects descriptions to explain to
you how each of them work.
I cannot stress enough that Ambient City is a fantastic piece of work by Nereng. Largely due to his
efforts we have had great response from the community. Id like to thank you all for your feedback.
Nereng has written a beginners guide to Ambient Animations. Find it in this document.
Guide updated May 22nd 2005.
My hope is that this tutorial will help the beginners to understand scripting better and to encourage
them to reverse engineer other peoples code to see if it can be changed to fit their needs.
Some of the scripts and ideas presented in the demo modules may even give you great ideas for
your own creations. That would make me happy.
Also important is it to realize that there are other NPC Activity Scripting Systems to be used in
NWN.
The best one is done by Deva Bryson Winblood and can be found here (last version I have seen):
NPC Activities 5.7.a3 SOU Edition
It is much better than the NWN Ambient System but then this tutorial is as much a description of
the NWN Ambient System, as it is a way of explaining to novice scripters what is going on in
scripts.
Index
Chapter One: The NWN x2_am ambient system (version 1.54)................................................1
What is the x2_am_ ambient system? .................................................................................................................... 4
What jobs are there to be had? (as seen in the x2_am_inc file) ........................................................................... 5
Main scripts for the ambient system .......................................................................................................................... 6
Anvil.................................................................................................................................................................................................................. 12
Bookcase ........................................................................................................................................................................................................... 13
Lamppost .......................................................................................................................................................................................................... 14
Chairs Mate!..................................................................................................................................................................................................... 16
Wipe the table please! ...................................................................................................................................................................................... 18
Chapter Two: Lets make the changes for the better ...................................................................48
Spelling mistake in x2_am_inc.................................................................................................................................. 48
Change to the heartbeat script x2_am_heart ...................................................................................................... 48
And then there is The Waitress ................................................................................................................................ 50
Prices are different from Inn to Inn ......................................................................................................................... 56
Appendix ...........................................................................................................................................70
What do all the different types of waypoints listed in the toolkit do? ................................................................... 70
What jobs are there to be had? (as seen in the x2_am_inc file)
We shall start at the beginning by having a look at the lines in x2_am_inc that lead me to compile
this document.
!"#
"#
- .
-
0
1 #20
$
%
&
$ () * + % &
- * / .
" * $'
'
'
"
+3
4
56
-
" +
7
"
-
4
.
**
4
9
/(
**
+ 5 ! ++
+ 5 +
;
< =!
>
! =
36!+=
?
@
56
A
0
*
8
)(
85
! = (
40.
/
/
. %(
As you can see there are several interesting jobs to be had. Almost everybody on the Forums and
The Vault have had dealings with one waitress-script or another, so it will not be my main
priority.
The jobs mentioned above are only the ones that Bioware has made in this skeleton of a system.
There are certainly others jobs we can do with the system and Nereng has devised a very interesting
way of enhancing the system to make everything much more interesting (chained requests).
Maybe this is a good place to say that this tutorial in no way tries to make or even flog yet another
ambient NPC system to complement the ones already found on the Forums and The Vault. Keep in
mind that it is an effort to explain what the x2_am system is and what we can do with it.
The x2_am_inc
The x2_am_inc is an include script which contains all the functions used by the ambient system.
It is in this script we find functions like SetJob(), DoJob(), Request() and a host of supporting
functions.
5
8$ () * + % '
5 +
"
$ () *
&
% 1*
!
BB&
1*
#
=C +. !
(
'
($ () * !"#
=#+ 0=1<'
" 8 0
$ () *
=#+ 0=1<'
5
(
8$ () * 0 /
=#+ 0=1<'
0
(
8$ (+
& () * 0 /
=#+ 0=1<'
5
+
$ () * 0 /
=#+ 0=1<'
0
+
$ (+
& () * 0 /
=#+ 0=1<'
" 8
(
$'
(
"
$ () * 0 /
'
0
($
(& () *
() *
=#+ 0=1<&
+
+
< 10=&
5
($ () *
() *
=#+ 0=1<'
($ () * 0 /
=#+ 0=1<'
*
1
$
D
& () * + %
=#+ 0=1<'
*
1
$
D
& () * + %
=#+ 0=1<'
5 1
$ () * + %
=#+ 0=1<'
#
$'
< * $ () * !"#& () * + < * '
"
+1
$ () * <
'
#
D
< 3 (6 $ () * #
'
! " 8
$'
/ BB'
The x2_am_heart
The x2_am_heart which is the heartbeat script used to fire the events when needed. We find the
request to DoJob() in this script among other nifty little details among which is the very useful
Day/Night posting.
While the above is true in huge modules with large numbers of creatures and events running all the
time (this is particularly true for persistent worlds), it is not necessarily true for modules of the six
hour play time or less type.
Certain procedures can be applied to minimize the problem and one of them is to make sure the
heartbeat doesnt do very much when theres no PC around to see things actually happen. To
prevent this Bioware has already implemented two of the possible ways of doing this in the ambient
system:
In the x2_am_heart we find this piece of code:
/$5
$'E
1=D=1 1
'
In other words
5
1
5
$'
. *
1
.
. *
/. /
%
1=D=1 !D 1 &
1=D=1 D= F 1
&
1=D=1 3 53&
1=D=1 D= F 3 53
5
1
$ () * + %
=#+ 0=1<'
1=D=1 1
&
1=D=1 !
1&
1
$'
.
% . / *
/ *
.
4 8
/
&. %
(
. (
&(
(8
This suggests that creatures stop doing anything when PCs are not around.
To be absolutely sure of this there is another method that is also used in the ambient scripts:
! " 8
$'
G
() *
/$5
"# 5 !
#
() * D
$ "#'
< 10=
+ 6=
,
- 8
$# = +6 = +F"= "1 F=
+ 6='
#3
&"1 F=
#3
0 "#'
This is a function found in x2_am_inc that returns true if there are no PCs in the area.
This should be sufficient to keep the discussion on Heartbeat scripts to a minimum. If you are
programming a persistent world you have probably already achieved a scripting level superior to
this anyway and you have no need for this tutorial or solutions for heart trouble B-)
BJ7
B
*B
%
*B
$'
G
0 0#
5 5
+#
0
($
" +
$!
<1 5 !
1 56= =D=!+'
$
=#+ 0=1<&
$ 'K '
!&
=#+ 0=1<&+ 6='
BJ7
*B
$'
G
6
/
$6
G
() *
/$5
G
5 6
:'
H
H
# !D= 0 +
() *
5 1 0() * D
$ () * '
/
/.
( $'
!
$'
+ 6='
BJ7
%#
*B
$'
($
=#+ 0=1<'
+ 6=
!&"= #="+
! 0==!'
As you can see there is a lot of jobs and job functions. Those with _sp_ I have determined to be
OnSpawn scripts and likewise the _user_ are the OnUserDefined scripts.
We are now on the right path to utilize the ambient system from Waterdeep. We must, however,
keep in mind that the complete system never was implemented and that it hasnt been thoroughly
tested. We are in fact trying to use an unfinished system.
In the next sections we shall have a look at some of the more basic uses.
Ambient furniture
One of the many parts of the ambient system is the furniture. You notice its presence in the x2_am
scripts:
x2_am_anviluse
x2_am_bookread
x2_am_lampuse
x2_am_sit and
x2_am_sitme
For all of them it goes that they have to be NearestObject by the character that is supposed to use
them.
And the easy part of it is, that all you have to do to make them work is apply the scripts and paint
them in the area. They will attract attention all by themselves.
Anvil
So lets start with the anvil use script. The first job is to decide in which script slot the script
belongs.
,
I *
%
BJ7
*
*B
(8( *
$'
G
,0
/$
G
0 "
C
H
L M
L
'N 9;'
.)
< %$
=#+ 0=1<&+ 6='
$+ 02
2 !D 1&A4 & 4
;&
=#+ 0=1<'
If Random(100) is greater than 35 then send a request that a task to be done. In this case it says, I
am an anvil. Come closer to about 0.5 metre away.
The x2_am_inc script has a function for the Request() function and it says:
,6
/$$ +
G
(8 !D 1 () *
+ 02
2
% #
% #
% #
8#
8#
$#
$#
$#
$>4 &
$>4 &
!D 1'OO $5
&#
& *
& *
% #
% #
($ #
'
1 #20
+3''
$''
+ () * $ 0 /
&< 10=&/
+. #
*$0 /
''
$#
&#
*
$'''
$#
&0
+=
$'''
''
This means: If your job is a blacksmith, stop what you are doing; Attack me (bash me). After 6
seconds Ive had enough. Stop and lets be friends again.
Those 6 seconds before we are friends again, doesnt that make you think of Heartbeats?
Of course it does.
Lets put the x2_am_anviluse script in the Heartbeat slot of the anvil.
Edit copy an anvil and put x2_am_anviluse in the heartbeat script slot. We shall test it later, but
presume it works.
Bookcase
This one is the x2_am_bookread script. And as with the anvil we shall presume that it goes in the
Heartbeat slot. No, I must confess; I have tested it and I am sure it goes in the heartbeat slot.
Just edit copy a bookshelf and you are good to go. You might ask why it should be edit copy all the
time. Why not just paint a bookshelf somewhere and then put the appropriate scripts inside?
Because if you edit copy and put the scripts where they belong, you can always paint that bookshelf
anywhere you want it. AND it already has the correct scripts in the slots.
In other words; IT SAVES YOU TIME.
,
I *
. /%
BJ7
L
*B
$'
G
,0
/$
G
C
H
L M
L
'N 9;'
.)
$+ 02 1= 06 =
2&
0+ !#=
=#+ + 12& 4
;&
=#+ 0=1<'
(8(
. /
/$$ +
+ 02 1= 06 = =
2'OO $5
"#$ #
'
< 10='OO $
< 10=''
G
/$5 1
$#
'E 1= 06 = +3 =033 1 '
G
% #
$#
&#
*
$''
% #
$#
& *
+ () * $ 0 /
&< 10=&/
+. #
''
/$5
( 80* $ #
&
1 +F !+=11 5=!#='N A'
G
% #
$#
& *
" 8
$!
+ ! < =< 5=+ =
H
,)
($ #
'
''
*. .
G
% #
*
" 8
$!
% #
$#
&
+ ! < =<
$#
& *
+#3 3= ''
() * $
=#+ 0=1<''
H
% #
*
$#
$
& *
#
$; '& #
$=J *
0* - $B
8 B& #
'''
'
The NPC that gets attracted to the bookcase either has a read animation or a scratch head animation.
The clincher is ability (intelligence) score of 9 or less.
8 = scratches head.
9 = reads a document.
Lamppost
We stay in the tradition of heartbeat with this script; x2_am_lampuse in the OnheartBeat slot.
I *
BJ7
*B
$'
G
,
/$5 1 *
G
" 8
8#
0 1*
8#
0 1*
/ /
/(8 /
$
=#+ 0=1<&B!
1 +6 !0=1< <<B'
'
$!
+ ! "1 #= 1= = #+ D +='
$4
:&
0 " * (
$
=#+ 0=1<&< 10=''
$
=#+ 0=1<&
B!
1
!B& '
$4
>& * 0
*1%. %$5
$
=#+ 0=1<'''
$
=#+ 0=1<&B!
1 +6 !0=1< <<B&
'
H
,
/$5 1 *
$
G
C
$+ 02
H
=#+ 0=1<&
B!
2 1
!B'
,
- /
/
/$5 1 *
$
=#+ 0=1<&
B!
1
!B'
G
C
$+ 02
2 1 "" 0+&A4 & 4
;&
H
OO 5
! %. $'
+ 6='
=#+ 0=1<'
OO 5
8$'
+ 6='
=#+ 0=1<'
Not much to say about this script. Lamp is off at creation, recomputes static lighting and waits until
night. Then it calls to someone and have them come closer. Please turn me on, it whispers.
x2_am_inc has this to say:
,6
(81 -"
() *
/$$ +
+ 02
2 1 "" 0+'OO $5
"#$ #
'
< 10=' OO $5
($ #
'P
+ 5 +'OO $5
($ #
'P
+ 5 ! + +''
G
( %$BP
P
1 - + % B& #
'
% #
$#
&#
*
$''
% #
$#
& *
+ () * $ 0 /
&< 10=&/
+. #
''
% #
$#
& *
* () * $ 0 /
''
% #
$#
& *
#
$=J * 0* - $B
7
8 B& #
'''
H
Someone cannot be a PC and cannot be from a tag team. The scripts assign a command
(ActionInteractObject) to someone who just happens to be closest. Then the someone gets told to
resume waypoint walking.
Bet you that this someone could be a guard on patrol with all his waypoints passing the lampposts.
You cant use the GUARDS from x2_am ambient system for this. Apparently there are some issues
with ambient animations and the WalkWaypoints() function. The guards never resume walking the
waypoints. Or so we are let to presume.
This is what it says in the NWN Lexicon:
2
+.
L
0 00 0-
.
#
#
/
%
$!
$!
/
(
.
8<1 5
<1 5
. *.
*
%
% .
/8
/ %
1=
=!+ !
-
*.
*
=!+ !
+ !0'4
%
8"
.
$' *
.
+
.
!0'
. %
4F
* L
Chairs Mate!
Did you hear about the Irish wake for Murphy? A lot of people attended and the room where
Murphy was laid out became rather crowded.
Wife and brother decided that they could sit Murphy on a chair in a corner instead of using all that
space where the dining table was.
The brother was holding on to Murphy while the wife and her brother packed the dining table away.
It was one of those tables where the legs could be folded back on themselves to make the table fold
up to less than a fifth of the original size.
As it turned out, Murphy was not that easy to hold on to. The stiffness had gone and his head was
lolling, arms were dangling, and he was actually starting to slip. The brother holding up Murphy
was getting a bit concerned and called out, Come on now, give me a chair for Murphy. From the
back of the room a slurry voice called back, Hip, Hip, Hoooraaayy.
Where were we? Oh yes, the chair script. Or should I say chair scripts. There are two scripts for
sitting that comes with the x2 ambient system. One is very short and sweet - x2_am_sit:
,* *
$'
G
() * 0 /
% #
=#+ 0=1<
$5 1 6
8$'& *
0 $0 /
''
And we can all see that it says click on me and GetLastUsedBy. We shall put this particular
script in the chairs OnUsed slot. Make the chair useable and you can sit in it.
The other script is same as anvil and lamp scripts. It requests an action to be taken and it is therefore
another Heartbeat script (according to the logic we have employed this far).
x2_am_sitme is the name of the script:
,
I *
. /%
BJ7
L
*B
$'
G
() *
/$5
*
/$5
G
5 0
%#
() * D
$0
'
1
"#$ 0
% #
() * 0 /
% #
$
=#+ 0=1<'
+ 6='G
$;& 0
'
'
< 10=OO 5 1
$0
&#
=#+ 0=1<
$0
& *
$0
$''
8<
'N
-
1= 06 = +3 =033 1 '
%
() * $ 0 /
&< 10=&
4 ''
H
H
,0
/$
G
C
H
H
L M
'N
L .)
7;'
$+ 02 1= 06 = 0 +&
0+ !#=
=#+ + 12& 4
;&
=#+ 0=1<'
Notice it says, Bookshelf gets read at the top of the script. Just proves yet again that the ambient
system is slightly rough around the edges.
Never mind.
If it works...
I have tried it in the inn with five patrons and four chairs, a bookcase and a waitress. The chair thing
looks ridiculous. Try for yourself.
Perhaps I would only keep the OnUsed script. Or perhaps I shall have to change something in the
ambient scripts somewhere.
And then there is the Table Wipe script.
(
*B
$'
G
,0
/$
G
C
H
L
L
'N >;'
$+ 02
.)
2 #1= ! !5&
0+ !#=
=#+ 0=1<'
The TASK_WORK_CLEANING can be found in the x2_am_inc script and looks like this:
,6
(8+ 1= () *
/$$ +
+ 02
2
G
% #
$#
% #
$#
% #
$#
/*
+. . &94
;''
% #
$#
4
;''
H
#1= ! !5'OO $5
&#
& *
& *
& *
*
+
" 8
($ #
'
$''
() * $ 0 /
&< 10=&/
$!
+ ! 1
8<
''
+. #
''
" !5 5=+ 1
() * $ 0 /
&< 10=&/ *
&
+.
*+
() * $ #.
'E
4 OO 5 1 *
$ #.
'
You must change the distance to something useful. In this case it will work if you change the
distance to something like 1.5 metres.
/$5
*+
() * $ #.
'E
4
; OO 5 1 *
$ #.
'
%$B
P
B'
ut: Youre It!. Whats this? In my part of the world it would be something like DU ER DEN!
Or where my wife comes from: Tag! Youre It!
As you can see, there is ample reason already to make changes to the scripts.
Maybe you have noticed that there are some lines in the x2_am_sp_it file that says
- 8
/JM
%4
$.
.
%% '
8(
/.
*.
#
() * D
% #
5 !
$#
() * $
=#+ +F"=
'
+ 6='
$ =J & *
() * $ #
F"
!+'
''
It doesnt seem to look for a specific waypoint and presumably it can be any waypoint. Paint one
inside the triggers area.
Thats it really.
And it works just fine. As soon as one from a tag-team has left the triggers area it is redirected back
to the nearest waypoint in the triggers area. We can then divide the towns area into segments for
tag-teams and of course use the trigger to keep the kids out of trouble like getting stuck in corners
and by stairs.
#.
5 !
() * D
$ #.
#
'
$# = +6 = +F"= "1 F=
+ 6='
#3
&
"1 F=
#3
! + "#'
If you dont want to have the chicken chase the dog, you will want to enter variables for the
chicken blueprint and set an integer X2_G_NEVERIT to the value of 1. This will be tested for in
the x2_am_user_play script and no exchange of roles in the game will take place.
1
/$5
*+
() * $ #.
'E
4 OO 5 1 *
$ #.
'
As with the children: You can use the fix-it trigger to keep them confined to a specific segment in
an area.
Hanor has drawn my attention to the fact, that the chicken sometimes would get stuck in corners, by
buildings and other obstacles. His solution to this problem is:
3
S4
4
4
/
*. (
(8*. % % *
4
. *. *
L.
8<
() * $ &+ 6=&
* *.
&
4
T
4 '/
(line 74 in x2_am_user_play)
Remember to save under a new name unless you want this change to be default.
;4 & %
($
+ 5
+&
*. *
B'
According to the script it makes the dog create chicken that it then chases.
The x2_am_inc script has this to say about the SetJob function:
0
($
(& () *
() *
=#+ 0=1<&
< 10=&
/ BB'
So the dog gets the job as a tag-team member with the specific role as IT. It is NOT a
TownTalker and there is a string with ResRef townchicken.
Further down in the script x2_am_inc we find
/$
G
/P BB'
/ $
E
$9'K 7 KK'
G
() * #
#
() * $
=#+ +F"= # = +6 =&
0 1*
$#
&BQ7 5 !=D= +B&+ 6='
0
($
+ 5 ! + +& #
'
H
/
&5 1 *
=#+ 0=1<''
This leads us to believe that the dog when spawned should create two or more creatures with the
ResRef townchicken and with the local integer X2_G_NEVERIT set to 1 (or TRUE).
Just use the other default scripts for the tag team member IT (x2_am_user_play and
x2_am_heart in case you have forgotten).
You will want to save x2_am_inc under a new name, as we shall make changes to it.
Perhaps we shall look later at all the relevant changes and see if they collide in any way. If
they do not, we can combine the changes in fewer scripts.
Go create a chicken copy (remember the correct ResRef). Ill bet you twenty to one that the
townchicken has got to have the scripts mentioned for the NOTIT tag-team member (you can use
the default script for the chicken).
Lets check it out.
We have now established that the dog indeed creates chicken. My dog created two chickens. And
then it just stood there doing nothing. All the Tag-team scripts are in place, the ResRef is correct.
So what is wrong?
When I had two Tag-teams in one area nothing happened. One on one seems to work. My guess is
that it might be the number of chickens. Perhaps it gets confused?
Lets try that theory.
The above script lines mention Random(3) and this is a strong hint that some chickens will be
created. And this is indeed the case. I have had number from 2 to four chickens appear.
/ $
$9'K 7 KK'
Basically this means that the loop will cycle through values for i from 1 to random(3) +2
Random(3) means three values and we start at 0. (Thank you for pointing that out Heung Wei Lo).
You will therefore have a minimum of 2 chickens created and a maximum of 4.
Since we are testing if the non-chase problem has to do with more than one chicken we will change
the line in the x2_am_inc to something like
/$
G
/P BB'
/ $
E
$9'K 7 KK'
G
() * #
#
() * $
=#+ +F"= # = +6 =&
0 1*
$#
&BQ7 5 !=D= +B&+ 6='
0
($
+ 5 ! + +& #
'
H
/
&5 1 *
=#+ 0=1<''
and remember to save it under a different name. I suggest x2_am_inc_dcc. Then you have to save
the dogs OnSpawn script and save it as x2_am_sp_dcc after you change the #include file
refernce to include the new file x2_am_inc_dcc.
Again: The reason why we save the inc file under a new name is, that it might be silly to change the
spawn number to only one, if the spawn of several creatures will be needed for other of the
available jobs.
And it works now with the dog creating one chicken and chasing it.
36!+= '
$
=#+ 0=1<&=
$=D=!+
+3=36!+= ''
! = '
%$
"
() * &+ 6='
$ () * &B36!+= B&1 0+=!
36!+F 6'
$
@
? *
/$5
G
H
/$5 #
G
#
*
H
(
($'
%'
36!+= '
*
*
(8
$'P
#+
D=+ "
!+'
$'
$'
So if the wanderer isnt moving towards any point it will be told to stop what its doing and wander
randomly.
When we look further we find x2_am_user_rat which is what makes the rat differ from the
wandering dog. Apparently the script is also used for the hunter as well as for the rat.
We were, however, making a wandering dog.
We can use the heartbeat script x2_am_heart and x2_am_sp_rat for the wandering dog. We use
the default OnUserDefined script. Will he just stand still? No of course not. He moves around all
right.
That should cover the wandering dog. There is another interesting dog to be had. He is the stray
dog. We can expect very different behaviour from him.
7'
"= #= D=
G
() * 1 " *
5 1 " *
$'
/$5
() * D
$1 " *
'
+ 6='
G
/$5
8$
=#+ 0=1<'OO 5
"#$ 1 " *
OO 5 #
*
$
=#+ 0=1<'P #+ !
'
G
#
*
$'
*
+ () * $ 1 " *
'
" 8D * #. $D #= #3 +
++1=# F '
H
H
'
+ 6=
D=+ " !+
So you can change the script accordingly (if you wish) and save it under the same filename. Doesnt
override the original, it is merely preferred if it exists. Weve been over this before.
Well leave the stray dog for now.
The hunter and the prey (this garbage pile creates rats)
When we refer to hunter in the x2_am_inc script it is in reality a specialized dog and the prey is
a rat.
We will start with the dog and save the very special rat (which is spawned by a placeable object) for
later.
We can create a dog with the job HUNTER. Usual heartbeat script and we can use the stray dogs
OnSpawn script (we should use the stray dogs OnSpawn for reasons which will become clear).
Save the spawn script as x2_am_sp_hunter.
Using the stray dogs UserDefined script you save it as x2_am_user_huntr.
Paint the dog in the area.
We are now set with the hunter. He will call out every second that he is on the prowl.
And now we shall create the prey, the poor little rat.
The heartbeat script is the same again, x2_am_heart.
In the x2_am_user_rat we find an interesting piece of code:
() * 3
5 1 * () * $
=#+ 0=1<&BQ7 1 3 60=B'
/$5
() * D
$3
'
+ 6='
G
00
%$B
%B'
,
.
Does this mean that she lives in a house? Apparently she stores the X2_L_HOUSE variable at
spawn time. We shall have to look for a script in which this variable is stored.
What then happens is that we find a function designed to create a rat
,#
#
$*
(8
8L
5 (%
* - '
$'
G
() *
#
() * $
0 1*
$
=#+ 0=1<&BQ7
, .
. / . .
0 1 * () * $
&BQ7 1 3
() * 0 /
=#+ 0=1<
% #
$
& *
H
() * $ 0 /
''
B&5 1 *
$
=#+ 0=1<''
=#+ 0=1<&BQ7 1
+0
=B'K '
This function creates a rat with the ResRef townrat at location OBJECT_SELF. This object must
be a placeable I suspect, as it then sets the local int on the rat X_L_HOUSE, meaning this is
where the rat lives (the filth that created it).
We must find this function that calls the function CreateRat(). It is found in x2_am_makerat. And
it is interesting (I use that term a lot dont I?).
J7
# -8 %. $*'7
# -4
,
*
8
4
4
+.
/ * - '4
/
(*
36!+=
. % (% . *
(
8
.
,
#
#
I *
BJ7
*B
$'
G
!
/$ !
G
#
H
(
(
/
/
5 1*
'
+0
=B'
$'
/$
$
'N $$ !
(
/
G
00
%$B3
BK
+0
00
%$B
%
U B'
#
$'
H
0-
=#+ 0=1<&BQ7 1
%$B5
, ; '''
%$ !
''
, .
8&
The script stores the number of rats made. It creates one rat.
The CreateRat() function increments the local int X2_L_RATSMADE everytime it is run.
#
$'
G
() *
#
() * $
0 1*
$
=#+ 0=1<&BQ7
, .
. / . .
0 1 * () * $
&BQ7 1 3
() * 0 /
=#+ 0=1<
% #
$
& *
H
() * $ 0 /
''
B&5 1 *
$
=#+ 0=1<''
=#+ 0=1<&BQ7 1
+0
=B'K '
.
$'
+ () * $ 3
&+ 6=& 4 '
0 /
=#+ 0=1<
*
,
8 *
//
/$5 #
( $
=#+ 0=1<'
+ 6='
% #
$3
&
8#
$> 4 &0 1 *
$3
&BQ7 1
+0
=B'M '''
*
#
$
8 () * $ 0 /
''
5 1*
$3
&BQ7 1
+0
=B&
,/
8
3
&.
.
*.
/$5
($ () * '
36!+= '
G
% #
$ () * &#
*
$''
% #
$ () * & *
+ () * $ 0 /
&+ 6=& 4
7''
H
0 #
( $< 10='
,*
%
*
&
H
Makes perfect sense doesnt it? The garbage pile calls out to the dog, Go away. This gives the rat
time to see the dog. As soon as the dog is seen the rat moves towards its house, decrements the
X2_L_RATSMADE variable by 1 and sets the rat non-commandable. Not only does this take
care of the rats that are rushing towards safe haven, but also the rats that didnt quite make it.
Another interesting point is the SpeakString(Go away.....) which is run at every heartbeat.
If we use the stray dog set of scripts, this will mean that if the dog has approached the garbage pile,
and is just standing there, the dog will be told to go away. A cunning use of the listening patterns I
think. This will allow the rat to exist more than a few seconds giving it time to perceive the dog.
At least this is how I interpret the scripts until I see what actually happens.
The rat created uses the townrat set of scripts. We must edit copy a townrat with the correct ResRef.
Go do that. There is the usual heartbeat script and specialized x2_am_sp_rat and
x2_am_user_rat.
Depending on which rat blueprint you choose to use for edit copying a rat it will be faction
commoner or hostile. The rats OnSpawn script looks for an enemy:
/$5
($
() * '
36!+= VV5
8$
() * ''
We must therefore assume hostility between the rat and the dog. Since the dog is commoner (so it
doesnt attack us) the rat must be hostile.
Hostile rat blueprint is NW_RAT001.
And then we need to make a pile of garbage with x2_am_makerat in the heartbeat.
All there is left to do is run the module, find the area and observe. Nice isnt it?
But what if we want rats to be made in larger numbers? (That question was asked on The Forum).
In the x2_am_makerat script you could change the chances of extra rats being made to something
like:
/$
'N $$ !
'''
$9'K 7 KK'
. % . --
Say we want up to 4 rats created every time the makerat script allows for extra rats.
You could try wrapping the second CreateRat() in the above code
/ $
G
#
H
$9'K 7 KK'
$'
There are other ways, but these will do for this tutorial. Remember to save the script under a
different name if you dont wish the script change to influence all the creatures that use the original.
It is also a good idea to recompile the entire module once in a while if you constantly change
scripts. This is particularly valid if you make changes to an include script. ALL the scripts that use
this include script MUST be recompiled.
>
() * <
5 1 * () * $
=#+ 0=1<&BQ7 1 < =! B'
/$5
() * D
$<
'
< 10='
G
() * #
5 !
#
$# = +6 = +F"= "1 F=
"1 F= #3
! + "#'
/$5
() * D
$#
'
+ 6='
G
0 1 * () * $
=#+ 0=1<&BQ7 1 < =! B& #
'
H
H
,/
#3
&
&/
G
/$5 #
*
$
=#+ 0=1<'P #+
G
#
*
$'
*
< *<
() * $ <
& 4
;'
H
! < 11
'
H
(
H
We can see that he attaches himself to any non-pc character that is a person.
In other words, we can have Old yellow or Lassie follow his master (Yes Lassie was a He, even
if He was called Good girl in the films).
You could try creating a commoner in an area. Put down a set of waypoint for him to walk and then
we create the faithful dog.
Notice that the dog does not have a Master initially and if oFriend is FALSE the dog look for the
nearest NPC and nominates him to be a friend. If it is a friend, follow him.
For the dog we have the usual heartbeat and the specialized OnSpawn script x2_am_sp_friend.
Thats it really.
And then there are the guards. There are two types of guards.
#
0< !
# -8 %. $*'7
# -4
,
-
* -
,
#
#
I *
I *
BJ7
B
*B
%
*B
$'
G
,%
L
0 1*
$
=#+ 0=1<&B!
0
($
56
'
8"
$'
1!
!20<
=B&
'
We notice right away that we are in fact looking at a Barmaid spawn-in script. It says so. Even
though the job is set to JOB_GUARD1. Well, its not really the barmaid spawn-in script. We only
see the result of a non-tested and not-finished system.
There is some connection with the Barmaid (or Waitress as some of us call her). The Guard has a
local int set to signify that he doesnt drink.
Lets create one of those guards and see what he does. Remember his waypoints or he shall just
stand there. You should use the usual x2_am heartbeat and his specialized OnSpawn script.
In the x2_am_inc we can read that guard1
56
-
7
"
-
4
.
**
4
In that function we can see that the GUARD1 will interact with people unless they are a GUARD2
or from a tag-team, have a master or is an animal.
/$5
($ !
'P
+ 5 + OO 5
($ !
'P
+ 5 ! ++
OO $5
() * D
$5
$!
''
< 10='OO
$5 1 *
$!
&1*
!
'P 1 *
#
=C
$5
8$ !
'
+ 6='
OO 5
* +8- $ !
'P
# 1 +F"= !
1
'
56
7 OO 5
+. !
( 'OO
($ !
'P
'
He stops what he is doing (clear all actions), moves to the target creature and initiates a
conversation. On the way he sets a local int to make sure that he doesnt approach the same person
again (actually trying not to talk to same person straight away).
We seem to need a conversation file of some description.
If we give him a small conversation file we can surely test it to see if this is indeed the case.
We create a small conversation file with only a couple of nodes in it:
Of course it would be so much better if we had him come with a random conversation node. Also it
could relatively easy be made such that he only approaches PCs in a persistent world. Just to give
them a warning, You behave yourself or you will have to deal with me. Maybe even have a shifty
character approach the partys thief/thieves to warn, You pull anything here without a permit from
the guild...
The conversation is all this character does. Only thing is, that it doesnt work well with only one
character in the area. You need a number of NPCs as well.
Problem is he doesnt resume WalkWaypoint after conversation. Im sure I have seen somewhere
how to deal with this, but I cant seem to find it.
Nereng on the other hand had a solution right then and there. Cant believe I had forgotten about it.
What you do is NOT have the conversation end on the OWNERS node.
Nereng wrote this:
*
.
*
. $=!
+
.
. %
1 56='
. "#
* $'
G
*
H
$=J *
0* - $B
8 B&
=#+ 0=1<''
A
0
85
40.
. %(
And that is absolutely correct. Thats what he does. You may wonder what he will be good for. You
may wonder what qualifies him for use in the ambient system. Perhaps as a bouncer at the Inn.
We use the ambient system heartbeat script x2_am_heart and x2_am_sp_guard2 in the
OnSpawn slot.
If we just check out his spawn in script we see that
0 1*
=#+ 0=1<&B!
1!
!20<
=B&
'
guards dont drink. The 10 is a number assigned to the variable to signal the waitress:
// * then set this variable for a short period of time
// * so that the person doesn't harass the same NPC over and over.
So this dude would be very useful in the tavern as he wont be approached by the waitress
when she goes looking for people to serve. Also he demonstrates what you have to do to stop
the waitress from harassing a character.
Thing is that there is another bit of code in the waitress part of x2_am_inc that says:
B!
8#
1!
$/
8
!20<
=B& '''
%<
& *
$0 1 *
$+
&
So in this code she sets the local int back to 0. Is this an indication that variables set on the NPC at
creation time are higher priority than those set through scripting? Does it override the Guards
reluctance to drink?
Maybe this command should be wrapped in an IF statement excluding the Guard from being reset.
The Blacksmith
This little fellow has got specialized scripts as well. In his Heartbeat we use x2_am_heart (no
surprise there) and in his OnSpawn we use x2_am_sp_blacksm.
His job description is JOB_BLACKSMITH and this is found in the x2_am_inc:
/$$ +
G
+ 02
% #
% #
% #
8#
8#
!D 1'OO $5
$#
$#
$#
$>4 &
$>4 &
&#
& *
& *
% #
% #
($ #
'
1 #20
+3''
$''
+ () * $ 0 /
&< 10=&/
+. #
*$0 /
''
$#
&#
*
$'''
$#
&0
+=
$'''
''
'N 9;'
< %$
=#+ 0=1<&+ 6='
$+ 02
2 !D 1&A4 & 4
;&
=#+ 0=1<'
Thats it.
Signal request on a 35% chance: Please bash me.
You have a blacksmith with working anvil. Can it be improved? Yes!
Well on with that later. It is time we go on to the Town Hub.
() * $ 3 (&< 10=&74
:'
Tells the NPC to walk to the hub and stop at a distance of 2.4 metres. So if you should want to have
a different distance, this is where to change it.
As soon as the hub goes active it will start to shout out for customers. Come hither. Should more
than four patrons turn up the surplus number will be encouraged to leave if another hub is shouting
out, I have need of more patrons. This can be found in the hubs UserDefined script where the
function AskPatronToLeave() is called.
3 (
"
+1
$ () *
8&
<
. (
/ .
'
G
,
*. * .
. *
)
8
, 8 %
% . /
.
J
*
. (
() * ! " *
5 !
() * 8+ %$5 + %$
=#+ 0=1<''
/$5
() * D
$! " *'
+ 6='
G
0 1 * () * $ <
&BQ7 F36 B& ! " * '
% #
$<
& *
+ () * $ ! " * ''
() * "
.
5 !
#
$# = +6 = +F"= "1 F=
"1 F= #3
! + "#& ! " * '
/$5
() * D
$"
. '
+ 6='
G
,
.
/*
*. .
< *$<
&"
. '
H
H
#3
&
G
H
H
Personally I think that the type of animations played out by the patrons at the hubs should be reexamined. At least the percentage change for them playing should be adjusted.
Its up to you to decide what to do with the hubs. Well get back to some uses for the hub later in
this document.
There is an issue with the come hither coming over the DM channel making it irritating
with all those messages in the chat window.
Nereng has a solution:
"It's in line 69 (or thereabouts) in the
townhub heartbeat script: TALKVOLUME_SILENT_SHOUT. According to Lexicon this
uses the DM channel, so it can be heard across the entire module. I tried
exchanging it with TALKVOLUME_SILENT_TALK, and that fixes it. The only drawback
is that NPCs won't be able to hear townhubs across areas, but I don't think
that's a big issue.
"
Now it is time to get on with some important people. The Waitress and her Patrons.
($
(& () *
() *
=#+ 0=1<&
< 10=&
/ BB'
G
0 1*
/$ (
() * &
BQ7 5
'0
B&
-
('
" * $'
So if the job is a waitress, we run to the function that sets up the prices:
,
0
- .
-
- * /
" * $'
G
0 #
0 #
0 #
+
+
+
$ :&
$ ;&
$ >&
+0
+0
+0
%$"1 + # 0+ 1=''
%$"1 + # 0+ 0"
+0''
%$"1 + # 0+
!=''
Smart isnt it? You set some variables at the start of x2_am_inc with the prices, and they will be
used in custom tokens.
Some of you may remember the 0.9b version of this document. I said some rubbish about the
variables being on the area. Thats not exactly true. (It would be smart because you could
have different prises at different inns/taverns/bars). For that we need to make changes to the
x2_am_inc script. Later in this document I will point out what to do.
The variables are integers because we can use them in arithmetic and they get translated into custom
token strings, because they can then be used in conversations.
We can test this theory with a small test conversation:
And it works.
Back to tracing the waitress bit in the x2_am_inc file.
In the SetJob function we also find:
, +.
*
(8
(
, /L
8
%L
.
, .
.
.
,8
L
L
0 1*
$5
$ () * '&5 + %$
() * '&
'
In other words, you must set a variable on the area to tell the ambient system, that this is the
waitress working area.
My waitress is for the moment just called WAITRESS1 and we now have the following variables
set on the area:
Kindly disregard the PLOT_COST lines, as they are clearly not working (see above read
text). They will be later on, so I leave them here as an appetizer.
The next bit is setting up the working zone:
,0
. L
W
L
&/ .
4+.
.
%%
, .
. !"#
() * + %%
5 !
() * $
=#+ +F"= + 55= '
() *
+ %%
5 <
"
() * $ + %% '
( + %%
< 10=
. $5
() * D
$ + %% '
+ 6='
G
/$ + %%
=#+ 0=1<'
( + %%
+ 6=
+ %%
5 ! J "
() * $ + %% '
H
/$( + %%
+ 6='
G
0 1 * () * $
=#+ 0=1<&B!
1 FX !=B& + %% '
H
As we can glean from the code, it must be the trigger into which the character spawns. As we saw
with the tag playing kids the trigger zone should have a waypoint that the character can return to if
it strays out of the zone. Remember the exit script in the trigger (x2_am_exit_fixit).
You might as well also put a tavern waypoint into the inn.
Next interesting bit that gives us another clue in this puzzle is this:
# -8 %. $*'7
,
!"#
( %
#
,
.
8(
#
#
# -4
/
(
- */
/
*
- 8
4
&
'
# -4
,
/- 8
L
&
%. 4
!
*. * / .
(*
.
!"# . 8
L.
. 5 "#0$' 5 1 0-
.
() *
4
,
#
#
$'
G
() * +
5 "#0$'
/$5
() * D
$+
'
< 10='
G
+
5 !
#
$# = +6 = +F"= "= #="+
H
0 1*
$+
&B!
1!
!20<
=B& '
H
!&"= #="+
! 0==!'
Makes sense that we shall have a conversation node that says something like No thanks, I dont
drink.
So just to improvise the conversation, we now have
So if the waitress asks anyone (because we only have one node) they will tell her, that they dont
drink, and she wont bother them again.
(She uses SetLocalInt(oTalker, "NW_L_NODRINKSFORME", 10);).
Which for some reason isnt quite what happens. After a while she starts all over again with the
patrons. There is a timed delay
Lets examine the job description for the patron before we go any further (I have marked the
interesting places in yellow):
(
"
$ () *
0 /
'
G
() *
/$5
G
,
8#
() * D
3 (
8#
5 1 * () * $ 0 /
&BQ7
3 ('
+ 6='
. %& . 36
F36 B'
H
G
#
*
$'
#+
! =
#+ 1= D=
*
#+
! =
/$5 5
$0 /
'E :'
G
*
#+ 1= D=
H
/$ *
#+ 1= D='
G
() *
5 !
() * $
=#+ +F"=
'
/$5
() * D
$
'
+ 6='
G
,
. *
( 8
.8
.
8
0 1*
$0 /
&BQ7 5
60FB& '
*
81 * 5 1 *
$0 /
'
*
+ () * $
'
%
/ 5
/
$0 /
'
*
1* 5 1*
$
'
() *
( " * (
#
() * $
=#+ +F"= "1 #= 1=&B- *
()
B& 1 *'
% #
$
( " * ( & *
#
$
8#
$<" + ! =1 F&
*
#
$#
#
$
/
& 1 *& 81 *&
$ 'K '''''
% #
$
( " * ( &
8 () * $
( " * ( &<" + ! =1 F K
4 ''
*
#
$
8 () * $ 0 /
''
H
*
H
/$ *
G
() *
/$5
G
/$5
G
*
H
H
/$
G
" 8
H
#+
! =
#+
! = '
5 !
() * D
$
*+
+
*
H
H
H
() * 8+ %$B+
'
+ 6='
() * $
() * $
'N 74 '
'
'N 7;'
(
$'
G
H
$'
- *
(8
B'
Now what?
If you have read this far and have had a look at the x2_am_ scripts you will no doubt have noticed
that there are some scripts I havent mentioned.
x2_am_con_atwork
x2_am_conv
x2_am_converser
x2_am_daynight and
x2_am_store
Why is that? you may well ask.
x2_am_con_atwork is clearly another conditional script for a conversation. It could be great to
have this condition on the first conversation branch so that the NPC can have a completely different
response set if she is going home from work (not at job).
For instance you can have the waitress say something like: Please leave me alone. Just because Im
a waitress doesnt mean I have to put up with this after hours.
x2_am_converser is empty. It only hints to the fact that it is meant for the Conversation Hub.
x2_am_daynight is quite frankly not a lot of good as it is now. Nereng has tested it thoroughly
and hes not happy with it. The NPCs simply vanish into thin air when its time to go to their night
lodgings. And they appear again at the position they left when it is day again.
The only creatures that this would suit are vampires, werewolves, ghosts and suchlike creatures. In
reverse of course. The day/night thingy.
x2_am_store simply opens the nearest store. Not much in that really.
x2_am_conv is another script to put in the OnConversation slot.
But this isnt over yet.
I mentioned that x2_am had two ways of dealing with not executing code when there was no PC
around to see anything happen.
In the x2_am_heart we find this piece of code:
/$5
$'E
1=D=1 1
'
In other words
5
1
5
$'
. *
1
.
. *
/. /
%
1=D=1 !D 1 &
1=D=1 D= F 1
&
1=D=1 3 53&
1=D=1 D= F 3 53
5
1
$ () * + %
=#+ 0=1<'
1=D=1 1
&
1=D=1 !
1&
1
$'
.
% . / *
/ *
.
4 8
/
&. %
(
. (
&(
(8
This suggests that creatures stop doing anything when PCs are not around.
To be absolutely sure of this there is another method that is also used in the ambient scripts:
! " 8
$'
G
() *
/$5
"# 5 !
#
() * D
$ "#'
< 10=
+ 6=
,
- 8
$# = +6 = +F"= "1 F=
+ 6='
#3
&"1 F=
#3
0 "#'
This is a function found in x2_am_inc that returns true if there are no PCs in the area.
Personally I prefer the last version (NoPlayerInArea). Not because I dont trust the AI_LEVEL
thing to work, but because it is the game that decides when to shut down heartbeats.
You mustnt forget that the AI_LEVEL system allows you to create NPCs or events that DO run
even if PC isnt around. All you have to do is to use the function SetAILevel().
I gather this will be especially useful in a persistent world where certain events have to take place. I
wouldnt want to go deeper into this discussion. Sufficient to say that I shall make changes to the
heartbeat script so that you can choose witch version you want.
This is how the start of the main function in x2_am_heart looks now:
$'
G
,
0
( .
1=D=1
"# 1
$'E
1=D=1 1
VV! " 8
8
1=D=1
/$5
1
$'E
1=D=1 1
'
8
"# /$! " 8
$''
/$5
$''
The two || are the logical OR just as the two && is the logical AND.
You can then decide for your self if you want the one method, the other method or even if you want
both ways of minimizing CPU load.
($''
G
,
*
.
5 +
"
$0 /
&
B!
1!
!20<
=B& ' (
($''
G
,
*
G
/
$5 1 *
G
5 +
H
(
$
"
=#+ 0=1<&
B
= B'
$0 /
&
B!
'
1!
!20<
=B& '
We must also change the Conversation file to fit the new situation. And we have to have each
conversation line happen in the correct sequence.
My new conversation file for the waitress looks like this:
As you can see I am also trying to use the Custom Tokens we made to contain the prices for this
particular inn.
AH! I never did that did I? Making it so that the prices could vary from Inn to Inn? Well get back
to that one. Promise.
Lets get back to the conversation.
Initial approach: How may I help you?
PC can answer any of the three, but the patrons answer is dependent on whether or not he has
enough gold to spend.
As soon as the patron has answered the waitress goes to the bar and tells the Bartender what the
patron ordered. Bartender answers and she then goes back to the patron with the order and gets
paid. She is then ready to pester a new patron.
There are Conditions on each branch and Actions Taken when needed.
From earlier on we remember that the conversation file works with a number of lines with
conditions on them (Text appears when) and a single line without condition.
So if no condition is met the conversation defaults to the last line/branch with no condition.
In this case the condition is found in the variable ORDER set on the waitress. If it is 1, we see
the line A glass of wine. And whom would she say this to? To the bartender of course.
Lets follow a typical day in the life of a waitress.
The waitress scans the room. Is there anyone who could need a drink? She finds a victim (customer)
and heads for him. IF THE VARAIBLE ORDER = 0. If it is she does the famous
GoToRandomPersonAndInit(oSelf,"NW_L_NODRINKSFORME",10);
The GoToRandom... function basically starts up the conversation with the random person.
In the conversation for the default line there are three possibilities. Two with conditions on them,
and one default.
The customers purse is quickly scanned and if he has enough money for wine he orders wine. If
there is only enough for ale, he orders ale and if he hasnt got any money he comes with a lame
excuse.
Lets pretend he has got enough money for wine. He then answers the waitress question with A
glass of wine please. At the very instant this sentence is uttered a script is run where the variable
ORDER is set to 1 and the waitress is sent to the bar waypoint and start her conversation file
$'
G
0 1*
*
*
0
$
+
#
=#+ 0=1<&
B
= B& '
() * $5 !
() * 8+ %$B+
!
$5 !
() * 8+ %$B!
B'&
< 10=& 4
;'
+=! = B'&
B
B'
again, this time with the bartender. Because of the other lines with conditions on them (and they test
for content in the variable ORDER she tells the bartender A glass of wine. which appears
because of a Text appears when condition like this:
0
%#
$'
G
-* *
/
$P
$5 1 *
$
< 10=
(
=#+ 0=1<&B
= B'
''
+ 6=
H
(
=#+ 0=1<&B
= B& '
5 1 * () * $
=#+ 0=1<&BQ7 1 1 0+"= 0 ! 0" 2=+ B'
() * $ +
&
< 10=& 4
;'
$+
&
B
B'
As you can see, she is sent to LAST PERSON I SPOKE TO which is a variable stored when she
first picks out the customer.
The variable ORDER is changed to 10 and as luck would have it, it corresponds with an
appropriate line in the conversation file for when the waitress speaks to the patron again with the
line Here you are <Sir/Madam>. The finest wine we have.
$'
G
0
.
0 1*
(
=#+ 0=1<&B
= B& '
We must remember to reset the ORDER variable to 0 or the waitress wont serve any more
patrons.
We can script something to set the variable to <> 0 if for any reason we want her to stop serving for
a period. And this is also what happens if the customer for some reason moves out of her working
zone (remember that one?).
So we have to make sure her variable ORDER is set to zero if that happens. Well get back to that
one.
We have another Actions Taken script for the customers answer Hmmm. Glad I didn'
t get the
House Wine then
We use the x2_am already made by Bioware: x2_am_act_paywin
I *
BJ7
*B
$'
G
$B!
" +
! 79B&"1 + # 0+
!='
The customer is relieved of gold equivalent to the price already stated in the x2_am_inc file.
Check out the relevant function in the file if you dont believe me.
And the problem with waitress stopping to serve if customer leaves working zone could be solved
by having the script that sends her back also reset the variable ORDER.
And that concludes our walkthrough of the waitress behaviour. You can have a look at the scripts
for the Waitress if you open her conversation file and have a look at all the branches and all the
lines.
There are still some issues with the waitress. If she gets distracted she might forget about the ale she
was supposed to bring to the customer. Ive experienced waitresses like that and find it to be part of
natural behaviour for a waitress.
Of course you cant mention anything to Nereng without him fiddling with it B-)
He points out that the forgetfulness is due to a ClearAllAction in the DoJob() function. Makes
sense really. He also points out that a solution could be to alter the heartbeat script slightly.
/$5 1 *
=#+ 0=1<&
B
= B'P
OO 5 1 *
=#+ 0=1<&
B
= B'P 7'
($'
You should be able to work out how to do this. If not you will just have to check out Nerengs
Ambient City.
And now we return to the prices. We should be able to have separate prices in separate
establishments. I was told that a drink could cost vastly different sums if you find yourself in the
right place. Ive actually tried this when I was a sailor. A bar in the harbour area beer cost 25
Danish kroner. In a bar in the red light district (swear on my mothers grave I was only visiting my
aunt) beer cost 85 Danish kroner.
- .
-
- * /
" * $'
G
0 #
0 #
0 #
+
+
+
$ :&
$ ;&
$ >&
+0
+0
+0
%$"1 + # 0+ 1=''
%$"1 + # 0+ 0"
+0''
%$"1 + # 0+
!=''
Since we have the possibility of storing local variables on object, module and area from creation
time, we might as well try to use it well.
Lets set some variables on the are (which is the Inn)
That should take of that. Now we need the programming to find them in the x2_am_inc script.
Best not to do anything to lines 44-46. We might forget to set the prices or we might prefer only to
set the prices for Inn where it is appropriate.
So we need to do something to lines 481-487
We need to make sure that the default prices are in place. Weve done that
We need to make sure that the correct variables are set on the area. Weve done that.
And then we need to change the SetUpPrices bit of the x2_am_inc.
" * $'
G
5
.
() *
0
/$P
5
G
"1
H
/$P
5
G
"1
H
/$P
5
G
"1
H
0 #
0 #
0 #
.
5
. *
1*
+ # 0+
1*
&
B"1 + # 0+
1=
+ # 0+
+
+
+
5 1*
1=B'
+0
5 1*
&
B"1 + # 0+
!=
5 1*
$ :&
$ ;&
$ >&
+0
+0
+0
'
&
B"1 + # 0+
&
B"1 + # 0+ 0"
+ # 0+ 0"
1*
=#+ 0=1<'
+0B'
1=B'
'
&
B"1 + # 0+ 0"
!=B'
+0B'
'
&
B"1 + # 0+
!=B'
%$"1 + # 0+ 1=''
%$"1 + # 0+ 0"
+0''
%$"1 + # 0+
!=''
And then we have to recompile all scripts that use the include file x2_am_inc. Rebuild module.
(Lucky for me. I almost gave up trying to keep up with his work. He just wouldnt stop. He kept on
and on with new ideas on how to use the ambient system).
He has written comments in the objects properties. He has explained it all. It is there for you to
learn from, to use and to expand on.
to "Chair", right-click on it and "Edit Copy" so that you can use it in other places in your module.
Make it "static" (properties/basic page) if you don'
t want PCs to use it. Finally, right-click on it
again and choose "Adjust Location". Set the z-axis (number beside Z) to 0,00. This is so that the
NPC will face the same direction as the chair.
Time to make some NW_INTERACTIVE placeables!
NW_INTERACTIVE divides all placeables into three groups:
1) Placeables with open/close animations that have inventories.
2) Placeables with open/close animations that don'
t have inventories.
3) Placeables with activate/deactivate animations.
Common to them all is that they must have the tag "NW_INTERACTIVE" and they must not be
static. The first group must also be useable, otherwise it won'
t have an inventory, the other two need
only to not be "static", but can be useable if you wish. Right-clicking on the placeable and choosing
"properties" will open the "basic" tab where you can change these states. Group 2) also needs to
have the "will save" set to 1. This group is fairly small and you propably won'
t be using it much
since it consists mainly of trap-doors and secret wall-doors.
Let'
s start by putting a standard armoire to the right of the desk. We open it'
s properties, and
noticing that it already has an inventory, we give it the tag NW_INTERACTIVE. That'
s all we need
to do in order to make our NPCs occassionally walk over and open it (or close it as the case may
be). There is a small trick we can play on it, though: If you uncheck the "useable" box and set it'
s
will save to 1, it becomes a member of the second group! Our NPCs will still open and close it, but
players won'
t be able to do anything with it. The armoire won'
t even light up when they cursor over
it. Useful if you like to give the player something to wonder about!
Now you can place a trapdoor to the left of the stove. There are two different to choose from in
"Secret Objects", the topmost is the one best suited for this interior area. Opening it'
s properties we
find that it is already not "static", so we give it the tag (NW_INTERACTIVE) and set the will-save
to 1. Here, too, you can uncheck the "useable" slot so that only NPCs can interact with it. I don'
t
recommend leaving this trapdoor for players to find as they would propably be more aggravated
than amused at finding a "secret trapdoor" that does nothing.
Now we need some placeables from group three. This also consists of lighting placeables, and
luckily CEP placeables work fine with NW_INTERACTIVE, so there'
s several to choose from.
Find the crystal ball in "Trades& Academic&Farm" and place it on the little table next to the big
chair. Don'
t place it right in the middle of the table, though. It needs to be closer to the edge towards
the room so that NPCs can reach it. Open it'
s properties as before, give it the tag, and uncheck the
"static" box. When activated by an NPC it will now begin to rotate. Unfortunately, if you make it
"useable", nothing will happen if a PC uses it. Open it'
s scripts tab to find out why - there is no
script in the OnUsed slot! Do you remember what we did with the chair to make it possible for PCs
to sit in it? Let'
s try the same here: scrolling down the list of possible scripts in OnUsed we find
"x2_plc_used_act", and voila! The crystall ball works!
The room needs a little more light, so now we put a candelabra somewhere. I'
ll leave you to decide
where you want it yourself. As before, we open it'
s properties to give it the tag
"NW_INTERACTIVE" and make sure it isn'
t static. This too can be made useable for players, and
this time we find that it already has a script in OnUsed called "nw_02_onoff". Good thing, because
we'
re getting tired of all that scrolling down the lists.
And that should be all except... there'
s a fourth group of placeables, isn'
t there? What about all those
placeables that doesn'
t have any animations? Well, we can give these too the tag
NW_INTERACTIVE and uncheck "static". The NPCs will then go up to it and play the GET_MID
animation, but of course nothing further will happen. I'
ll leave it to your own imagination to think
of placeables to do this with, except for one: the invisible object that you find in
placeables/miscellaneous. Put it on the kitchen stove, give it the tag, and uncheck "static". This will
make your NPCs interact with something that normally can'
t be interacted with.
I should also mention NW_ALTAR, which is a tag you can put on things you want your NPCs to
worship. Normally that would be altars, of course, but you could also give that tag to an invisible
object in front of the king so that his people will show some proper respect. Just don'
t spawn him
with ambient animations, or he will start worshipping too, which looks silly.
Another thing that needs mentioning is that you must uncomment in the OnSpawn script line 141:
SetAnimationCondition( NW_ANIM_FLAG_IS_CIVILIZED);
if your NPC does not belong to one of the player or humanoid races (orcs and goblins are
humanoids, demons are not).
In case you'
re now thinking that NW_INTERACTIVE is great, here are some downsides:
Placeables don'
t play the sound they should. Eg: a fountain doesn'
t make a running water sound and
torches can'
t be heard.
Lighting objects light up, but don'
t change the area lighting. This can look very silly in a "torch-lit
only" area.
Tagging doors as NW_INTERACTIVE doesn'
t work.
There is no way to control how much or little an NPC will interact with NW_INTERACTIVE
placeables. You can wait around forever before they do it, or they can get completely stuck opening
and closing the same thing over and over again. I can tell you that they seem to prefer talking to
other NPCs and sitting in chairs over using an NW_INTERACTIVE, though.
Finally, Georg Zoeller has earlier mentioned in the Scripting Forum that NW_INTERACTIVE was
made by Floodgate for Shadows of Undrentide, and that it is not officially supported by Bioware.
(So don'
t complain to Bioware about it.)
End of walk-through for "stay-at-home" NPCs.
Now for some "townwalkers"!
We make these by making a new version of the default OnSpawn script nw_c2_default9, just like
we did with the "stay-at-homes", but this time we uncomment line 119 which goes:
SetSpawnInCondition( NW_FLAG_AMBIENT_ANIMATIONS);
Once again: RENAME THE SCRIPT FIRST! Then put it in the OnSpawn slot of your townwalkers
properties.
The NPC will now chat with fellow NPCs and wander randomly about, except... he isn'
t going to
wander very far. He needs to know where he is supposed to wander, and for that you must place
some Generic Stop Waypoints. Find them among the standard waypoints and put them in all places
that you think he should visit. The Stop waypoints can'
t be too far apart. In my experience 20
meters between is about right (One area tile is 10x10 meters).
You can of course give the NW_INTERACTIVE tag to outdoor placeables too. An example: Place
a barrel somewhere, change it'
s name to "Trashcan", remove the tresure-scripts from it and give it
the NW_INTERACTIVE tag. Another idea is to put invisible objects with the tag on top of terrain
features like fountains and wells. And if the NPCs get weary from all the walking about they can sit
on benches and other things with the tag "Chair".
The "townwalkers" will also enter areas that are adjacent to the one they were spawned in which
have TAVERN- or SHOP- waypoints. So if you have some of those in your city or village you'
ll
want to place these waypoints there. There is a nasty snag to this, however: they never come out
again. The reason for this is that the engine is saving CPU power by dropping the NPCs AI-level to
very low when there are no PCs in the same area as the NPC. This makes them "forget" to leave the
area they are in (unless there'
s a PC there). There are some ways around this, the easiest being to
write this line in the OnSpawn script (The one you'
ve already renamed, NOT the default Bioware
script!):
SetAILevel(OBJECT_SELF, AI_LEVEL_LOW);
This will force the engine to always treat the NPC as if there was a PC watching him. The problem
is that the NPC will now be a constant drain on the CPU, instead of only taxing it when there are
PCs around. So this is something you should do as little as possible, especially if you are building a
PW or very big single-player module.
If a townwalker starts his life in an area with the HOME-waypoint he will leave it during the day
and return to it at night. This too suffers from the snag I just mentioned: if there'
s no PC around,
nothing happens. The solution is the same: SetAILevel.
In addition to luring townwalkers to their areas, TAVERN and SHOP waypoints make NPCs play
other animations than they would otherwise. (There'
s lots of drinking and laughing going on in
taverns).
I have seen some posters express concern that NPCs could start walking through several areas to get
to TAVERN, SHOP or STOP waypoints far from their home. IMHO this does not happen.
How many "townwalkers" should you have? Bioware has said somewhere that a good rule-ofthumb is one NPC per
five tiles. This means that a 10x10 area should have about 20 NPCs in all. My own experience
confirms this, but you
should take into account whether there are large, open spaces (town squares, parks), in which case
some extra NPCs are in
order. It is also a good idea to have NPCs with different behaviours: maybe a couple of guards are
walking waypoints,
another is standing at his post, there'
s a couple of immobile merchants with day/night postings and
maybe there'
s agroup of NPCs who are standing together, with Immobile/Mobile Close Range
is to your own module or just put the script on a placeable of your own. And that'
s all you need! Off
you go to write some conversations! If you want to, you can of course import the conversations
from Ambient City, and use them as a template or as they are.
The TRIGGER-method is very similar to the sundial-method (sorry - placeable method!). All you
need is a guard who walks between some waypoints, and the trigger "ChatTrigger". Paint several of
them in the path of the waypoint-walking NPC. It has a script in OnEnter ("n_am_chat_trigge")
which randomly signals nearby NPCs to start chatting randomly with each other. You can either
import the trigger, or just the script. It will only be triggered by a NPC with the tag "GUARD2".
And that'
s all there is to it here as well! This method should appeal to builders who don'
t like
heartbeats.
The last method is the UserDefined HEARTBEAT EVENT method, which is used by Flora in The
Halfway Inn. You set that by "un-commenting"
SetSpawnInCondition(NW_FLAG_HEARTBEAT_EVENT); in the OnSpawn script
"n_am_sp_m_anims", or you can use Flora'
s script "n_am_sp_multi". A lot of different events has
been set in her script, which goes with the "emote-triggers". Comment in or out as you see fit in that
script. The conversation on Flora has a large number of TextAppearsWhen scripts which are tailormade for NPCs speaking to NPCs. I hope you also like the script for an NPC healing another with a
potion.
Note that only NPCs with a class in "commoner" will be told to start conversations with the two
first methods. This is to make it easier for the sundial and trigger to pick out NPCs who have the
scripts on them. If you want some fighter, paladin or other class NPC to participate: just give them a
class in "commoner" or use the Heartbeat Event method.
I have done my best to reduce CPU strain from these scripts, but it has to be noted that both the
function GoToRandomPersonAndInit itself, and the sundial and trigger cycles through the area to
find valid targets. I believe this could be fairly CPU-intensive, but you will have to find out how
much yourself. In Ambient City it seems to be OK. Also, reducing the frequency (% chance that
they will fire) in the scripts will reduce this type of strain. This will also make it take longer before
the conversations between the NPCs become repetitive. Open the heartbeat script on the placeable,
and the OnEnter script of the trigger to do this.
Writing the conversations: Start by taking a look at the conversations on the NPCs. They are
am_talkative (on Flora)
am_waitress
am_x2_man
am_x2_female
Note that when the NPCs are speaking to each other, the PC conversation-node can be used. Also,
when the tokens points to one of the NPCs in the conversation, it is always to the one taking the
place of the PC. As usual, you must avoid putting scripts in a final owner-node, because it won'
t be
executed there.
Since neither the conversation-wizard nor the script generator will make conditional scripts that
work in NPC to NPC conversations, I'
ve made some for you:
n_am_taw_npc
n_am_taw_33npc
n_am_taw_pc
n_am_taw_doorman
n_am_taw_augie
better
n_am_taw_waitress
Finally, you should put the script "n_am_walk_wp" in CurrentFile Normal and Aborted to make the
NPCs resume their ambient animations more quickly.
Changes in 1.53
1. Fixed a bug where the shopkeeper would stop and never get to his POST_waypoint if you talked
to him in the morning right after he had left his home, by giving him a conversation line for that
situation.
2. Increased the shopkeeper'
s spot and listen skills to 8 so that he can see PCs who has tried to steal
from his chest in stealth mode but without having at least 8 points in Move Silently.
3. Moved all the ambient placeables blueprints to Special/Custom2 to make them easier to find for
builders who use CEP.
Changes in 1.5
1. Three new methods for using the function GoToRandomPersonAndInit. (NPCs randomly starts
conversations with each other and PCs.) With this comes also a bunch of TextAppearsWhen scripts
to use in conversations between NPCs.
2. Two fixes to the ambient waitress. She no longer stops working, and doesn'
t sell ale to the
bartender and door-guard.
3. Four emote-triggers for NPCs.
4. The merchant now uses NW_FLAG_SLEEPING_AT_NIGHT.
5. NPC sitting in a chair, and staying seated.
6. Several new placeables: Area lightswitch, Restingbed with a little twist, Background-music
changer, sundial, and many more.
7. A quick explanation of the x2 death system.
8. A fix to PCs closing the gate during the day, thereby shutting everybody inside the city. Thanks
to Sir Elric for pointing out this problem.
9. A trigger now stops Inquisitive Guard walking too far away from the gate.
10.A chest that makes nearby NPCs go hostile if you open it, but not if you are stealthy.
11.Tweaks and fixes here and there. New and old books in the library has most of it, or look at the
comments page of the object and the comments in the scripts.
Final note: Please don'
t hesitate to tell us if you find bugs or have comments on how you think this
package can be improved. And dont forget to rate either!
nereng
-
-ooOoo--
Appendix
What do all the different types of waypoints listed in the toolkit do?
By Baron of Gateford
This information is split into six sections.
The first section details the normal waypoint system (walkwaypoints)
The second section details the waypoints that can be used in conjunction with ambient animations.
The third section details the waypoint specific to the Beholder.
The fourth section details the NW_GENERIC_MASTER variable which needs to be set on NPC'
s
for certain settings.
The fifth section details how to set thee AI level on NPC'
s to make them walk even if the PC is not
in the same area.
The sixth section details other guides/systems that you may find useful
WAYPOINTS USED WITH WALKWAYPOINTS (or normal waypoints)
There are 4 different types of waypoint to get your NPC to move around in a set pattern via
the standard Bioware Waypoint system.
WP_ , WN_ , POST_ , NIGHT_
Each waypoint has a prefix (as shown above) followed by the TAG of the NPC.
So if your NPC had a tag of SMITH then the waypoint tags would be,
WP_SMITH, WN_SMITH, POST_SMITH, and NIGHT_SMITH
WP_ Waypoints: These waypoints are used to move your NPC around in the day.
WN_ Waypoints: These waypoints are used to move your NPC around at night.
POST_ Waypoints: Used to make your NPC walk to one spot and stay there at daytime.
NIGHT_ Waypoints: Used to make your NPC walk to one spot and stay there at night time.
The NPC can have multiples of the WP_ and WN_ waypoints,
but only one POST_ and one NIGHT_ waypoint.
Multiples of the WP and WN waypoints have a sequence number at the end of the tag name,
so for the NPC called SMITH, the waypoints would be;
WP_SMITH_01, WP_SMITH_02, WP_SMITH_03, etc....
The POST waypoint cannot be used with WP waypoints for a given NPC.
The WP waypoints override POST waypoints.
A similar rule applies to NIGHT waypoint not being used with WN waypoint
WN waypoints override NIGHT waypoint.
This means you cannot have the NPC run a set pattern of WP_ waypoints to then stand at
a POST_ waypoint.
The easiest way of getting the waypoints up and running for your npc is;
Right click on your npc and choose create waypoint.
A waypoint is created underneath or near the npc.
Move the mouse to the point on screen you want your second waypoint to appear, and then
right click, the option to create a waypoint is given.
Choosing create waypoint will create a second waypoint for your NPC.
This process can be done multiple times.
To get a guard to return to his barracks at night.
If the guard has a tag of GUARD, then place a NIGHT_GUARD waypoint in the barracks.
This can be used with a sequence of WP waypoints for your guard to patrol in the day,
e.g. WP_GUARD_01, WP_GUARD_02, etc
Or it can be used with a POST waypoint tagged POST_GUARD to have him stand at his post in the
day.
To allow for cross area transitions, e.g. Barracks in one area, patrol route in another.
You will need to set the global int X2_SWITCH_CROSSAREA_WALKWAYPOINTS to one on
the module.
To do this;
In module properties, click the advanced tab, then click variables.
Enter X2_SWITCH_CROSSAREA_WALKWAYPOINTS as an int and the value to 1.
My guard gets stuck crossing area transitions.(or is going a strange route)
You will have to experiment with this, due to some issues with the path finding.
If your area has more than one transition point to a second (but same) area then do not expect
your NPC to use the transition point you want.
It may be best to experiment using POST and NIGHT waypoints first to see which route the
NPC favours.
Its worth knowing this, so you know why its happening, and you don'
t waste too much time,
like I have
My NPC is getting stuck on walls.
This is due to the AI on NPC'
s being set to low if a player is not in the area.
One of the best ways to get around this is to have more WP, WN waypoints if you can to help
the NPC path find a lot better.
Obviously this won'
t help POST and NIGHT waypoints, but if you know scripting you could place
a script on enter of an area to check if any players are in the area and if not, jump the NPC
to its POST or NIGHT waypoint.
See the AI section below if you need the NC to move around regardless of PC'
s being present in the
area.
My NPC is not facing the same direction as his waypoint when at a POST or NIGHT waypoint.
Right-click the Waypoint and go to variables.
Enter X2_L_WAYPOINT_SETFACING as an int and the value to 1.
My NPC is not changing to its NIGHT_ or WN waypoints at night time.
Right-click the NPC and go to variables.
Enter NW_GENERIC_MASTER as an int and the value to 4194304
(the value listed above is for day/night posting only - see the section below on the
NW_GENERIC_MASTER settings.)
My NPC doesn't seem to want to walk to their waypoints
Ensure that the NW_GENERIC_MASTER has not been set for the
NW_FLAG_AMBIENT_ANIMATIONS or
NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS settings. (see the section below)
WAYPOINTS USED WITH AMBIENT ANIMATIONS
The following Waypoints require that ambient animations be switched on at spawn time
of the NPC.
That means that the following variable needs to be set on the NPC.
Right-click the NPC and go to variables.
Enter NW_GENERIC_MASTER as an int and the value to 524288
When ambient animations is switched on for a NPC, the NPC will wander around and
interact with other NPC'
s that have either ambient or immobile ambient animations switched on.
They will also interact with nearby placeables. Walking up to a placeable, closing nearby doors.
Also worth noting that the NPC'
s will also use the same animations for ambient animations,
as they do for immobile ambient animations (with a bit more moving around).
The NPC with ambient animations switched on will never wander too far from its spawn
point(starting position), always returning back to it.
The following waypoints allow for better control of your NPC'
s.
To wander around more between the waypoints described below, as well as the placeables the NPC
comes across, or the other NPC'
s, or its spawn point(start position).
Remember - The NPC'
s will not walk straight to these waypoints as in walkwaypoints above but
will casually walk around and occasionally walk to one of them.
After long testing, the NPC only seemed to want to leave the area if a player entered it,
however the NPC did return back to the area at night.
This is due to the AI level of the creature.
See the AI section below if you need the NC to move around regardless of PC'
s being present in the
area.
Safe Waypoint
This waypoint is tagged "NW_SAFE".
Placing one of these waypoints in area, means that any injured NPC with ambient animations
will retreat to this point.
Sort of like a cowering corner.
NPC'
s will not cross area transitions to get to a NW_SAFE waypoint.
If there is not a NW_SAFE waypoint in the same area then they will resume ambient animations.
Stealth Waypoint
This Waypoint is tagged "NW_STEALTH".
Placing one of these waypoints in an area, means any NPC with stealth capabilities that reaches
one of these waypoints, turns stealth mode on.
Could be good for using in dark caverns/dungeons etc, to have NPC disappear into and appear from
the darkness.
Detect waypoint
This Waypoint is tagged "NW_DETECT".
Placing one of these waypoints in an area, means any NPC that reaches one of these waypoints,
turns detect mode on.
Again, could be good for using in dark caverns/dungeons etc, to have NPC'
s start to detect hiding
PC'
s.
My NPC is not wandering around even though mobile animations is switched on.
Ensure that the NW_GENERIC_MASTER variable has been set on the NPC for
NW_FLAG_AMBIENT_ANIMATIONS
and not NW_FLAG_IMMOBILE_AMBIENT_ANIMATIONS.