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, December 27, 2005

Common Modding Mistakes

Today I am gonna list a few common modding mistakes (hey look, that matches the title. What a coinkidink). These are things I tend to do over and over and over, and until I started doing them regularly enough to pick them up quickly, they can be so tiny u don't notice them even when bug-hunting and they can ruin an entire day. There is also some helpful stuff about finding and overcoming them.

Wrong Brackets: Having { instead of ( or vice versa is a common, frustrating screw-up.

To find it, open your dlg file in Proto-Ed. It will assign columns according to pairings of {}. If one of these is open or mistyped or something, it will show up pretty clearly. Elaborate programs like NotePad + also come in handy at such moments.

Open ( brackets is a common enough thing in .py files, and a single open bracket can take down the whole file. If you try adding a heartbeat or combat script or something and the whole .py file goes down, won't even open the dialogue, this is probably your culprit. Look where they are paired: something like

_________if (((game.global_flags[368] == 1) or (game.global_flags[313] == 1)) and ( attachee.reaction_get( game.party[0] ) >= 0 )):

Another common punctuation problem can be forgetting the colon (:) at the end of an 'if' script.

Wrong Operands: Is that the right word? Who cares. I mean the use of mathematical symbols, = >= < != etc.

If you are doing a quest or something, it is common enough to do the 'trigger quest / set flag' bit and the 'effect it has' bit simultaneously. So in dlg you have:

{150}{So you'll do my quest?}{So you'll do my quest?}{}{}{}{game.quests[101].state = qs_accepted}

And in another dlg u have:

{152}{I'm on a quest, I'll need you to answer some questions.}{}{8}{game.quests[101].state == qs_accepted}{250}{}

Simple enough. And to minimise screw-ups, you make liberal use of copy-paste rather than risk typos.

Fine. But what do you forget?

You forget the change in operands between an executing function and a comparative one: namely, the fact that above in our first example we have ONE equals sign becuase we are setting the qs_accepted bit, and in the other we have TWO because we are asking if it is exclusively equal. (For anyone who is curious - yes you can use >=, <= etc in such circumstances but I am not entirely sure what consitutes 'greater than' what. It is probably obvious, 'unknown' is less than 'mentioned' is less than 'accepted' is less than 'completed' is less than 'botched', but I am not sure and so don't bother using it.)

Anyways, if your quest stuff, or anything involving an executable or comparative function ain't working, thats something to check.

Wrong Args: Here's a right PITA! This can occur where u have already defined one of the objects in a script, then u use something abstract like 'triggerer'. Or, forgetting to put args in at all. Lemme show u an example.

def san_heartbeat( attachee, triggerer ):
________for obj in game.obj_list_vicinity(attachee.location,OLC_PC):
________________if game.global_flags[3] == 0:
________________________attachee.turn_towards(obj)
________________________game.global_flags[3] = 1
________________________if (attachee.has_met( obj )):
________________________________obj.begin_dialog( attachee, 100 )
________________________else:
________________________________obj.begin_dialog( attachee, 1 )
________return RUN_DEFAULT

Simple enough script, (makes the Tower Watch yell at you when u first go into the Bailiff's tower. Flag 3 is reset by the first heartbeat, so he only does it once each time). But didn't I have a ginormous amount of grief trying to get this to work! Because I had written the common-enough triggerer.begin_dialog( attachee, 1 ) instead of obj.begin_dialog( attachee, 1 ). Bastard! I even got caught doing this with attachee.float_line(945,triggerer) at one point, and I swear I have used that line more than anyone else in ToEE's history (including the developers!)

Also, don't forget to add args if u need them. I have had many issues trying to get made-up scripts to fire because I forgot that little caveat. So, the following scripts (which I or others made) work fine:

def amii_dies():
________game.quests[101].state = qs_botched
________return RUN_DEFAULT

def room_no_longer_available():
________game.global_vars[4] = 0
________game.sleep_status_update()
________return RUN_DEFAULT

def can_sleep():
________if (game.leader.map == 5030): # inn
________________if (game.global_vars[4] >= 1):
________________________return SLEEP_SAFE
________________return SLEEP_PASS_TIME_ONLY
________elif ((game.leader.map == 5094) or (game.leader.map == 5134)): # Forest, Graveyard
________________return SLEEP_DANGEROUS
________elif game.leader.map == 5123: # Caravan
________________return SLEEP_SAFE
________return SLEEP_PASS_TIME_ONLY

The last one is, well, not complicated, but its got a bit in it (and will doubtless be huge by the time we have finished KotB). But none of these need arguments, they can all function independantly.

But throw in something like:

def chatter_box(attachee, triggerer):
________attachee.float_line(900,triggerer)
________return RUN_DEFAULT

and u better have that 'attachee, triggerer' bit in there, and in the script that calls it too! (Ok I know this shows what a n00b I am at Python, but then u r too or u wouldn't be reading this ;-)) This was the reason my time-thingy wasn't working, btw: all the ones I checked had no args, and when I started having trouble I reduced the script to the simplest possible thing to get it to work, but it wouldn't because I still needed args for it.

Wrong Conditional: Speaking of n00b mistakes, I may be wasting my breath mentioning this, as I may be the only person who does this! But I tend to use skill checks more than any other sort of checks in dialogue commands, and I sometimes get pc.skill_level_get() and pc.stat_level_get() mixed up even though there are a lot more stats to check than skills! For instance, if I had a dollar for every time I've errantly written:

pc.skill_level_get( stat_deity ) == ##

then Yvy and I wouldn't have to worry about getting a mortgage ;-) You'll find a few screw-ups like this in the Tenant's dlg in DH, (to be rectified with the next release that comes out, whatever it happens to be) and a few in the Watchmen's dialogue regarding being a follower of Kord. Annoying error. Another one like it is setting a flag using game.global_flags[#] = 1 then using game.global_vars[#] == 1 for ur conditional, again, just silly but it happens (well it does to me! Did it yesterday yet again!)

To help overcome this, I've attached something at the end. But first...

Wrong Name: By 'name' I am refering to the name and id columns in the protos (22 & 23 in Proto-Ed). Sometimes col 22 is missing. Sometimes it is just a copy of the proto-id. Sometimes they are all different. Its a pain. If you have trouble getting an item transfer or such to work, try putting the proto number in the id column, or using the number that is there if it differs. See THIS thread for more.

Bug-hunting:

What is it Hicks?
I'm Hudson sir, he's Hicks.
What is it private?
Will this be a stand-up fight or a bug hunt?


Ahhh, what a movie... anyways, if you have a bug in your .py file, and it is not killing the whole thing (ie it works to a point), one way to track it is with the ever handy command:

game.particles( "sp-summon monster II", game.party[0] )

Think of it like a 'break' command. It will cause the daemon-summoning pillar of flame to descend on your lead character when it executes. Hence, if you have a broken script and you are not sure if it is not being called due to args issues or if it is not working due to internal issues (or whatever), then put this line at the start. If in game u see the spell effect, u know the script at least is being called (even if it is not working). If u don't see it, then the problem is earlier than that (had this idea myself, but it also occurs in some really old threads, Zhuge or Dulcaion or someone recommends it to Liv for memory).

Ok, enough possible problems! There are plenty of them. But here is something useful (and you all have my permission to copy this into a .txt file and keep it on your desktop, like I do).

Some of these problems, like mixing up executables and conditionals, occur due to copy-pasting, and copy-pasting is done as a way of avoiding spelling errors (anyone who has spent a day going nuts because u didn't notice you mis-spelt 'neutral' will know what I mean).

Anyways, we can't eradicate the need to copy-paste, but we can eradicate the amount of subsequent typing (and possibility of typos) and we can put everything together in one place, so you don't have to go hunting through various scripts to find the right one to copy. Of course, Phalzyr's Dialogue/Python Commands thread does that, but it mixes a lot of stuff you need with even more that, generally, you don't, and the stuff you need often only has one possible parameter out of many that might all be useful (and that might all be potentially mis-spelled!)

So what I have done is accumulate a bunch of common little commands, all culled directly from the game so we know they work (hmmm we ARE talking about ToEE here... lemme rephrase that: commands that I have used in game successfully so we know they work!) So here they are! As I said, I keep a .txt doc on the desktop with these, opens instantly and everything easy to find. Feel free to copy it. Hope you all like it, and if anyone thinks of anything that is missing (or, heaven forefend, finds an error in here!) lemme know. I use these for KotB and it seems to run ok so far.

pc.skill_level_get(npc, skill_bluff) >= 7
pc.skill_level_get(npc, skill_diplomacy) >= 4
pc.skill_level_get(npc, skill_sense_motive) >= 8
pc.skill_level_get(npc, skill_intimidate) >= 4
pc.skill_level_get(npc, skill_gather_information) >= 6

pc.stat_level_get( stat_gender ) == gender_male or gender_female

game.quests[].state = qs_accepted
game.quests[].state = qs_completed
game.quests[].state = qs_botched
game.quests[].state = qs_mentioned
game.quests[].state = qs_unknown

game.party_alignment == NEUTRAL_EVIL or game.party_alignment == CHAOTIC_EVIL or game.party_alignment == CHAOTIC_NEUTRAL or game.party_alignment == LAWFUL_EVIL (chaotics)

game.party_alignment == LAWFUL_GOOD or game.party_alignment == NEUTRAL_GOOD or game.party_alignment == CHAOTIC_GOOD or game.party_alignment == TRUE_NEUTRAL or game.party_alignment == LAWFUL_NEUTRAL (non-chaotics)

game.party_alignment == LAWFUL_GOOD or game.party_alignment == NEUTRAL_GOOD or game.party_alignment == CHAOTIC_GOOD or game.party_alignment == LAWFUL_NEUTRAL (goodies)

pc.stat_level_get(stat_alignment) == LAWFUL_GOOD
pc.stat_level_get(stat_alignment) == NEUTRAL_GOOD
pc.stat_level_get(stat_alignment) == CHAOTIC_GOOD
pc.stat_level_get(stat_alignment) == TRUE_NEUTRAL
pc.stat_level_get(stat_alignment) == LAWFUL_NEUTRAL
pc.stat_level_get(stat_alignment) == CHAOTIC_NEUTRAL
pc.stat_level_get(stat_alignment) == LAWFUL_EVIL
pc.stat_level_get(stat_alignment) == NEUTRAL_EVIL
pc.stat_level_get(stat_alignment) == CHAOTIC_EVIL

create_item_in_inventory(4400,pc)

pc.stat_level_get( stat_deity ) == 1 // Boccob
pc.stat_level_get( stat_deity ) == 2 // Corellon Larethian
pc.stat_level_get( stat_deity ) == 3 // Ehlonna
pc.stat_level_get( stat_deity ) == 4 // Erythnul
pc.stat_level_get( stat_deity ) == 5 // Fharlanghn
pc.stat_level_get( stat_deity ) == 6 // Garl Glittergold
pc.stat_level_get( stat_deity ) == 7 // Gruumsh
pc.stat_level_get( stat_deity ) == 8 // Heironeous
pc.stat_level_get( stat_deity ) == 9 // Hextor
pc.stat_level_get( stat_deity ) == 10 // Kord
pc.stat_level_get( stat_deity ) == 11 // Moradin
pc.stat_level_get( stat_deity ) == 12 // Nerull
pc.stat_level_get( stat_deity ) == 13 // Obad-Hai
pc.stat_level_get( stat_deity ) == 14 // Olidammara
pc.stat_level_get( stat_deity ) == 15 // Pelor
pc.stat_level_get( stat_deity ) == 16 // St. Cuthbert
pc.stat_level_get( stat_deity ) == 17 // Vecna
pc.stat_level_get( stat_deity ) == 18 // Wee Jas
pc.stat_level_get( stat_deity ) == 19 // Yondalla
pc.stat_level_get( stat_deity ) == 20 // Old Faith
pc.stat_level_get( stat_deity ) == 21 // Zuggtmoy
pc.stat_level_get( stat_deity ) == 22 // Iuz
pc.stat_level_get( stat_deity ) == 23 // Lolth
pc.stat_level_get( stat_deity ) == 24 // Procan
pc.stat_level_get( stat_deity ) == 25 // Norebo
pc.stat_level_get( stat_deity ) == 26 // Pyremius
pc.stat_level_get( stat_deity ) == 27 // Ralishaz

pc.stat_level_get(stat_level_cleric) >= 1
pc.stat_level_get(stat_level_paladin) >= 1
pc.stat_level_get(stat_level_ranger) >= 1
pc.stat_level_get(stat_level_druid) >= 1
pc.stat_level_get(stat_level_barbarian) >= 1
pc.stat_level_get(stat_level_monk) >= 1
pc.stat_level_get(stat_level_rogue) >= 1
pc.stat_level_get(stat_level_bard) >= 1
pc.stat_level_get(stat_level_wizard) >= 1
pc.stat_level_get(stat_level_sorcerer) >= 1

pc.stat_level_get(stat_race) == race_orc
pc.stat_level_get(stat_race) == race_halfling
pc.stat_level_get(stat_race) == race_human
pc.stat_level_get(stat_race) == race_elf
pc.stat_level_get(stat_race) == race_dwarf
pc.stat_level_get(stat_race) == race_gnome

pc.stat_level_get(stat_strength) >= 10
pc.stat_level_get(stat_dexterity) >= 10
pc.stat_level_get(stat_Intelligence) >= 10
pc.stat_level_get(stat_Wisdom) >= 10
pc.stat_level_get(stat_Charisma) >= 10
pc.stat_level_get(stat_Constitution) >= 10

pc.money_get() >= 100
pc.money_adj(-100)

is_daytime() != 1

game.global_vars[] = game.global_vars[] + 1
game.global_flags[] == 1

game.party_size() <= 4 and pc.follower_atmax() != 1
group_average_level( game.leader ) >= 2

Saturday, December 24, 2005

Breakthrough

Well, I finally figured out the time thing so that NPCs wait a few seconds before delivering their lines. For those who don't remember what I am going on about, it was in THIS thread: we had the NPC follower Two Swords set to make a comment when u changed maps, just some party chatter to add life to the NPC experience. BUT since the party always assumed the same formation when you change maps, and the chatter went by nearest party member, she would always be saying the same thing to the same person. Plus, if there was more than one NPC in the party, you ran the risk of them talking over the top of each other. So I wanted to script it as an added time event happening a few seconds after the map change, with the time interval staggered for each NPC: this meant that depending how the party ran around in that time, you could have different members spoken to each time (ie different comments), and no talking over each other. BUT I couldn't get the timed events to work.

Well now I have :-D. Longer blog detailing how I did it, coming soon. For now I just want to gloat ;-)

Wednesday, December 21, 2005

HOLIDAYS!

Woohoooo! Finished work this morning, off for TWO AND A HALF WEEKS! Then night-shifts for a holiday camp thing, which will hopefully be a week of late-night modding on the laptop (and kiddies sleeping thru and not disturbing me. Might up their meds to make sure... its good to be a doctor!) So hopefully lots of modding time coming up. Not today though, going back to bed, my sleep patterns have just sucked the last few days. Might be the heat.

Saw Harry Potter - the Goblin's on Fire! yesterday. Took my ma grocery shopping - not happy about that, a few days out from Xmas - but the local shops were practically empty! In the middle of the day too... bizarre. So I figured I could go to the movies in peace, and I did 8^) Not a bad job with such a humungous book, indeed really enjoyed it. I heard Sirius Black was left out, but Gary Oldman still did some voice work I am glad to say, so by the look of things he will be back for #5 where he plays such an important role. They did the Quidditch World Cup as a RenFaire, I kept looking around for Allyx ;-) Really sweating for #5.

Hey anyone else having issues with Atari switching over to VBulletin? At least, it LOOKS like they switched over to VBulletin... I can't log in anymore - not that I remember my password. But when I hit 'I forget my password" and stick in my Yahoo mail, it says that mail account is banned! WTF did I do? Seriously, Volourn gets to be a troll and I get banned, call that justice!?!??!

Tuesday, December 13, 2005

Ten Things You Never Knew About ToEE

That is, in the CRPG of course, not the module ;^) You probably did know some of these.

1) There are no paladins in the game. (Thrommel doesn't count, however you look at it he was never an LG paladin).

2) There are no followers of Heironeous in the game. (There ARE followers of Ralishaz, Procan and Pyremius!)

3) The author of the keylog was a smartass. If you look at Keys in your logbook, they say things like:

Belsornig, the high priest of the Water Temple, probably didn't give you this key.
Kelno, the high priest of the Air Temple, always kept this key on his person.
Commander Feldrin of the temple forces used to have this key. Now it's yours.
This key belongs to Supreme Commander Hedrack, High Priest and Most Honorable Emissary of Iuz Himself. You are a thief.


4) There are cow portraits in the innards of the game. There are no cows.

5) If you talk to Riana while polymorphed, she says, "Mary, keep your animals in your own room, please!"

6) If an athiest character encounters a moment when he (or she) should invoke a divine name (ie yell "By Corellan's tights!" or something), he or she yells, "I rule!"

7) Half-elves and half-orcs are referred to as 'mudbloods' by some angry townsfolk (seriously!!!) Dwarves who are shrunken by spell are referred to as kobolds.

8) Jaroo's bear is named "Mobley".

9) The numbers that appear next to dialogue options - 1. 2. 3. etc - can easily be changed to letters, or words, or whatever. In fact, I may, for no reason at all, slip a change into a mod one day. Drow numerals, anyone?

10) Troika's site STILL refers to job opportunities with their company :-(

Well, enough shenanigans. On to business.

Update

Or, how to waste an entire afternoon's modding due to a stupid mistake.

Firstly, I found the bailiff's dlg for KotB. I scrawled a few lines for when the party encounter him in the pub, then lost it. I searched EVERYWHERE for the damn thing, ran searches on my computers (both OSes and my lappie) and even went to werk and checked the PC there. Nothing. Finally remembered where it was - I had LITERALLY scrawled it in a book. Thats a load off my relief, as we say here! So I can get on with KotB modding which had ground to a bit of a halt while I hunted around (for the last several days).

In the mean time, I have been working on the remake of the Thrommel encounter. Thats where my wasted afternoon comes in. I made a Wampyr, but I couldn't .mob him in! Well, not so he worked... Firstly, he always showed up nekkid (O good lord it is St Cuthbert all over again...) All I wanted him to do was wear some black gear like in the module, but he wouldn't. Finally I forced the issue by assigning the gear a slot number, that did the trick. BUT he wouldn't appear properly, just stood there with 'damage: 0' under the name instead of 'unscathed' in green, wouldn't fight back, wouldn't die if u whacked him. Not that there is meant to be a fight with him of course, but I need to be able to damage him to make him lie down! There's a little bit of info for you - OCF_SLEEPING seems to do jack, and OCF_PARALYZED just freezes the charcacter, won't make him tumble over (think an NPC when u enter a room, just before it crashes - I have seen lots of them for one reason or another ;-)). So how to make him lie down? Well, thump him down under 0hp, thinks I. But he's gotta be able to take damage to make it happen, and my .mobbed wampyr wouldn't. [sigh] Wouldn't even enter combat mode, just stood there getting whacked. WOULD enter dialogue though. Bizarre.

Why do I want him to lie down? To lay him on that slab in the room of course, as he is meant to. Anyways, after several hours fiddling I think "To heck with this, I'm gonna spawn him of Thrommel's heartbeat". I do this, works nicely (he shows up clothed ;-)) and I also add a thing to OF_OFF Thrommel while I'm at it (he can show up later after you've dealt with the whole vampire thing). Thanks to Allyx for finding that! Thrommel already has switch-off flags in his .mob for when he gives you a reward, so I just hit the switch a la Mickey and its all done.

That actually worked too - whodda thunk it? - BUT I couldn't get the little fella onto the damn slab. See, I had made the slab passable in the sector thingy, but it had clipping so when he stood inside it, only his top half showed up, the rest was clipped! For those of you who don't know, this '3d' clipping thing is a mystery to us modders - it is apparently done in the same proprietary format the 3d models are done in, and we don't have access to that (being proprietary, of course). So there is nothing I can do about it. In .mob mode, I was offseting on the z access to raise him above the clipped bit, but you can't do that in the proto so you can't spawn-by-script. Another couple hours of fiddling presented no solutions to this.

So then I tried .mobbing again, couldn't figure out why it suddenly shouldn't work. Still no luck, despite remaking new .mobs from scratch.

Finally after a very frustrating afternoon, I wandered off to the shops to return DVDs and have a coffee to clear my head (had a 'free coffee' card thing all filled up, so I got on of the most expensive coffees they had, mocha caramelatte, covered in whipped cream and caramel stuff and chocolate stuff too. VERY nice, and free!)

Then it hits me.

I was starting on the same map when I introduced the .mob, instead of coming in from a new map. I was starting outside that sector, but still on the same map, so some of the savegame stuff must have been interfering with it. Stupid, just stupid, I should know better.

Came home, loaded up the map (sans mobs), leaving all the doors between the stairs and the room already picked (theres about 2), moongated downstairs, saved, quit, added the .mobs, cleared the cache (God bless Agetian, Dulcaion, Sapricon etc for Toffee!) and tried again.

There was the Wampyr. UNSCATHED. WORKING.

FINALLY.

But now its time for church, so have to wait til I get back to see if I can knock the bugger over. *Best John Malkovich voice* "Die you f***ing vampire!"

Sunday, December 11, 2005

Whats going on

For anyone who is wondering what is going on with the lack of posts at this site, I have simply been a bit caught up with various things. I have several modding things that need my attention (none of which is progressing very fast, but all are being picked away at) including redoing the Thrommel encounter (the vampire is at least in the protos.tab now - not that there actually IS an encounter with a vampire, but he has to be there if you take my meaning), an overhaul of some voices for the Voice Pack and ongoing KotB stuff of course (just added a couple more character .mobs into it). And some stuff for Cujo that has been hanging over my head forever - haiyoolah! O yeah and trying to fix the damn node bug.

Also there is a bunch of real life stuff going including much overtime at work (we have been changing buildings and the place is a mess) and a need to basically decide the direction of my life sometime in the next week, apply for a couple jobs, enrol for a diploma, and generally get my shit together before my upcoming nuptials c. next August.

But I do have a tutorial thing lying around waiting for me to finish it, damn handly little gadget it is too. So should release that sometime in the next couple days.

Tuesday, December 06, 2005

KotB starter pack

Did I mention the new KotB starter pack is out? Go get it!

KotB starter pack redux