xFirstNPC, xNextRef npc list loop is broken, please prove me

Post » Sun Oct 07, 2012 6:12 am

Hi,

Some of you may be aware that I and PeterBitt are working on a huge overhaul for Morrowind sound and music system: Morrowind Acoustic Overhaul (MAO). A huge part of this projject is sound randomization for Player, NPCs, and creatures. Recently we discovered a huge problem with attaching scripts into NPCs via MWSE xFirstNPC, xNextRef functions. There's got to be some kind of bug with MWSE NPC lists. In some cases when you change the cell xFirstNPC and xNextRef functions will skip NPCs (and creatures) within the cell player currently is. When you change cell the global script will be once again able to add script into that NPCs.

Please prove me worng and show me the error in scripts :wallbash:

MAO scripts contains hundreds lines of code so for testing purpose I stripped down all unnecessarry junk, optimization etc. and left only basic MWSE NPC list loop, so anyone could test it in game.

Global script, which loop through NPC MWSE list and start directed AO_MWSE_NPC script when neccesarry:
Spoiler
Begin AO_MWSE_GetRef    long lAIRef    long lTemp    float fDelay    set fDelay to ( fDelay + GetSecondsPassed )    if ( fDelay < 0.05 ) ; max 20 times per second (0.033 = 30)	    return    endif    set fDelay to 0    if ( MenuMode == 1 )	    return    elseif ( CellChanged == 1 )		    ; set lAIRef to 0 ; resetting reference doesn't fix problem	    MessageBox "CellChanged"	    return    endif    ifx ( lAIRef )	    setx lAIRef to xNextRef lAIRef    else	    setx lAIRef to xFirstNPC    endif    if ( lAIRef == 0 )		    ; MessageBox "xNextRef loop done. xFirstNPC will be triggered in the next frame."	    return    endif    setx lTemp to lAIRef->xRefType    if ( lTemp != 1598246990 ) ; not NPC	    return    endif    XSetRef lAIRef    if ( GetItemCount "AO_DummyTemp" > 0 ) ; script already attached	    return    endif    XSetRef lAIRef    if ( GetDistance Player > 2048 ) ; NPC is not close enough	    return    endif    XSetRef lAIRef    StartScript "AO_MWSE_NPC" ; this directed script attaches script to NPCEnd

This directed script attaches one of AO_MWSE_NPC_XX scripts into NPC:
Spoiler
Begin AO_MWSE_NPC    StopScript "AO_MWSE_NPC" ; this only needs to run for one frame    if ( ScriptRunning "AO_MWSE_NPC_01" == 0 )	    StartScript "AO_MWSE_NPC_01"    elseif ( ScriptRunning "AO_MWSE_NPC_02" == 0 )	    StartScript "AO_MWSE_NPC_02"    elseif ( ScriptRunning "AO_MWSE_NPC_03" == 0 )	    StartScript "AO_MWSE_NPC_03"    elseif ( ScriptRunning "AO_MWSE_NPC_04" == 0 )	    StartScript "AO_MWSE_NPC_04"    elseif ( ScriptRunning "AO_MWSE_NPC_05" == 0 )	    StartScript "AO_MWSE_NPC_05"    else	    return    endif    set AO_NPC_Count to ( AO_NPC_Count + 1 )	    ; MessageBox "DEBUG: Scrip attached. AO_NPC_Count = %0.f" AO_NPC_CountEnd

And this is the script that is attached to NPC. It adds AO_DummyTemp item into NPC inventory to let the AO_MWSE_GetRef script know that NPC has script already attached. For testing purpose it just shows MessageBox "Script is attached" when you activate NPC. In test esp that I've uploaded below there are 5 such scripts (01-05).
Spoiler
Begin AO_MWSE_NPC_01    short sDisable    short doOnce    if ( sDisable == 1 )	    set sDisable to 0	    set doOnce to 0	    if ( GetItemCount "AO_DummyTemp" > 0 )		    RemoveItem "AO_DummyTemp" 1	    endif	    set AO_NPC_Count to ( AO_NPC_Count - 1 )		    ; MessageBox "DEBUG: Script disabled. AO_NPC_Count = %0.f" AO_NPC_Count	    StopScript "AO_MWSE_NPC_01"	    return    endif    if ( doOnce == 0 )	    if ( GetItemCount "AO_DummyTemp" == 0 )		    AddItem "AO_DummyTemp" 1	    endif	    set doOnce to 1    endif    if ( OnActivate )	    MessageBox "Script is attached"	    Activate    endif    if ( GetDistance Player > 2048 )	    set sDisable to 1	    return    endif    if ( GetHealth <= 1 )	    set sDisable to 1	    return    endifEnd

If you can find an error within the scripts that would explain why excatly AO_MWSE_GetRef script can't see some NPCs, please let me know.

---------------------------------

Here is the plugin with the above scripts if anyone would be kind enough to test it in game: http://www.sendspace.com/file/osmz9w

Here is how you can recreate the problem:
1. open console and type "coc Balmora" (coc usage doesn't change anything - if you travel to Balmora by Slit Strited other part of the city will have silent NPCs due to different cell you start in).
2. go to the roof of Council Club in Balmora without leaving the town (you should see only one cellchanged messagege when you travel there in a direct line). Council Club is located near slit strider port but be sure to not change the cell, which ends nearby. Talk to Tedryn Brenur or Dranas Dradas who are standing there - none of them will have script attached (you won't see MessageBox when you talk to them). They don't have AO_DummyTemp item in thier inventory so they can't be skipped by the script this way (you can check it in console with GetItemCount). Unless you are using MCA there are free script slots too (type "show AO_NPC_Count" in console to be sure).
3. Leave the Balmora using the nearest gate (CellChanged) and come back - both Tedryn Brenur and Dranas Dradas will have now script attached.

It looks like MWSE is sometimes using wrong NPC lists or... dunno :sadvaultboy:
User avatar
Gemma Flanagan
 
Posts: 3432
Joined: Sun Aug 13, 2006 6:34 pm

Return to III - Morrowind