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

3 Comments:

At 1:00 am, Anonymous just a bum said...

u kno wut? is ther sum progrem 2 fix mistaeks liek spellin or grammer otomaticaly? so it close all brackits otomaticaly n shit liek dat. n if itz relly smarts it evn knos wut kind of brackit it shoulds b!
u should rite such [progrem homie it woulds help u a ton. or get sum1 smarts 2 rite it 4 u haha! couls b liek sum nu featurz in dat TOE worldz editar progrem calld -=TEH ULTOMATE SCRIPT COMPILAR! CLIX HEAR!!1=- so u just clix it in menu n its don.

 
At 3:08 am, Blogger ShiningTed said...

Yeah i think there is, probably a few of them, proper assemblers and such: anything with in-built debugging stuff. Debugging software goes straight for open-ended brackets.

Personally I just use Notepad.

 
At 12:19 pm, Anonymous gaming mathematician said...

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

Those are operators. The operands are the things on either side of them. For example, in "game.party_size() <= 4", "<=" is the operator, and "4" and "game.party_size()" (or, rather, the value returned by that function) are the operands. It's the same thing as parts of speech in a sentence written in a human language: the operator (is less than or equal to) is a verb, game party size is the subject and 4 is the object. In another way of looking at it, is_less_than(a, b) is a binary function which takes two arguments; the operands are the things operated upon by the operator.

 

Post a Comment

<< Home