Jump to content

Script crashing on NPCs, but not the player.


PAPVAFS11

Recommended Posts

My goal with this script is to allow a one-size-fits-all leveled list to work for both Capital Wasteland and Mojave Wasteland NPCs in Tale of Two Wastelands without either using incorrect weapons for the locale. Here's the script I'm using:

scn CYCWCChineseAssaultRifleWasterSCRIPT



ref rHolder



begin GameMode



    if (rHolder != GetContainer) ; Set the reference so we can add the item.

        set rHolder to GetContainer

    else

        if (rHolder != 0) ; Ensure the item is in a container before proceeding.

            if (bInDCWasteland == 1) || (GetRandomPercent == 1)

                rHolder.AddItem WithAmmoChineseAssaultRifleNPC 1 1

            else

                rHolder.AddItem WithAmmoAssaultRifleNPC 1 1

            endif

        endif

        RemoveMe ; Remove the misc item as it's done its job.

    endif



End

This runs on a misc item that, as the code might suggest, is intended to transform into the appropriate weapon. When added to the player or an NPC via the AddItem command, this works just fine and it functions correctly. I've ensured that leveled lists inside the script exist and I know that the global exists, so I don't think they're the problems.

 

On NPCs that are just spawning into the world, however (in my case, a test NPC spawned with the PlaceAtMe command), the game locks up and has to be ended with the task manager. I've tried adding a timer to the script to give the NPC time to load in, but that only delayed the crash until after the timer expired.

 

This script has to function with an item that has to be part of a leveled list. If it can't, it's entirely useless and I'll be forced to juggle even more leveled lists for the Mojave (which is a problem as I've got way too many for just D.C.).

 

What am I doing wrong and how can I fix it?

Link to comment
Share on other sites

I can't guarantee it'll work any better, but have you tried it using getself instead of getcontainer for the container ref and/ or rholder.removeitem (scripted object's baseid) 1 instead of removeme?

 

If nothing else it's worth trying because some functions can get a little picky with how they work in certain situations.

Edited by uhmattbravo
Link to comment
Share on other sites

Unfortunately, that didn't work. While it didn't crash, the script failed to do anything with GetSelf in place of GetContainer. Still, it was worth a shot and I appreciate the suggestion.

 

Is there anyone out there who might've run into the same problem?

Link to comment
Share on other sites

I may have spoken too soon. I narrowed down the crash to the RemoveMe call and did some juggling with it. While RemoveMe crashed no matter what I did, using rHolder.RemoveItem in a very particular way worked perfectly.

 

What I did was add in a boolean check in a particular way to ensure that the GameMode block runs to completion at least once before the item is removed. This gives the item time to "settle" before it's removed and seems to be preventing the crash. Here's the code I'm using now:

 

scn CYCWCChineseAssaultRifleWasterSCRIPT

; Converts weapons dependent on the wasteland it's in.

ref rHolder
int bGiven

begin GameMode

    if (bGiven == 1)
        rHolder.RemoveItem CYCWCChineseAssaultRifleWaster 1 1
    endif

    if (rHolder != GetContainer)
        set rHolder to GetContainer
    else
        if (rHolder != 0) && (bGiven == 0)
            if (bInDCWasteland == 1) || (GetRandomPercent == 1)
                rHolder.AddItem WithAmmoChineseAssaultRifleNPC 1 1
            else
                rHolder.AddItem WithAmmoAssaultRifleNPC 1 1
            endif
            set bGiven to 1
        endif
    endif

End
I don't think this is quite perfect as it could result in a situation where multiples of this item could only convert to one weapon (or so my often-fallible logic leads me to believe). Regardless, it's working now, so I'm going to run with it.

 

If anything else comes up, I'll report again.

Link to comment
Share on other sites

Yes, it's important to give the game world a chance to catch up and not try to do everything in one frame.
I think Getself returns zero on placeAtMe actors, so Getcontainer is what to use. I have always had to skip a frame before doing any equipment stuff to the actor. The removeMe in the same frame as adding the misc item is also a CTD magnet :smile:
I don't know if it still applies, but at one time there was a game bug where the script could loop again after removeMe, and therefore run the command again, causing a CTD. So I always guard that function so there's no way it could run again.
scn CYCWCChineseAssaultRifleWasterSCRIPT






ref rHolder
short iStage




begin GameMode



if (rHolder) ; Set the reference so we can add the item. (skip if already set)
else

     set rHolder to GetContainer
     set iStage to 1

endif


if (rHolder) ; Ensure the item is in a container before proceeding.
     if (iStage == 1)
          set iStage to 2 ;Do nothing. Just skip a frame
     elseif (iStage == 2)

          if (bInDCWasteland == 1) || (GetRandomPercent == 1)
               rHolder.AddItem WithAmmoChineseAssaultRifleNPC 1 1
          else
               rHolder.AddItem WithAmmoAssaultRifleNPC 1 1
          endif
          set iStage to 3 ;skip another frame
     elseif (iStage == 3)
          set iStage to 4 ;make sure there's no chance removeme will run twice
          RemoveMe ; Remove the misc item as it's done its job.
     endif
endif


End

 

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...