Jump to content

Troubleshooting a Stutter or Constant PID


cmorgan

Recommended Posts

Troubleshooting a Stutter or Constant PID (Player-Initiated-Dialog, or "Force Click")

 

(If you are a player who just wants the troubleshooter and how to use it, skip to post #2!)

 

The problem

 

PC: Hey, I'd like to talk to you about...

KORGAN: Shut up.

PC: Hey, I'd like to talk to you about...

KORGAN: Shut up.

PC: Hey, I'd like to talk to you about...

KORGAN: Shut up.

PC: Hey, I'd like to talk to you about...

KORGAN: Shut up.

PC: Hey, I'd like to talk to you about...

KORGAN: Look, kid, this damned well better be a script stutter, 'cause if you are just clicking on me to initiate PID, I'm gona stick this sword where the sun don't shine, capish?

 

It happens. Your NPC looks nice, and installs fine. But suddenly, out of nowhere, he starts constantly coming up to the PC and trying to initiate conversation. Or he keeps bugging another NPC, over and over again, without actually saying anything, bogging down your game. Or he stops every few seconds, fidgets as if about to say something, and then moves on. Games slow down. Bleh.

 

This is usually caused by a script block being triggered, but not being able to close. The ultimate "get the annoying stutter" would be to have a block that looks like this in your mod:

 

IF
 InParty(Myself)
THEN RESPONSE #100
 StartDialogNoSet(Player1)
END

 

This block always fires if the dude running the script is in the party. And with no conditions, it runs every script cycle. So you get the ultimate Noober/Neeber character, and lots of hate mail. Your NPC starts initiating conversations with PC non-stop, for as long as his script is active, everywhere... the ultimate kid sister following you around, tugging on your sleeve every second or so.

 

Common reasons that this might happen in your mod:

  • Typos in timer or var. The block might be triggering on "my_variable" but then closing on "my_vraiable"
  • Differences in variable scope. The block might be triggering on "myvar","LOCALS" and trying to close on "myvar","GLOBAL"
  • Another mod interfering. Mod B may have come along and put something that changes either script or dialog or DV or something that results in your code not working as tested. Which can lead us to...
  • Weighting. The block may be evaluating true, but can't resolve because the dialog or action that it is trying to launch is being blocked by another. A simple example in a dialog file, setting up for a script stutter:
     
     
    IF ~InParty("cmorgan")~ THEN BEGIN heya
     SAY ~[CMORGAN] I am conditioned broadly, so I will always evaluate true when the script tries to look for what it wants. I take priority each and every time, no matter how hard you try to clear me. Nothing that weights below me will ever be called by the script - I run instead.~
     IF ~~ THEN EXIT
    END
    
    IF ~Global("myvar","GLOBAL",1)~ THEN BEGIN what_the_script_is_looking_for
     SAY ~[CMORGAN] I am conditioned narrowly, so I will only evaluate true when a very specific global is set. The script looking for me starts at the top of the dialog and works downwards until it finds me... unless it finds something else that is true, and fires it instead.~
     IF ~~ THEN DO ~SetGlobal("myvar","GLOBAL",2)~ EXIT
    END


In this configuration, if you wanted to turn the narrowly-conditioned block into a showstopper, just leave off the DO, and voila - that line, even though narrowly conditioned, just became an "always true" when the variable is set to 1. And anything downstream of it will never play.

 

reminder -

- scripts evaluate top to bottom, stopping when something evaluates true, and jumping back to the top again (unless you add Continue() )

- dialog files are called by scripts or the "hidden" scripts inside the engine, and evaluate top down... except when you set up WEIGHT that changes the evaluation order, making a talk rise to the top of the evaluation order (or lowering it, whichever you set - you can manipulate the thing to top or bottom of the stack of everything that has been installed before it. After that, other mods can do the same, but the newcomer can change things; you can't).

- dialog TRANSITIONS are evaluated BOTTOM UP. So, while the state is evaluated from the top of the file down, once a state is called, the transitions are checked from the bottom card in the deck to the top one, and the first one is taken - or in the case of REPLY, every statement that returns true is displayed.

 

 

The Challenge

On your own install, this is a PITA to troubleshoot, but it is eminently do-able. You have full access to your own unique install, you have NI, DLTCEP, WeiDU, text editors, ways of searching all of your project at once for matching variables, and the knowledge of your own code.

 

But.

 

When it hits the field, all of this changes. Because every modded install is slightly different, you can't just grab a .bcs or .dlg file from a player experiencing a problem and decompile it yourself on your own install and have it help. You can do some of the investigation with tools like Vlasák's Variable Checker from The Black Wyrm's Lair, which features savegame compares, or manual comparisons with WeiDu and NI and DLTCEP - in this case, tools like CamDawg's Debugger is not as useful because we are not dealing with possible file corruption or problem areas/assignments, we are dealing strictly with script evaluation. In this day and age of BWP and BiG World installs, troubleshooting stutters and weighting issues and such becomes an impossible task, because it is 99% likely that even if you replicated the install as closely as possible, it would never get troubleshot, for a very simple reason - limited modding time, and huge amounts of time installing and uninstalling to replicate.

 

Even more importantly, all of these tools have the disadvantage of working from a snapshot instead of real-time, on the actual install having the problem. So, either have a player .zip up between 2 and 5 GB of their entire game folder so you have their entire install and pay for the upload/download, troubleshooting on their actual game, or ...

 

 

The Solution

 

The Bigg came up with a reasonable way of checking to see what script block is firing but failing to resolve itself mod to find the problem. Berelinde adapted it and used it to troubleshoot Gavin. And now I have shamelessly copied and pasted and modified it to work with Aran.

 

Basically, all it does is take whatever in-game .bcs files you point it to, and look for the RESPONSE section, number each one, and set up a DisplayStringHead() on PC. in the old days, we did this manulaly, which was horrible. It was even more horrible when it was just manually. Nothing like numbering and identifying each and every block and dialog, then having to go back and remove all that before giving it out... Now, through WeiDU-foo, you can have a user experiencing the problem go back to an earlier save, install a mod, run through to the problem, and report the number. Eventually, someone will whip up a good way of decompiling the resulting file and sending you the info in text, but for now, the safest thing to do is have the player read off which block of which .bcs is firing in the dialog window, and have them decompile and send you the problem file. Then have them uninstall the mod. Good news - it can go on the very end of the install with no problems!

 

Here is the base code:

 

 

BACKUP ~aran_troubleshoot/backup~
AUTHOR ~berelinde~

BEGIN ~Troubleshooting Aran's stutter with Shamelessly Re-Appropriated Code from Gavin~

COPY_EXISTING 	~c-aran.bcs~ ~override~ // be sure to change the file names to point to the relevant ones
			~c-arand.bcs~  ~override~
			~c-ar01.bcs~  ~override~
			~baldur.bcs~ ~override~ // use either baldur.bcs or baldur25.bcs whether you're in SoA or in ToB.
			~player1d.bcs~  ~override~
			~c-arn25.bcs~ ~override~
			~c-arn25d.bcs~ ~override~
SET x = 0 - 1
DECOMPILE_BCS_TO_BAF
	REPLACE_EVALUATE ~\(RESPONSE #[0-9]+\)~ BEGIN
					x += 1
			END "\1
	ActionOverride(Player1,DisplayString(Myself,~Running block %x% of %SOURCE_RES%.BCS~))"
COMPILE_BAF_TO_BCS

 

So, to copy it and use it yourself, you just need to identify what scripts you touch and swap them in the .tp2.

Link to comment

The Troubleshooter

 

The Bigg came up with a reasonable way of checking to see what script block is firing but failing to resolve itself mod to find the problem. Berelinde adapted it and used it to troubleshoot Gavin. And now I have shamelessly copied and pasted and modified it to work with Aran. His version is available for download here: aranw_troubleshoot.rar .

 

How To Use It

 

 

Download it, and install it AFTER ARAN. This is important. It works by reading in your game's scripts and numbering them. If he isn't installed, then there are no scripts to number. In fact, after you have finished getting the data, you want to uninstall it... but we will get to that later!

 

Now, start up your game, and look at the dialog box as you approach the problem you are looking to report on.

You will see numerous script blocks displayed in the dialogue window. They will look something like

PC: Running block 24 of baldur.bcs

PC: Running block 5 of aerie.bcs

PC: Running block 76 of c-aran.bcs

PC: Running block 8 of anomen.bcs

 

Eventually, one will repeat and keep repeating. When you find that block, please decompile the script that it references, so the problem can be solved. For example, if right before the stutter or repeatedly in the dialog box each time Aran tries to initiate PID over and over again, you see

Running block 827 of c-aran.bcs

 

then you would be looking to decompile a copy of c-aran.bcs and send it to me.

 

Here is a sample screenshot of the troubleshooter in action:

 

troubleshooter1.png

 

In this example, there is no problem. But we know that the last block fired, Block 3 of c-ar01.BCS, triggered properly, causing a byplay between Erika and Toran to fire. When we cross-reference this with the decompiled c-ar01.bcs, sure enough, you see

IF
AreaCheckObject("C-AR01",Player1)
RealGlobalTimerExpired("c-scenery","GLOBAL")
Global("c-smalltalk","C-AR01",0)
THEN
RESPONSE #20
	ActionOverride(Player1,DisplayString(Myself,85662)) // Running block 2 of c-ar01.BCS
	SetGlobal("c-smalltalk","C-AR01",1)
	RealSetGlobalTimer("c-scenery","GLOBAL",TWELVE_MINUTES)
RESPONSE #20
	ActionOverride(Player1,DisplayString(Myself,85663)) // Running block 3 of c-ar01.BCS
	RealSetGlobalTimer("c-scenery","GLOBAL",TWELVE_MINUTES)
	SetGlobal("c-smalltalk","C-AR01",1)
	Wait(2)
	DisplayStringHead("C-AW01W1",85233) // I heard you, I heard you.
	Wait(2)
	DisplayStringHead("C-TORAN",85234) // No rush. Just letting you know I need more ale.
RESPONSE #20
	ActionOverride(Player1,DisplayString(Myself,85664)) // Running block 4 of c-ar01.BCS
	RealSetGlobalTimer("c-scenery","GLOBAL",TWELVE_MINUTES)
	SetGlobal("c-smalltalk","C-AR01",1)
	Wait(2)
	DisplayStringHead("C-AW01W1",85235) // Orrin, whose orders are these?
	Wait(2)
	DisplayStringHead("C-AW01TK",24958) // I have no idea.
	Wait(2)
	DisplayStringHead("C-AW01W1",85236) // Oh.
	Wait(2)
END

 

If there had been a problem, then the stutter would happen and the "Running block 3 of c-ar01.BCS" would happen again and again in the dialog box, and we could immediately search for the malfunctioning block.

 

But what about those other things in there, where we got reports of things that ran but nothing was happening? Well, lots of script stuff does not fire off dialog. In those cases, I can look up c-aran.bcs and 188 and 193, and find that those blocks have fired successfully and closed up shop. On this install, 188 is the block initializing friendtalks and setting timers for the embarrasing talks. 193 is the romance match check, setting initial timers for the romance materials. Both of those run in the background. (If you are a modder, search around DavidW's stuff for ways of not forcing the engine to continually re-evaluate your script blocks with things that have to be constantly checked on in the background. He sets up small timers that unload some of the needless 'every script cycle' checks from constant evaluation. It is not necessary to check to see if the party has picked up an item your NPC is going to comment on every single script cycle. Every few seconds or so is infinitely preferable - or even longer!).

 

OK, so how do I decompile the script?

 

Courtesy of Bereline, here's how to decompile scripts and dialogue files using WeiDU:

  1. Download a version of WeiDU to your game directory, like you do with mods. Get it here. OR, rename an existing setup-mymod.exe "WeiDU.exe" and skip to step 5.
  2. Extract (unzip) the archive, and then open it.
  3. Inside the WeiDU folder, you will find a file called WeiDU.exe. Right-click on it and select COPY.
  4. Go back to your game directory and PASTE WeiDU.exe there.
  5. Open a command prompt (DOS window). If you are using Windows XP, you can do this by clicking on the Start button and typing cmd into the box next to "run". That will open a command prompt. If you are using Vista, type cmd into the box next to "Search". You should see several Help topics. One of them will be "Open Command Prompt?" Choose that one, and it will open a command prompt.
  6. Go to the new window and navigate to your game installation directory. If you used the default installation, you would type in
    cd c:\program files\black isle\bgii - soa\
    then hit enter
  7. Notice how the prompt now shows the path to your BG2 installation? Good, that's what you want.
  8. You're ready to decompile files!
  9. To decompile a file, type in weidu foo.ext, where foo is the file you want to decompile and .ext is the extension type. Dialogue files use the extension .dlg, script files use the extension .bcs. So, if you wanted to decompile the Graveyard District area script, you would type in
    weidu ar0800.bcs
  10. WeiDU will create the decompiled file in your game directory, alongside all your mods. Dialogue files will use the extension .d, script files will use the extension .baf
  11. Put all decompiled scripts into an archive and email them to the mod author.

You could also open the darned thing in NI or DLTCEP, and copy/paste into your favorite text editor.

 

OK, What Now?

 

As a player, UNINSTALL THE TROUBLESHOOTER! It will just copy back the files it changed, so you can proceed however you want. But you do not need these stupid little reports running all the time. And the order of blocks might change on the update when the modder fixes the problem, so this is a one-shot deal - install troubleshooter, check, decompile resulting problem file, send to modder to fix, uninstall troubleshooter, and play your game, serene in the knowledge that you have done a Good Thing for the universe and for the modder, and hopefully the modder in question will be able to figure out what is messed up.

 

As a modder, now the fun starts.

 

The block in question is what is happening right before the problem. So, now you get to figure out whether it is a simple missed global, whether there is a problem with another mod messing with stuff, whether it is a typo, whether you forgot to set up the weighting and your PID is evaluated before your talk, etc., etc. Welcome to the most frustrating and fascinating part of coding mods - debugging!

Link to comment
The Troubleshooter

 

 

[*] Go to the new window and navigate to your game installation directory. If you used the default installation, you would type in

cd c:\program files\black isle\bgii - soa

 

Add a \ after soa. Wouldn't work without that on my version of XP. For those unsure of my meaning, it will look like this:

 

cd c:\program files\black isle\bgii - soa\

then hit enter

Link to comment

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...