Jump to content


Photo

Can't we all just get along?


  • Please log in to reply
7 replies to this topic

#1 berelinde

berelinde

    Troublemaker

  • Modder
  • 4916 posts

Posted 15 December 2007 - 08:51 AM

Some modders are more concerned with compatibility than others. Some just want to tell their story and are not worried too much about how it plays with other mods. Others would like to make their mods work on any possible installation. This "tutorial" is for the latter group.

General Notes
  • Plan on patching, not overwriting. More on this later.
  • APPEND, rather than REPLACE
  • Beware of hijacking original material. More on this later, too.
  • It's really cool when added quests use new areas and new creatures, because that lets existing material play out as intended, and avoids overlap with other mods. This does take work and planning, though.
Dialogue
Most mods make some adjustment to existing game dialogue. This is as it should be, but there are a few ways to ensure that your mod will still "play nice" with other mods.
  • Use INTERJECT sparingly. INTERJECT_COPY_TRANS is fine, because the COPY_TRANS ensures that other mod content can play. INTERJECT derails the content entirely, sending it off in its own direction. Original content may not be seen, let alone contributions by other mods that might affect this dialogue. Sometimes, you may be tempted to do this, for a plot-essential reason, but you should still give the matter a lot of thought before you go there.

    Suppose I wanted to make it impossible for the PC to work for Bodhi, because Gavin, a cleric of Lathander, would have grave reservations about working for a vampire. I could accomplish this by using an INTERJECT or two, but I'd be railroading the PC into a major decision, and I'd be making huge chunks of other mods unavailable in the process. I would be better off using INTERJECT_COPY_TRANS to let him register his objections, or even forcing him to leave the party if the PC still decided to work for Bodhi. (I'm not planning on doing this, by the way.)
  • Use the same caution with REPLACE_STATE_TRIGGER and other REPLACE actions. There is usually some kind of workaround.
  • When using EXTEND_TOP and EXTEND_BOTTOM in dialogue files, it is considerate to COPY_TRANS back into the original state to allow other content to show.
  • Please use EXTEND_BOTTOM wherever possible in dialogue files, as opposed to EXTEND_TOP. Modders rely on original BioWare transition order for ADD_TRANS_ACTION and ADD_TRANS_TRIGGER functions, so using E_T is likely to break other mods.
  • Always use modder prefixes!
    Suppose I wanted to add a brand new character called Vai to BG1. I'd be in deep trouble if I didn't use a modder prefix, because the vai.cre I copied into the game would overwrite the existing Officer Vai. Now suppose I wanted to create a creature called Tashia. Again, I'd have some trouble, because there is already an older mod who uses tashia.cre as a creature code. There is nothing we can do about older mods, because that's how things were done then. But going forward, there is no reason not to use a modder prefix. Creatures, dialogue files, scripts, etc.: all need them.
  • Use modder prefixes in interjections! Every time an interjection is made, a global variable is added to the game. This variable is the same as the state label for the interjection. If I use AranJob as a state label for an interjection, I'll mess up the game. Better to use a prefix.
  • Be careful about state weighting with banter files. Because many mods use the banter file for scripted dialogue, a mis-assigned state weight might cause some oddness. More on that in a minute, during the great B/J debate, but for now, when you add unscripted banter to a BioWare NPC, you are better off not assigning a state weight. Yes, your banters will play after all the original material, but at least it won't cause any of the NPCs to develop a sudden case of chatterbox.
  • Any mod that allows the player to skip chunks of the game is probably going to be incompatible with some other mod. Chloe spawns in Chateau Irenicus, so using DungeonBeGone will prevent you from picking her up. This does not mean that you should not play with Chloe or DungeonBeGone, nor that you should not write mods that allow the player to skip some of the more tedious aspects of the game. It just means that you should be considerate about how you do it. For example, in DungeonBeGone, you don't have to talk to Jasper, nor do you have to accept his help. In the Ust Natha Accelerator in Zyraen's Miscellany, you don't have to go do the pit fights before going to Solaufein. Both of these mods provide shortcuts in a compatibility-friendly fashion.
Script
Please do not copy already-compiled scripts into the override. You're going to have to write it anyway before you compile it, so you might as well write it as a BAF and let WeiDU compile it during installation.

And some more things to think about:
  • Do not use a True() trigger outside a cutscene. Including them in area scripts, BioWare NPC scripts, or other game scripts will prevent material added after them from showing up.
  • EXTEND_TOP vs. EXTEND_BOTTOM... check it out first. Look at the script in question to see if it already includes a True() trigger or an OnCreation() trigger. Many do. If the script includes a True() trigger, you should EXTEND_TOP. Otherwise, EXTEND_BOTTOM. If you do need to EXTEND_TOP, please do it in a way that will not create problems in the original script. Use efficient scripting, and make sure you close your check variable, so that the script will only fire once. If the script contains an OnCreation() trigger, you need to read up on the use of Continue(). It is outside the scope of this tutorial to talk about it here, but in general, if you are extending the top of an area script, use Continue().
  • Be very, very careful about what you add to the game scripts, baldur.bcs and baldur25.bcs. There will be times when this is unavoidable, but if possible, consider using NPC scripts or area scripts instead. If your script contains InParty(), it can go in an NPC script. If you simply must add to a game script, you must do so considerately. Keep it short, keep it clean, and keep it efficient.

    This would be all right to add:
    IF
    Global("BAidanDiagott","GLOBAL",1)
    PartyHasItem("B!AMACE")
    Global("B!AidanHasMace","GLOBAL",0)
    THEN
    RESPONSE #100
    SetGlobal("BAidanDiagott","GLOBAL",2)
    SetGlobal("B!AidanDelayTalk","GLOBAL",1)
    SetGlobal("B!AidanHasMace","GLOBAL",1)
    END

    This would NOT (crossing it out, just to reinforce the idea of not using it):
    IF
    OR(18)
    AreaCheck("AR0021") //City Gates - Crooked Crane 1st floor
    AreaCheck("AR0022") //City Gates - Crooked Crane 2nd floor
    AreaCheck("AR0313") //Docks - Sea's Bounty 1st floor
    AreaCheck("AR0314") //Docks - Sea's Bounty 2nd floor
    AreaCheck("AR0406") //Slums - Copper Coronet
    AreaCheck("AR0509") //Bridge - Five Flagons 1st floor
    AreaCheck("AR0510") //Bridge - Five Flagons theater
    AreaCheck("AR0511") //Bridge - Five Flagons 2nd floor
    AreaCheck("AR0513") //Bridge - Calbor's Inn 1st floor
    AreaCheck("AR0514") //Bridge - Calbor's Inn 2nd floor
    AreaCheck("AR0514") //Bridge - Calbor's Inn 3rd floor
    AreaCheck("AR0522") //Bridge - Five Flagons 1st floor (stronghold)
    AreaCheck("AR0523") //Bridge - Five Flagons theater (stronghold)
    AreaCheck("AR0704") //Waukeen's Promenade - Mithrest Inn
    AreaCheck("AR0709") //Waukeen's Promenade - Den of the Seven Vales
    AreaCheck("AR1105") //Umar Hills - Imnesvale Inn
    AreaCheck("AR1602") //Brynnlaw - Brynnlaw Inn
    AreaCheck("AR2010") //Trademeet - Vytori's Pub
    Global("BAidanDiagott","GLOBAL",1)
    PartyHasItem("B!AMACE")
    Global("B!AidanHasMace","GLOBAL",0)
    THEN
    RESPONSE #100
    SetGlobal("BAidanDiagott","GLOBAL",2)
    SetGlobal("B!AidanDelayTalk","GLOBAL",1)
    SetGlobal("B!AidanHasMace","GLOBAL",1)
    END
Getting it into the game
Most of this is related to considerations for Mac users and for folks who want Mega installs.
  • Don't use \ in your tp2. It makes life tough for Mac users. As per the bigg, this issue has been addressed.
  • Linux is case sensitive, so you should label all your files in lowe-case. If you are saying COMPILE ~mymod/dialogue/lovetalks.d~, then the mod folder should be named mymod, the dialogue subfolder should be titled dialogue, and the D itself should be titled lovetalks.d. WeiDU has been adapted to convert to lower-case on the fly, though, so you could COPY_EXISTING ~sw1h01.itm~, COPY_EXISTING ~Sw1H01.itm~, COPY_EXISTING ~SW1H01.ITM~ or whatever.
  • The songlist in BGT installations fills up pretty fast. Your mod might have trouble if you've decided to add your music to the songlist. You might be better off using a different method of getting music into your mod, like copying mymusic to the override, and then using

    PlaySong(0)
    PlaySound("mymusic")

    If you really feel strongly about allowing non-Mega folks to listen to your music, you could detect for BGT, one of the key mods of a Mega, and only install the music, and the version of the script that calls it, on installations that do not contain it. This would involve creating two versions of the script, though, one that includes the PlaySong("mysong") and one that includes PlaySong(0). Of course you could be very clever and use cross-platform variables for this with EVALUATE_BUFFER, but that is the subject of another tutorial.
  • Kits. NPC-only kits are no problem. You can add as many of them as you like. But when you make a kit available to the PC as well, that might cause problems on mega installs, some of which are already maxed out for kits. There are workarounds for this, as well. You can make two versions of the kit, one of which is NPC-only, and then offer the player the choice of whether or not to install the custom kit. If the player does install the custom kit, install the NPC CRE with the PC-available version. If the player decides not to install the custom kit, install the NPC CRE with the NPC-only version.
  • When using COPY_EXISTING(_REGEXP) to copy game files with the tp2, always include BUT_ONLY_IF_IT CHANGES. When APPENDing 2da, always use UNLESS file.
  • Patch rather than overwrite. If I was writing a mod for a neutral evil Jaheira that used a half-orc avatar, I'd patch her alignment change and avatar, rather than just replacing her CRE. Any field you can view in NI can be altered by patching. All you need is the hex offset. For example, suppose I did want to change Jaheira's alignment. I'd fire up NI, look up the hex offset for alignment and animation, and then stick the following in my tp2:
    COPY_EXISTING_REGEXP GLOB ~^jahei.*\.cre$~ ~override~
    WRITE_BYTE 0x27b 35 //alignment neutral evil
    WRITE_SHORT 0x28 24853 //FIGHTER_FEMALE_HALFORC
    BUT_ONLY_IF_IT_CHANGES

    This can be done for spells, and other things, too, but it takes more homework, and more testing.
The great B/J debate.
It is entirely a matter of personal preference where you put your scripted banter. Some folks put it in the B file, and use Interact() to call it. Others use the J, and use StartDialogueNoSet() to call it. Historically, modders have used the B.

I like to put all scripted dialogue in the J file as opposed to the B file, and use StartDialogueNoSet() to call it. The reason for this is simple: state weighting is less complicated, and crossmod is greatly simplified. If ever you need to add anything to the J after the PID is compiled, no need to worry about state weights: just stick a WEIGHT #-1 after the IF for each conditional state, and you have nothing to worry about.

But not everyone does it this way. Suppose, for a moment, that I decide to use the B file for Gavin's scripted dialogue.

I install Kelsey, the Flirt Pack, the Banter Pack, Xan, Iylos, Gavin, and Crossmod Banter Pack. The first five mods all have scripted banter in the B. Now suppose I have decided to include both scripted and unscripted crossmod banter in Gavin's B file.

Now, suppose I wanted to have have Kelsey/Gavin crossmod, and have unscripted ToB banters between them, but that I didn't want to have them appear in game dead last. I would need to add a state weight that will put them ahead of some of Kelsey's already compiled unscripted banter, but after his scripted banter. I would decompile bj#kel25.dlg, and find out that the ending weight for the last state in the scripted portion of the mod is 25. So, I would go ahead and weight the banter with a WEIGHT #27, which will put it ahead of many original Kelsey banters. OK... except for one small problem: Xan and Iylos went and added scripted banter to Kelsey's B, which means that now, state weight #27 happens to fall before some of the Xan/Kelsey material and all of the Iylos/Kelsey material. So, when the banter engine accesses the banter file for an Interact() in Iylos, it's going to have all the unscripted banters file in rapid succession before it gets to the scripted banter added by Iylos. Iylos will get the bug report, but it's really Gavin's fault. So, I can't weight unscripted Gavin/Kelsey crossmod, so it will just have to show up dead last, after all other banters. Bummer. There isn't much I can do about this, since I'm not responsible for Iylos', Kelsey's, or Xan's coding.

The whole thing is a heck of a lot simpler if modders put all scripted banter in the J file instead. That way, all the modder needs to do is add a WEIGHT #-1 to get scripted banter ahead of any possible PID, and everything is cool. When somebody wants to add weighted banters to Gavin for the CBP, it's easier, too. A sensible state weight for the banter going into ~BB!Gav25~, and it's all good.

But I admit that this doesn't matter much unless you want crossmod.

Edited by berelinde, 23 December 2007 - 03:16 AM.

"Imagination is given to man to console him for what he is not; a sense of humor, for what he is." - Oscar Wilde

berelinde's mods
TolkienAcrossTheWater website
TolkienAcrossTheWater Forum


#2 the bigg

the bigg

    2083 is a prime number.

  • Modder
  • 3331 posts

Posted 15 December 2007 - 09:10 AM

Sorry, I'm too lazy to start a "comments" thread". Since you have GM powers, you can split this post if it can cause confusion :whistling:

Don't use \ in your tp2. It makes life tough for Mac users.

Not needed since about V187.

I believe that Mac and Linux are case sensitive, so make your file titles consistent with the tp2. If you are saying COMPILE ~mymod/dialogue/lovetalks.d~, then the mod folder should be named mymod, the dialogue subfolder should be titled dialogue, and the D itself should be titled lovetalks.d. WeiDU doesn't much care about case, though, so you could COPY_EXISTING ~sw1h01.itm~, COPY_EXISTING ~Sw1H01.itm~, COPY_EXISTING ~SW1H01.ITM~ or whatever.

No. Mac is case insensitive. Linux is case sensitive, and (since modders grew up on Windows and are inconsistent with file name case) everything is mapped on the fly to lowercase.
This means:
- no changes to tp2.
- all files in the mod archive have to be in lowercase.
- the .sh installation scripts must be changed, not only the files.

When COPYing files in the tp2, always include BUT_ONLY_IF_IT CHANGES. When APPENDing 2da, always use UNLESS file.

Unless a later mod does highly unusual stuff, B_O_I_I_C is only to save clutter and its absence shouldn't break anything. Also, fix COPY to COPY_EXISTING(_REGEXP). You definitively DON'T want B_O_I_I_C when copying a file from the mod folder to the override :)
APPEND/UNLESS is required, though, but I doubt.

Re the title: not when modders slap "INCOMPATIBLE WITH" tags to further their flame war agenda ;)

Italian users: help test the Stivan NPC!

Author or Co-Author: WeiDU - Widescreen - Generalized Biffing - Refinements - TB#Tweaks - IWD2Tweaks - TB#Characters - Traify Tool - Some mods that I won't mention in public
Maintainer: Semi-Multi Clerics - Nalia Mod - Nvidia Fix
Code dumps: Detect custom secondary types - Stutter Investigator

If possible, send diffs, translations and other contributions using Git.


#3 cmorgan

cmorgan
  • Modder
  • 2301 posts

Posted 15 December 2007 - 09:13 AM

Only one typo:

If you do need to EXTEND_TOP, please do it in a way that will [missing> not <missing] create problems in the original script.


way cool otherwise.
We should probably (I should probably) grab some time in January and link specific code examples clipped from RL mods to illustrate, so that snagging the hyperlink shows related code.



What the bigg said on COPY (I made that mistake, too) but I would argue that using B_O_I_I_C for everything else should really be considered important even if it isn't technically necessary. If someone is going for compatability, why refill the player's override, as they are probably going for a big install anyways :)

Edited by cmorgan, 15 December 2007 - 09:18 AM.


#4 berelinde

berelinde

    Troublemaker

  • Modder
  • 4916 posts

Posted 15 December 2007 - 09:23 AM

Thanks, guys! I'll leave these posts here, though, to keep the discussion together with the tutorial. :)

(And thanks for the corrections! I've included them above.)

Edited by berelinde, 15 December 2007 - 09:39 AM.

"Imagination is given to man to console him for what he is not; a sense of humor, for what he is." - Oscar Wilde

berelinde's mods
TolkienAcrossTheWater website
TolkienAcrossTheWater Forum


#5 Miss Sakaki

Miss Sakaki

    Modder

  • Modder
  • 505 posts

Posted 20 December 2007 - 04:45 AM

way cool otherwise.


Seconded! Thanks for doing this - it's great to have this kind of info in one place for reference.

#6 jastey

jastey
  • Administrator
  • 3219 posts

Posted 20 December 2007 - 03:08 PM

This is great! Thank you for writing it.

One remark: If possible, in dialogues EXTEND_TOP to add a respond should be avoided completely, as it could mess up A_T_T and A_T_A from other mods.

(When reading the title, I thought this was another thread about politics..)

Edited by jastey, 20 December 2007 - 03:09 PM.


#7 berelinde

berelinde

    Troublemaker

  • Modder
  • 4916 posts

Posted 23 December 2007 - 03:16 AM

Thank you Jastey! That is an important point I completely forgot! I've added it above.

"Imagination is given to man to console him for what he is not; a sense of humor, for what he is." - Oscar Wilde

berelinde's mods
TolkienAcrossTheWater website
TolkienAcrossTheWater Forum


#8 -Pakoh-

-Pakoh-
  • Guest

Posted 11 September 2008 - 02:07 PM

Thanks!

From a spanish.