Ted's RPG Rant

A place to rant about RPG games, particularly the Temple of Elemental Evil. Co8 members get a free cookie for stopping by. Thats ONE cookie each, no seconds.

Tuesday, September 27, 2005


A simple scripting idea (with no scripting supplied ;-) for keeping track of larcenies in the Keep.

In various houses (not all, but some) there will be hidden compartments, along the lines of Terjon's bookshelf, that you have to search for and can find stuff in.

Inside will be gems or other valuables. But they will be, not flagged, but specific: ie say you nick the Castellan's family jewels (down, Bertram!) then you won't get say a generic 'opal' and 'pearl', you will get unique protos. These can be written into the protos.tab in place of 'Otis' magic jockstrap' and 'Wonnilon's scroll of penicillin' and all the other individual stuff there is in ToEE we don't need.

Now, when you try to sell them, you just MIGHT be selling them to someone who recognises them... that can be scripted in through recognition by id#. Probably the party should have the chance to bluff their way out of it (if they can), although for mundane things they should be able to get away with the thievery: who can really tell one plain gold ring from the next?

The scripting bit: the box or shelf or whatever has a heartbeat, that periodically checks if the equipment it contains is now in the hands of the party (there are various scripts already in existance for this, Otis' anvil comes to mind). If it finds it IS there (and thus has been nicked), then it adds one to the 'things nicked' variable, and game.new_sid=0's the heartbeat (job done). Of course if the variable gets high enough, we have a crime wave and the Watch will take appropriate measures. (See earlier ramblings on the behaviour of the Watch, here).

Also, if the thing nicked is jewelry or armour, then the owner, in conversation, will of course have a script to see if the item is equipped (ie worn). A line or two in san_dialog will do nicely. If so, the NPC will act accordingly:

Castellan: You seem to be wearing my mother's jade necklace that was stolen last Friday night, when you were here for a visit.
PC: Ah well see the thing is, I can explain that...
Castellan: Of course you can. Archers, FIRE!!!

Edit: Just realised, there are flag, ocf2_item_stolen and oif_stolen that could perhaps be flagged for any jewel etc that is hidden in one of these chests or whatever, that can quickly be scanned for by a single script if in the party's possession, to save having to create new items all the time. Well, some of the time. And maybe we can have some sort of fence who will give you a better deal (but then has the wool over you for selling stolen goods) compared to say one of the more honest merchanst who won't trade with you at all so long as you have stolen merchandise in your possession.

Sunday, September 25, 2005

Poor Eels

My poor Eels LOST, after finishing the season at the top of the ladder - no mean feat in the closest Rugby League season in histroy.

Last final - game to get into the Grand Final next week - and they had a shocker, nothing went right and the team that had both scored the most points all year and conceded the least went down 29-NIL.


There is always next year of course, when our rookies will have finals experience and we will undoubtedly do better, but for now its depressing.

Don't expect anything sensible from me tonight by way of emails etc.

Saturday, September 24, 2005

How it stands

I am really in the mood to do some more tutorial work but I have a lot of other stuff to do (still) particularly about getting the starter pack out for KotB. So for the moment I will simply post a blog letting people know how things stand with everything that is going on.

I have found the remaining problems with my mod. Thanks to Agetian I fixed the Ah Fong CTD issue and after much frigging around I fixed the naked St Cuthbert issue. So, everything there is done, and my end of the Co8 4.0.0 project has been passed on to Cerulean. O and I was able to do a complete changelog. COMPLETE. Well almost complete ;-)

Sol has provided Liv's email address (NOT for public consumption of course, I won't even be using it myself) so we can get in touch and ask if there is anything she still wants to pass on.

Screeg has made several more maps (he has mapped 10 seperate locations, with multiple floors and day/night versions for them) and is working on the main keep map. He will doubtless do a better job than mine! I am currently sectoring some of his maps.

A friend of mine, the very artist who was meant to help in the first place, is doing some art for me to pass to Gaear for our first ever fan-made cut-scene.

Spike has provided me with all the original art from the module and indeed everything from the original module in an easily distributable web form. Again I am just not going to hand out the module top everyone - copyright, u know - but people who want to get on board and want to ask about this and that will have the answers at their fingertips.

Edwin is providing plots at a rapid pace and several plot-lines are being thoroughly fleshed out.

Thats about it! Lots of other little things going on, of course. All coming along slowly but surely.

Tuesday, September 20, 2005

Proactive NPCs

Welcome to part 6 of the Dialogue writing tutorial, and what a pretentious name it has!

By 'Proactive', I mean situations in which the NPCs butt in and say their piece (or react) without the PC initiating it. We have seen that generally events have to be triggered by the PC (who is defined as the triggerer in many scripts, or will be the effective triggerer) and as far as dialogue goes, it is triggered by the player clicking on the NPC to initiate dialogue (or selecting talk from the radial menu).

Many of the proactive events are no different, they are still triggered by something the PC does, its just not as blatant as a click from the mouse. An obvious one is when you move near to an NPC such as the sentinel outside the ruined Tower, who speaks as soon as you get near (or any of the NPCs in the opening vignette, again they will start talking as soon as you go near them, you don't have to click on them and you don't get the option of just walking past).

Dialogue-by-click (if we can call it that) is activated by the san_dialog script we saw earlier. This script is accessed by the game when you clearly initiate dialogue, by clicking or selecting 'talk' on the radial menu. Proactive efforts are done by another method. This is the ubiquitous 'heartbeat' method you may have heard reference to.

The heartbeat is a script that fires every couple of seconds (no surprises for guessing where the name came from). It can do pretty much anything you like, but here we are going to consider its use to start a dialogue. Since Liv always does these things the best, lets look at Kent, her kiddy at the start. (His script is py00228kids_off.py)

for obj in game.obj_list_vicinity(attachee.location,OLC_PC):
__________if (obj.distance_to(attachee) <= 30 and game.global_vars[702] == 0 and critter_is_unconscious(obj) != 1):
______________if (obj.stat_level_get(stat_race) == race_halfling):
_______________________game.global_vars[702] = 1
______________elif (obj.stat_level_get(stat_race) == race_halforc):
_______________________game.global_vars[702] = 1
______________elif (obj.stat_level_get(stat_level_paladin) >= 1):
_______________________game.global_vars[702] = 1
______________elif (obj.stat_level_get(stat_level_wizard) >= 1):
_______________________game.global_vars[702] = 1
______________elif (obj.stat_level_get(stat_level_bard) >= 1):
_______________________game.global_vars[702] = 1
_______________________game.global_vars[702] = 1

Well that looks complicated! I barely understand it myself. But it starts repeating itself pretty quickly so it won't take too long to see what it is all about.

First line:

for obj in game.obj_list_vicinity(attachee.location,OLC_PC):

Obviously words like 'for' and 'list' tell us we are going to do a loop. What we are checking for is a list of objects in the vicinity of the attachee's location (ie anything near where Kent is at that moment), and seeing if those objects are PCs. If they are, it moves on to the next line:

if (obj.distance_to(attachee) <= 30 and game.global_vars[702] == 0 and critter_is_unconscious(obj) != 1):

Note 'if' clauses always end in a colon.

In the event that a PC is detected, it checks:

Is s/he close? Actually 30 is pretty far, but remember Kent is MEANT to speak to you as soon as you appear.

Is the critter conscious? Note how it is phrased - is the 'critter_is_unconscious' flag for the object (the PC) NOT equal to 1. I am not sure why that is there: possibly you can come thru from a combat start like CE, NE or CN with noone in a state to talk. But if so, how did you win the combat? No idea, maybe Liv is just making sure or she played through an obscure situation where it happened.

And finally, game.global_vars[702] == 0. You will notice further down that when one of the choices is made, it sets this variable to 1. Once this variable is no longer 0, Kent will never butt in in this manner again. It makes sure he only does it once. (Kids can still butt in though, look further down in the file and you will see they can come and annoy you a fair bit).

If all these conditions are met, it goes on to the next line passage. This is a series of conditions that establishes where the dialogue will start. Here we see why Liv specifically went for a list of the PCs and not just checking if there was A PC (or the leader, game.party[0], or whatever). Its so all the PCs could be checked for to see (in order):

if there is a halfling

if there is a half-orc

if there is a paladin

if there is a wizard

if there is a bard.

If that is meant to be from least to most likely - so you get to see obscurer lines first - then I would have put the bard ahead of the wizard myself. If none of these are present then you get the default line.

The lines of dialogue that start, then, are dependant on what is there.


It is not just 'start at line 1' as we have been doing with simpler examples. Rather, we have the following lines depending on the PC examined:

{500}{Hey, a new kid! Where are your parents? What grade are you in?}{Hey, a new kid! Where are your parents? What grade are you in?}{}{}{}{} halfling
{600}{[looks frightened] Um... uh... Are you a giant? You won't eat me will you??}{[looks frightened] Um... uh... Are you a giant? You won't eat me will you??}{}{}{}{} half-orc
{200}{Wow! Are you a real knight!}{Wow! Are you a real knight!}{}{}{}{} paladin
{300}{Wow! Are you a wizard!}{Wow! Are you a witch!}{}{}{}{} wizard
{400}{Wow! Are you in a traveling band!}{Wow! Are you in a traveling band!}{}{}{}{} bard

Wonder why Liv didn't use question marks? O well ;-)

So that was all pretty straight forward: if the party goes near Kent (and they will, he is positioned so they will ;-)) then his heartbeat file will trigger an appropriate line of dialogue.

Note that if we didn't care if the party never spoke to Kent again after this, we could avoid using san_dialog all together: Kent would just show a floating line when you clicked on him (like one of the pirates wandering Nulb) but will still have his dialogue triggered by san_heartbeat. The two are completely independant.

Why do some critters have floating lines to cover a lack of dialogue and others (like chickens) don't? It depends whether they are flagged as 'mute' in their object critter flags. If they are, they show nothing: if not, they will show a generic dialogue line.

One more example, something much simpler: the goon who screams 'intruders' in my mod. Now, this is messy and complicated as only a mod can be: the goons are dlg file 00286, but they work off heartbeat py00288 (because I wanted him to speak first, but he was too far away - I should have used Liv's vicinity of 30 thing perhaps) and also contain a dialogue line for the daemon who gets summoned (to save having a whole new dlg file for it - Liv likewise stores other things in the kids' file.) Note that because the goons have their san_dialog set as 00286, when their heartbeat script fires for a dialogue (we are about to see this) it fires dialogue from file 00286 even though it is py file 00288. Interesting! I wouldn't have thought it would work like that, but it does!

The heartbeat is like this:

def san_heartbeat( attachee, triggerer ):
________if (not game.combat_is_active()):
________________for obj in game.obj_list_vicinity(attachee.location,OLC_PC):
________________________if (is_safe_to_talk(attachee,obj)):
________________________________game.new_sid = 0

First it checks there is no combat going on (this is common - you shouldn't speak during combat unless it is something very specific, such as Lareth's offer to surrender. To have an NPC want to initiate chit-chat with you while you are hitting them over the head with your flail is silly.) Then it checks for something in the vicinity, a la Kent. It checks again dialogue is possible, starts the dialogue at line 10, and finally changes the heartbeat from 00288 to 0 - the heartbeat has done its job so it is now scrapped (they can have a performance effect, so you only use them if you have to and try not to leave them running). This saves setting a flag as Liv did (well, a variable). Game_new.sid, as you will know from what Agetian posted about this, means the sid (script id, in this case 00288) is reset to a new one, in this case 0 (nothing). It could have been set to something else for some other critter, even as I am using the different py files for the Goons, the baddie and the Daemon. Note that even though Agetian hsa just explained this to us, Liv was using it aeons ago - for instance, she disabled this command in Shenshock's script to make him work better. Always one step ahead ;-)

So the heartbeat for dialogue is easy, isn't it. Since this fires the instant we walk onto the map, we could probably skip the combat and is_safe_to_talk bits since there has been no time for anything to happen. Its that easy.

What other proactive stuff is there? Well, there are the butt-ins. These are when an NPC starts talking even though you are in dialogue with another. Some examples are Monier and Sunom (if a female PC is chatting to Monier, Sunom butts in resenting it) or the back and forth between Lila and her hubby in my mod. Of course Elmo and Otis chatting away to each other when they first catch up is the same principle, or Riana and her sister reacting to each other, or switching from Elmo to Prince Thrommel if you find him in Elmo's presence (or numerous other NPCs who react at that moment - Zert has the floating line, "quick kill him!" or something). This actually happens a lot in the game though not necessarily a lot in play if you take my meaning.

Lets see what these calls are, ummm, called in the .py files:

py00005 Calmert to Terjon: switch_to_terjon( npc, pc ):

py00005 Calmert to Spugnoir: look_spugnoir( attachee, triggerer ):

py00017 Meleny interrupts Mona: buttin( attachee, triggerer, line):

py00084 Sunom to Monier: argue( attachee, triggerer, line):

py00091 Elmo to Otis: make_otis_talk( attachee, triggerer, line):

py00091 Elmo to Thrommel: switch_to_thrommel( attachee, triggerer):

py00100 Riana to Jenelda: together_again( attachee, triggerer ):

py00108 Bertram to Preston: buttin( attachee, triggerer, line): (butt-in, Bertram?)

py00109 Dala to Dick: make_dick_talk( attachee, triggerer, line):

py00112 Murfles to Y'Dey: buttin( attachee, triggerer, line):

py00121 Tower Sentinel to Lareth: talk_lareth( attachee, triggerer, line):

py00170 Taki to Ashrem: switch_to_ashrem(npc,pc,line,alternate_line): (that looks complicated!)

Etc. I have shown these at length in order to demonstrate there is no single way of doing this, even within a .py script (like Elmo's or Calmert's) there might be more than one thing defined. But they all look pretty similar in action.

I used Monier and Sunom's carry-on as my template by and large because it goes back and forth a few times and is nice and familiar. Lets look at it in detail as a script and see how it is applied. (From py00085).

def argue( attachee, triggerer, line):
________npc = find_npc_near(attachee,8006)
________if (npc != OBJ_HANDLE_NULL):
________return SKIP_DEFAULT

Simple enough? Again, attachee is Monier, triggerer is the PC, and line is the line number of the dialogue you are GOING to (Sunom's).

Now: first of all, it looks for Sunom and makes sure she is there (the party might have snuck in, killed her, beat Monier unconscious then came back later. Stranger things have happened! Or they might have charmed Monier and be holding this conversation, not in the weavers' house, but out on the parapet of Burne's tower or some other obscure place.) Finding her is simple enough, she is id #8006 so we start with

npc = find_npc_near(attachee,8006)

As you remember from above this defines her presence as a variable called npc. The actual finding bit is the next line: having established this concept of 'npc' being near the attachee (Monier) it is either true or false. So the comparative line reads

if (npc != OBJ_HANDLE_NULL):

Common enough proposition: 'null' means no, basically; the search has returned a null result. That is, Sunom is NOT there. So, here we are asking if the proposition 'npc' (Sunom's presence) is NOT equal (!=) to not happening! Confused? Damn double negatives! But thats the way the game operates, you will get used to it pretty quickly.

What happens if it DOES return a null verdict - if Sunom is absent? Jump ahead to 'else', and we see that what happens is


Note it is the attachee line 10, Monier's: his dlg line 10 is the copout:

{10}{I cannot talk now. Please come back later.}{I cannot talk now. Please come back later.}{}{}{}{}

Its good to have a copout line though! They usually do: you might want an NPC to butt in if you have a particular NPC follower in the party, (like Elmo with Otis) but because of the vagaries of the pathfinding, you often initiate dialogue on big maps while your NPCs are standing around far away wondering what to do. Initiating dialogue across sectors like that looks ridiculous and may well cause a crash. So NO SKIPPING THESE BITS.

Anyways, assuming Sunom IS there, the 'obj_handle_null' thing will return false (not equal, !=) and on we go. Next line:


It will go to the npc line number specified - this is the switching bit, because we have defined npc as Sunom.


This makes Sunom (the npc) and Monier (the attachee) towards each other, so instead of facing the PC when they yellll at each other, they face each other. Nice touch, but I bet you don't notice ;-)

Now, how is it fired in Monier's dialogue? Lets see:

{20}{[no response]}{I was not leering!}{}{}{}{}
{21}{And I...}{}{1}{}{0}{argue(npc,pc,40)}
{30}{[no response]}{Sunom, you are overreacting! I would never...}{}{}{}{}
{31}{I think...}{}{1}{}{}{argue(npc,pc,50)}
{40}{[no response]}{Sunom, mind your manners! She is a customer here!}{}{}{}{}
{41}{Now wait just a...}{}{8}{}{0}{argue(npc,pc,60)}

So between each line it goes off to Sunom, then she sends it back again with a similar script of her own (identical, actually).

The actual call of the script comes from the PC's line, because if you fired it from Monier's his would disappear before you could read it and probably they would wizz back and forth so fast you wouldn't even notice ;-) It means you have to say some little thing or have a 'continue' line in the PC's part but that can't really be helped.

It says argue(npc,pc,40). Now, watch carefully: this calls the defined thing argue( attachee, triggerer, line):. So hear 'npc' refers to the attachee, Monier, NOT to Sunom who then gets defined as 'npc' in the script seperately. Don't get them mixed up or you will be sending people to the wrong lines!

BUT the line number is still defined as '40' so that will be SUNOM's line number. It will go to line 40 of Sunom's dialogue: lets look at it.

{40}{[no response]}{Please, your eyes nearly bugged out of your skull! And you winked!}{}{}{}{}
{41}{Excuse. . .}{}{1}{}{0}{argue(npc,pc,30)}
{50}{[no response]}{Oh shut up, you hussy! Leave my husband alone!}{}{}{}{make_hate( npc, pc )}
{51}{Hussy? Who are. . .}{}{8}{}{0}{argue(npc,pc,40)}
{52}{Hussy? Me not. . .}{}{-7}{}{0}{argue(npc,pc,40)}
{60}{[no response]}{She is no customer! And don't tell me what to do, Moneir! I have half a mind to tell my father about this!}{}{}{}{}
{61}{Well, half a mind is about. . .}{}{8}{}{0}{argue(npc,pc,50)}

The 'no response' bit for males is of course because you only get this when you start a conversation with Monier and a female PC.

That's about it. Its pretty straightforward. :-)

To soldier on to the next installment, click HERE.

Some things I hate

A quick rant before hitting the 'draft' button and getting on with more important things.

I hate it when a program butts in. How many times are you typing away at an email, or IM, or forum comment (or blog ;-)) and you look up from the keyboard (those of us who have to peck away with our eyes glued to the keyboard to type) and realise everything you just typed is not there because some program has just butted in and put itself on top. Or worse still, you are typing away while something downloads in the background or some slow-running thing is happening, and it butts in just as you finish typing and hit the enter key and instead of a carriage return on your typing, you have just entered 'cancel' for something you were waiting an hour for! >8-/

Hate it hate it hate it. If I had any programming ability I would prevent it - I would make a li'l utility called 'stay on target' or 'stay on top' (ooo-err ;-)), i would advertise it on TV as 'the most useful utility in the world' and people could come to my site and downlaod it for free, no strings attached. The ad revenue from the site would more than pay for the TV ads cause it would actually BE the most useful damn utility in the world (better than the 'open things with one click instead of two!' crap you see around, why do people waste their time on such things?)

The second thing I hate - NORTON. Its gotta go. It is not even working now, it is just sitting there with a big red cross over it, won't start and was flashing up some stupid error message 'Norton is switched off so you have to be told every 3 seconds cause its the worst news in the world' until I used the task manager to turn off every damn thing running that looked vaguely like it was from Symantec (but it is still in the tray). Symantec are an absolute disgrace - no uninstall, no ability to turn it off, Norton is a FUCKING VIRUS ITSELF. The 'help' thing reckons its carrying on because I have the Audigy startup thing enabled - HELLO!?!? Its been like that since I got the damn thing 3 years ago? Thats the thing, it has started carrying on out of the blue and I have not made any changes to the PC lately (well I updated Yahoo Messenger recently - don't get me started on them, thats only on step awea from being a virus itself). Long time readers of this blog (or possibly it was a forum entry on Co8...) will remember me saying that when I tried switching Norton off in MSconfig, ToEE started running in XP for the first time ever (though still took out the whole OS when I hit quit which sorta defeats the purpose, since I normally restart and play ToEE in 98) but then when I tried to turn Norton back on in MSconfig, it had to be REINSTALLED!!!! Piece of CRAP - seriously, this is everything Neil Young sings about. If I had a spare cent i would throw the Norton CDs in the bin today and get something better. Really, though, I need to do a clean install of XP.

Some good news - Screeg has now finished all the little rooms along the south wall of the Keep (numbered '7' in the original module). He is supplying things so much faster than I can do anything with them ;-) must get on to that. Got a couple days off coming up and can hopefully get on top of it all.

Sunday, September 18, 2005

Cat stuff

Ever noticed that most blogs are 43% useful stuff, 51% regurgitated rubbish that you've already read in a spam email, and 16% nonsensical statistics that were made up on the spot?

Yes its regurgitated rubbish time! This is something to keep visitors amused, entertained or at least occupied until I can write something more useful (like finish that damn draft of the Dlg Tutorial part 7. Its about getting NPCs to butt in and initiate dialogue in various situations).

Today's blog is about cats, in honour of my gorgeous e-pal Sheila, who has a new kitten (well, not so new now ;-)). Enjoy!

If you can feel your cat's ribs with your fingers and see his waistline, he's probably healthy. If not, help your kitty drop some weight:

Get him to play. Invest in some interactive toys such as a fishing-pole line for him to chase.

Watch portions. Keep her food out of reach when you're not home. Cats should be fed mornings and evenings -- don't let them graze all day.

Make him move. Encourage your cat to climb by putting a table in front of a window that looks out to a bird feeder or some alluring sight.

Be patient. Have your vet weigh the kitty every few weeks at the start of the weight-loss program. Cats can safely lose up to 1% of their initial body weight per week.

A list of cat myths

1. Cats should have a litter before they are spayed.
This is not true. Cats that have a litter before they are spayed are not better for it in any way. In fact, spayed cats are healthier and have eliminated the risk for life-threatening uterine infections.

2. Street cats are always healthier than purebred cats.
This is not true. Both purebred and "street" cats can be unhealthy. Both can have diseases, however, many mixed breed "domestic" cats do not have many of the genetic diseases common in purebred lines.

3. All cats prefer canned food.
Some cats do but some cats will only eat dry food.

4. Cats cannot be trained.
This is not true. Cats are very smart and can be trained to do tricks.

5. Cats like tasty food.
Cats have poor taste buds and eat primarily based on their sense of smell.

6. Cats will let you know when they are sick.
This is not true. Cats generally are very good at hiding that they are sick by survival instinct, thus not to appear vulnerable to "prey". Often by the time they show you that they are sick, their disease or condition is quite advanced.

7. Cats don't need heartworm prevention.
This is not true. Cats can get heartworm disease, even indoor cats. Heartworm disease is spread by mosquitoes, which can come inside.

8. Cats don't need litter box trained - they naturally know where to go.
There is a natural instinct for many cats; however, not all cats understand the litter box concept.

9. Cats are happier and healthier when they are outdoors.
This is not necessarily true. Many cats are happy being outside at certain times, especially when the weather is good. However, during bad weather, they would prefer to be inside. Nevertheless, outdoor cats are definitely not healthier than those that remain indoors. The average lifespan of strictly outdoor cats is estimated to be approximately 1 year of age; indoor-outdoor cats about 3-6 years and indoor only cats have an average lifespan closer to 13-15 years.


1. "If life hands you a lemon, then tie it on a string and make a play-toy."

2. "There's more than one way to skin a dog."

3. "Give a man a fish, and he'll eat for a day. Teach a man to fish, and I'll personally move into his garage."

4. "When the going gets tough, the tough find a sunny spot by the window."

5. "Fool me once, shame on you. Fool me twice and I'll scratch your face off."

6. Better to have napped and been disturbed, then never to have napped at all."

7. "Never drag home any dead thing that is larger than your head."

8. "Today is the first day of the rest of your lives."

9. "As you travel along life's long & lonesome highway, don't forget to stop and eat the roses."

10. "To err is human."

Friday, September 16, 2005

Keep Map done (for the moment)

I have finished a working Keep map, its still as ugly as sin, lacking everything from shadows to windows and many doors to chimneys to everything, but the buildings have rooves and you will be able to walk around it (and there are doors for the interiors Screeg has done) so it is ready to be sectored and thrown out. Screeg is creating maps at a phenomenal rate, I really must put some more up on the site so people can see, so when I put out the starter pack (still on target for 20th) you should be able to actually start a party and wander around the Keep (a bit) and people who want to create NPCs will have somewhere to spawn them.

Off to bed, then work tomorrow, more details after that.

O and Sydney are in the AFL grand final! Woohooo!!!

Thursday, September 15, 2005

First KotB dialogue underway

Well I had to work late tonight, and after the kids were in bed it was just me and the house Celeron for the last couple hours, so I powered up Notepad and got hacking at the first lines of dialogue. It was for the Watch (the guards what wander the Keep) who will hopefully actually be wandering around the map when the starter pack goes out. Starting writing I didn't have much in mind, just a few "move along" lines to get me going, but it was one of them moments like in Finding Forrester, you just start writing and you get in character and it takes over. Next thing I knew I had gone from inane crap - "where can I find accomodation in this here Keep?" - to a whole bunch of offshoot ideas, trying to bribe the guard, trying to get him to let you into the Fortress (on the pretext of attending services in the Chapel of Kord), cunningly getting him to talk about less well known things like the dungeons beneath the Keep, getting on his good side so the Seargant of the Watch will have a better reaction to you, and various alignment- and skill-related variants to these. These was just the 'off the top of my head' ideas. I also worked on a script to randomise his reaction to bribery, from accepting it thru rejecting it to telling you he will inform his superiors (depending on game state of course - if the PCs have been on a killing spree and the Keep is under Martial Law but they have not yet been identified as the culprits, the guard will still chat to them but will not be bribed under any circumstances). The random element reflects the randomness of which sort of guard you may be speaking to, a scrupulous one or a more mercenary one.

It was rip-roaring good fun to throw these ideas out and then just follow them wherever they led. I really do recommend people think about signing up if you have any sort of imagination and desire to see KotB come to fruition.

Back to working on the Keep map tomorrow.

Ted's Mods

An update on my mods for strangers who pass by.

I have done two main mods so far:


I have added about 40 or so PC voices (for your characters) to the default 22 in the game. They are available to download from Co8, in three packs, along with the control files. They are compatible with basically every other mod (they add / change files no one else has fiddled with ;-))

Get them from this thread, with full instructions (and bug-related feedback)

TED'S MOD v1.2.1

This contains a variety of things I have done for the game, bug-fixes and added stuff for the NPCs to make everyday play a bit more fun, and also has my main mod, Desperate Houewives, a trip through the seedy underbelly of Hommlet with an Ultima-flavoured twist :-D

This requires the official Atari Patches 1 & 2 (for those who don't know - DON'T USE THREE if you are going to use mods) and the Co8 mods 3.0.4 and Liv 1.5.1 (again for those who don't know, these are the DEFAULT mods to fix the game, everyone should have them). Those patches are all available HERE. (You can skip the meobius2778 fixes, they are INCLUDED in Liv's patch) Then add mine over the top. Full install instructions included, as well as details of the work of other modders included in mine (one thing I did was roll together about a dozen patches doing the rounds and build my stuff to include them).

My mod is HERE.

Note this is version 1.2.1, so it has been through many bug-fixing patches and is quite stable (the patches mainly added new content, I hasten to add!). But it DOES overwrite the portraits file so if you have custom portraits, you will have to reinstall them.

There is also a server where people can download all this HERE.

More stuff to come when I have time. This stuff is all free, so NO DONATIONS. If you would like to help disseminate it, just send people to www.Co8.org :-)

Tuesday, September 13, 2005

While we're waiting...

Part ummmm 6? 7? of the dialogue writing thing is in draft atm, don't think I've forgotten. Here's a kwik rant and anything else I can throw together to amuse you for the moment.

My rant is a familiar theme - monsters walking over each other where players can't.

I was playing through from the beginning again to test the full install of the mod and was in the moathouse, about to go into the room with the Bandits up the top (through the door, not the secret passage from outside). So my paladin, 'Ted the Holy' (my alter-ego :-P Or should that be altar-ego? ;-)) opens the door. A bandit runs out, and Ted and Elmo thump him.

Then Zert moves in. I wanted Zert to have a crack as he was armed with a special cleaver (crits on anything above 12 - NOT in my mod as released!!) to test the critical hit voice I have activated for him. Only Zert doesn't get a swing - despite having a clear line of attack, the game decides there are too many characters near the door and he doesn't have room. [sigh]

So we kill that first bandit. My wizard tries to charm the Barbarian leader in the background, to use him downstairs as cannon fodder for the Ogre. Of course, he saves.

Another bandit runs out. We kill him too, Zert still doesn't get a shot. Spuggy tries to charm the bandit, he saves again [yawn]

So now the Barbarian comes out. Crack, he lands a massive beaty on Ted's head. Still Zert gets no go, not a surprise of course: neither is what happens next, cause it has happened so many times before.

ANOTHER bandit comes out. Never mind there is a hulking barbarian there, he squeezes in, takes a wild swing.

And ANOTHER of the FUCKING THINGS comes out, he runs PAST my characters, through the gap that is apparently Zert-proof, and flanks my party!!! Thats right, my characters can't get in there to have a swing, but they can drive COLUMNS OF TROOPS through there! I mean its like when Guderian drove the 19th Army Corps through the Ardennes, they should be talking about this for generations to come.

Its just WRONG.

Then the Barbarian cracked Ted again, [he makes saves, he never misses, he's a marvel isn't he] and Ted's down at -8.

So I think, "to Tartarus with this, where's my .50 cal?"

O of course, Ted was carrying it because he was the only one who could comfortably take the weight. I resist the urge to punch the monitor off the table (I actually did that once - don't worry, it wasn't my monitor. One of my mates was a bit pissed afterwards though ;-)

Zert at least has a target now, he chops the flanker in half and my cleric can safely get off a spell to stabilise Ted. Elmo finishes the Barbarian and other bandit and Zert goes in to kill the one with the crossbow.

He lands a critical. No voice, no floating text, nothing.


Friday, September 09, 2005

Ideas for KotB

Ok, this is just some brain-spew on KotB and some info for people interested.

One way players will be able to adventure thru the Keep is by only being able to access certain areas as they achieve certain outcomes. Specifically, the Inner Gatehouse, the various towers, the walls, the roof area on top of the Stables, and the Guildhouse. As they gain the confidence of the various leaders of the Keep (by heroism or guile) they will be admitted to more areas, and thus learn more or have the opportunities to find or steal keys to yet more areas, or befriend / bribe / intimidate certain people. In this way, as the different sections open up, the player can truly adventure through the Keep and it will be a genuine place for fun, not just to rest and buy stuff.

Information about the mod can of course be freely exchanged among modders. However, a few things will be 'need to know', so that the modders themselves (hopefully including me!) will still have a few surprises when they play it through that first time. Otherwise, the more we share the better.

The Church in the Keep looks at this point to be a Church for Heironeous. There will also be a chapel to Kord in the Fortress which many of the guards use, and of course there will be some rivalry between the different clerics and factions (no damn 'conversion' quests though, please!)

Some clever puzzles would be VERY welcome. There is not a whole lot of support for such things, perhaps, but that just means we have to be smarter in coming up with them.

The 'make hate' issue should be important. NPCs should react sensibly to u, and if u have pissed them off, well, it shouldn't just be reflected in the opening comment, it should lead to its own dialogue tree. If you want something from them, you either have to skill your way to it or change their opinion of u!

NPCs should have morale checks and the ability to flee or surrender. Undead can flee when turned, so it can be done. Of course u then have to hunt them down, so we have to look into a leave combat thing. I think thats what the shitlist thing is for. What a great name ;-)

We also need some way of punishing characters who play outside of alignment, like fallen paladins. Lose a level maybe? Clerics particularly shouldn't be able to go against the interests of their gods.

Wednesday, September 07, 2005

My first game

Actually finishing (for the moment ;-)) my mod got me thinking about the first game I ever did. My post a while back about things I had started but not finished will give anyone who read it the entirely accurate impression that maybe I have started many games but not finished many. I'm sure I have no memory of the first computer game I ever planned or intended or dreamt up: I have been planning, drawing, scribbling away for many many years. I do remember the first time I heard of D&D, it was the reference in ET, with talk of portable holes and such. So I sat down (aged 11 or so) and decided to create my own version of D&D. I got it slightly wrong, on account of I thought it was a board game! (Yes yes i know it started out something like that but it was up to AD&D by those days). I still have that board I made tucked away somewhere, and see it every few years when I am questing for something buried in the back of a cupboard. "Cringeworthy" doesn't begin to describe it - I mean it had cards like monopoly! But I had fun making it. So if it was crap, well, meh I say, meh!

But that game never got finished (I discovered real D&D not long after) nor did pretty much any of the things I mispent my youth tinkering at. (Wish I had spent my time learning Latin instead). Indeed I am telling this story precisely because i have FINISHED my little mod! O there will be more to come - i STILL have to do those encounters for Cujo :-) - but this is done for now. Ahh, the value of putting yourself on the line and being accountable to a forum of folks you recently met :-D.

I say "pretty much" because there was ONE game I actually finished before this. One of the earliest I attempted actually (since they got bigger and more complex as time went on, it is not surprising they progressed less as well ;-)). It was written for the VZ-200, a computer released here in Oz some time between the Vic-20 and the C-64. It was built on the classic z-80 processor, had 8kb of Ram (upgradeable to 24) and was a lot of fun at the time, but blown out of the water by the C-64. But anyways, i learnt z-80 assembly language (though never really did anything with it) but mainly used BASIC, as was the style at the time.

And so I wrote my game.

Lode Runner.


Low res.

Thats right, just using the keyboard characters!

Of course in those days they took the keyboard characters seriously - remember the little symbols all over the C-64 keyboard? The VZ-200 had something similar. So I made Lode Runner, remember that glorious game? First game for memory that started as a computer game then went into the arcade, rather than visa versa. A true classic.

In my version, the ladders were 'H's, the player was an ampersand for memory, the baddies dollar signs (dang capitalists! :-P) and the boxes you had to collect were letter 'o's. I couldn't think how to do digging (or more to the point respawning the ground, since rewriting the whole map each 'round' would have been far too slow in BASIC) so I added jumping - you just jumped over the baddies! - and conveyor belts too :-). The baddies had independant 'scripts' so all 4 acted differently and chased you with different methods.

I wanted to show what it might have looked like, but this character set doesn't have the capacity! :-P

It was slow.

It was clunky.

It was UGLY.

But it was FUN!

And it was mine :-).

On to the next project!

Tuesday, September 06, 2005

Sound and visual FX and spawning from dialogue

Last night I added a little thing at Co8 for the Lareth fight. Absurdly simple, just:

ONE mp3 copied from elsewhere in the game
TWO lines in the dlg file
ONE addition to the py file (a chunk of script)

And now if you beat Lareth down to under 50% hp, when he stops the fight and tries to talk his way out of it, if you continue fighting he will call on Lolth for aid (fully vocalised call of course, like all my NPC mods :-D) and Lolth will send him some allies, complete with summoning effects when they arrive. The point of this is to compensate for the fact you are fighting him alone, having already killed off his boyos, whereas in the original module he would of course have come out and helped and you would have had to fight the squad of evil mercenaries and the higher-than-you-lvl cleric all at once (much tougher!)

Lets go through it step by step, that will teach us:

How to add visual effects
How to add sound effects
How to spawn new critters

Go and get the files here if you haven't already and we will look at them. There is only 3!

First the dlg file. The two lines I added are:

{700}{Lolth! Protect me!}{Lolth! Protect me!}{}{}{}{game.particles( 'sp-Curse Water', npc ); create_spiders(npc, pc)}
{701}{[attack]}{}{1}{}{0}{npc.attack( pc )}

You should be able to analyse these easily by now. First, Lareth calls out for Lolth, there is a couple things in the 'execute' field, and the second line is the PC response, which is common (1 Int), ends the dialogue (line 0) and initiates combat (npc.attack( pc )). O and i fiddled a few lines earlier to GET to line 700: namely, several lines that otherwise said something like:

{We fight now.}{}{1}{}{0}{npc.attack( pc )}

I changed to this:

{We fight now.}{}{1}{}{700}{}

Two changes, both obvious.

So, now Lareth calls on Lolth before the combat starts. What else happens? The first executable command is a glorious little thing, it allows us to add game particles. Thats what we call visual effects such as spell effects, monster visual stuff (not the models but things like the Balor's fire and glowing eyes, things like that) other things, anything that looks like a visual effect rather thna a model :-) I think they are sprites but I am not sure.

What are our options for this? Well, to see them all (or even add new ones) open the files partsys0.tab, partsys1.tab, partsys2.tab in the rules folder or in ToEE4.dat/rules if you have unpacked it (you HAVE to unpack these if you want to mod!! For instance, partsys2.tab is not in the rules folder of your normal game - only modified files are in there normally and we have to access a lot of files modding even though we may not actually modify them). Being tab files, open them in 'Proto Ed' like you would protos.tab (makes it much easier to view them). Now you can see all the visual effects :-) Of course, there is one for each spell.

If you don't want to look at them now, thats ok, we'll keep going. Suffice it to say, game.particles( 'sp-Curse Water', npc ) adds the visual effect (NOT the sound or anything, JUST the visual efffect) of casting that spell, so when Lareth calls out, a creepy looking red cross appears over him: you know he is doing more than just squealing ;-).

Notice you can just script these straight in the dlg executable thing? How cool is that?!?! Easy to add stuff.

Now... what do you suppose create_spiders(npc, pc) does? Hmmm...

Unfortunately, this requires a touch MORE than just the executable. This actually accesses something already defined in the .py file. So pop that file and lets find it. Go right down and you will see:

def create_spiders( attachee, triggerer ):
________spider1 = game.obj_create( 14397, location_from_axis (470L, 536L) )
________game.particles( "sp-summon monster I", spider1 )
________spider2 = game.obj_create( 14398, location_from_axis (481L, 536L) )
________game.particles( "sp-summon monster I", spider2 )
________spider3 = game.obj_create( 14620, location_from_axis (482L, 529L) )
________game.particles( "sp-summon monster I", spider3 )
________spider4 = game.obj_create( 14417, location_from_axis (529L, 544L) )
________spider5 = game.obj_create( 14417, location_from_axis (532L, 555L) )
________return RUN_DEFAULT

So here we define the create spiders thing. It is a variant of the scripts Calmert and Terjon use to call each other if you attack them in the church. I also used it to summon the Daemon at the end of Desperate Housewives.

As you can see it repeats a lot so we don't have to go over every line.

Firstly, lets compare:

create_spiders( attachee, triggerer ) with

create_spiders( npc , pc )

In the .py file we talk in the abstracts that define the event, in the .dlg we talk about the specific characters who trigger it. You'll get used to that. Certainly you will never see 'attachee' in the .dlg file, because the .py files are straight Python scripts that get compiled by the game when you access them (if they have not already). These are the identical .pyc files in the Scr folder. You may have some that don't have .pyc files, they haven't been accessed in your current game yet.

Now, the first line:

spider1 = game.obj_create( 14397, location_from_axis (470L, 536L) )

This both creates a spider, and defines it as a string called 'spider1' we can subsequently use in other scripts. :-) The specific spider is proto number 14397, a small fiendish spider from memory. Spider2 is a medium one, Spider3 a large one, and 4 & 5 are Black Widows for elsewhere in the game (a little surprise). So essentially we are saying, create object 14397 and call it 'spider1'. We could of course create anything and call it anything :-) We could create a Hezrou at this point and call it 'Fifi' if we have such a need.

location_from_axis is important, this says where to put it on the map, but how do we find that value? Well, when you want to add something, you go to the spot with your lead character (the leftmost one in the party lineup shown down the bottom of the screen).

Now, bring up the console (press [shift] and [~]). Type in

from utilities import * [hit enter]

This tells the game we are going to access the utilities.py file in the data/scr folder. Thats a file well worth looking at btw.

Next, we ask the game to give us the location we are at. So type in:

location_to_axis(game.party[0].location) [hit enter]

This is a little script added to the utilities.py file by the original ToEE creators for just such a moment. Agetian improved it so you only have to type loc, clever fellow! Later you can look for that improved utilities.py at Co8. For now, jot down the number that you see when you hit enter: that will be the location you will later put in your creating coordinates. Game.party[0] is your leftmost character (the 'leader'), then [1], [2] etc. And note we use location_TO_axis to find it but location_FROM_axis to use it. :-)

Next line:

game.particles( "sp-summon monster I", spider1 )

Well, we know what that does, don't we? It creates the particle effect of the summon monster spell, and the target for it is spider1. Compare this to the previous one we saw with the curse water effect, there the location for the spell effect was npc (ie on Lareth himself). You could also script in coordinates here if you wanted it to appear nearby for some reason, or put in game.party[0] if you wanted an effect to appear on your party leader for instance.


We've seen this one before too, it turns the spiders toward at least one member of the party , rather than facing the wall or something when they appear (that looks stupid). Might vary those later so they turn towards different member so the party, or we could even get them to turn towards the nearest, but not quite so easily ;-).

And THATS IT! The rest just spawns different spiders in different locations (different proto numbers and coordinates). Thats all :-) Spider4 and Spider5 spawn somewhere else in the moathouse, so we don't need to turn them to face the player or show particles. Only needs to be mentioned that these spiders are already flagged 'KOS' in their protos, so we don't have to do anything to make them attack, they will wade right in.

Now... what about sound effects? Time to do that.

For .dlg files, adding sound is easy. As it is, many characters (particularly PC followers, or at least potential ones like Lareth) come with vocal lines. So we just have to put those in.

Now, if we want, we can put in ANY mp3 file: a spell sound, a trumpet charge, geese squawking, anything. In this case, I simply added a vocal of Lareth actually yelling out "Lolth, protect me!" I could have added some spell effect sounds as well for the summoning, or layered them with a sound editing program or something, but I didn't!

Where did I get a sound of Lareth saying something? Well, if you pop 00060Lareth.dlg and scroll down to the bottom, you will see that he has a few combat sounds that really don't get used. I looked for a plea to Lolth, and sure enough, there is one at line {12080}.

So: I opened ToEE3.dat/sound/speech. In here you will find all the vocal lines of all the characters who have voice recordings (not all of the NPCs of course). They are divided into folders according to their .dlg/.py number, so Lareth is folder number 00060. For some reason, Ostler's stuff is just lying around loose in the speech folder. Messy damn programmers!

Open the folder. The mp3s are accessed by line number. So, for {12080} we need v12080_m.mp3. The 'm' means it is the male version of the line, this will be the default if the male and female versions are identical. If there is a seperate female version (saying 'hey lass' or something) it will be v12080_f.mp3 (but in this case there isn't).

We are adding line 700, so we simply copy this mp3, then go to our game folder and open data/sound/speech. We need a new folder, so we create one called 00060. Then we open it and go in, and paste that mp3 file. Then right click on it and rename it v700_m.mp3. Its that simple!

If you have my mod installed you can look elsewhere in the speech folder, everything here (at the time of writing) was added by me, because I am the only one who has done this sort of modding so far. You will find:

spell sounds fired from dialogue lines (00295, 00299 etc)
a bleating sheep (00298)
giggling kids (and a howling Cujo) (00228)
and lots of new dialogue made my blending existing rare and unused vocal tracks (00017, 00091, ooo97 etc).

Well, thats if for today! Now your npc.attack( pc ) episodes can have some cunning twists ;-)

Next tutorial is right here and is about getting your NPCs chatter to each other.

Saturday, September 03, 2005

Playful NPCs again

Well, I have made a couple discoveries.

There appears to be the 'pecking order' issue with the 'enter combat' voices, which long time readers will remember from the 'o no the leader is dead' voice. That's why Raimol was misfiring - take Zert out (you remember he tended to have a dominant vocal role?) and Raimol chirps up with the correct "into battle sir!" at the start of combat (as opposed to the wrong line at the start of his first round which he did before). Also, in some cases all the voices go off at once. That sux.

Worst of all, they only seem to fire ONCE. So you recruit a new NPC, like Fruella or Meleny, and they say this line once, then thats it.

Now, that is apparently due to me firing the line with san_enter_combat. I might change it to san_start_combat, which seems to fire at the start of each round, flag it then reset the flag in san_exit_combat. Thats a hassle, but if it gets it working properly, well and good.

Back to the grind! But certainly there will be no new voices in the next patch, alas :( Hmmm other than Zert: he seems to get it right each time :) and since there is no-one else there, there is no-one else to talk over him. I'll throw him in as an Easter Egg.

Friday, September 02, 2005

Playful NPCs, the ongoing saga

Well I have been back at work on the combat voices. Got Zert's "going into combat" thing working nicely, found Spugnoir and Furnok are missing that line (12057), found Raimol will show the line as floating text but say 12020 instead, and Elmo just ignores the whole thing [sigh]. The Raimol thing, which reminds me a little of the PC voices on map change getting mixed up, is yet one more bit of evidence that the voices were removed as broken rather than left unfinished or bugged. Since each has to be individually scripted, I will just find the ones that actually work and include those.

Doing it like this means the lines fire on the NPC's turn, so the "critical hit" and "miss" lines, which are meant to be said as responses to the PC scoring a hit (or missing) will probably largely have to be skipped, except where they make sense as refering to the NPC's own actions (eg "take that!").

Still working on the "I'm badly wounded, heal me" / "I'm badly wounded, I'm outta here" issue. Some new evidence has come to light that this may be overcomabable.

Thursday, September 01, 2005

Custom Soundtrack Tutorial

So, you've just made a whole new map or area or whatever following Jota's "how to make a new map" thread (its a bit more fiddly than he suggests, but it works :-)). And you want to add a custom soundtrack. Well I will tell you what I did step by step.

First I made my new map - we'll call it Frank's house, because that is what it is. It will occur in that empty house north of the brewery. I am using Jinnerth the tailor's house as a template: I may modify it graphically later but I doubt it, since I just don't have much skill with those arty programs (some may have noticed...).

So... my new map is in the maps folder, its called map1-int30-Frank. Its name in map_names.mes is {5120}{Frank's house} (note I went straight on to 5120 rather than leaving a gap like I normally do, beacuse I couldn't get it working any other way - what I meant when i said it was a bit more fiddly than first thought). I changed other files of course but they are irrelevant for the music.

Anyways, lets get our new music file and put it in. It is mp3, right? Mine is an old Chicago song, I swear it was the only mp3 I could find on my PC, and the good Lord alone knows how it got there (rolls eyes). Anyway, copy it and stick it in the folder data\sound\music. I named mine 'testingmusic.mp3'.

Now, lets look at the music files. These are schemelist.mes and schemeindex.mes. These are in ToEE2.dat.

Crack schemelist. Mine ends at 3100, future generations may go later.

Soooooo... I insert a couple new lines:


{3200}{music\testingmusic.mp3 /VOL:60 /loop}

Have a good look at this file: notice you can add ambient music too if u feel the need. For now, save, and stick this in the folder data\sound, right along side the music folder you just went into.

Now for schemeindex. I added the line:

{32}{Frank's house #3200}

This, as the rem stuff at the top suggests, points straight into the schemelist.mes file you just modified. Also notice I spelled 'Frank's house' IDENTICALLY to how it occurs in map_names.mes. Dunno if that is important, but lets not tempt fate. Save and stick this file in the sound folder next to the other one.

Finally, go back to the folder in maps (map1-int30-Frank). Open it up and go down the bottom to the mapinfo text file. I don't know if this is called or not or just for info but again, lets not tempt fate and be consistent.

Since I copied Jinnerth's house, it will say "soundscheme: 1, 0" - thats the basic sound u hear wandering around Hommlet.

As u may have noticed in schemelist.mes, it goes in hundreds. Ours is 3200, so of course we change the mapinfo thing to "soundscheme: 32, 0". Save.

Thats all there is to it - simple eh? Modify 3 files, stick in the music and your done.

So... I run the game, start down near the Renton's (seem to spend my whole game in that house), pop the console and enter (after the utilities bit) game.fade_and_teleport(0,0,0,5120,489,485) to go to my new map. Presto, there I am.

The Hommlet music fades out, and the painful strains of Chicago's 'you're my inspiration' or something begin to swell. Not too far though - the music is too soft. Obviously I can change that by fiddling the vol setting in schemelist.mes. But the main thing is, IT WORKS!