Jump to content

Creating Ghost NPCs in Oblivion


FiendishGhoul

Recommended Posts

Hello,

 

I am currently working on a mod, player housing, and it occurred to me that I'd like to feature a brief appearance from a named ghost NPC in one of the cells.

 

I am familiar with the AbGhostNPC spell in CS, and somewhat familiar with creating NPCs in CS, but I am hitting a brick wall on plotting how to implement the ghost NPC practically.

 

What I'd like for him to do is, when a PC 1st enters a specific cell, the ghost NPC will be standing in the middle of the room facing PC. He will perform a brief motion, ie, one of the bowing conversation idles, or something like that, and then fade from view. Ultimately, he will then teleport to a dummy cell that I've created for another purpose, where he will spend the rest of the game with no further purpose.

 

Sounds simple and probably is, provided one is more familiar with NPCs than I apparently am. I am also thinking that this will require either a quest or a script of both in tandem, and sadly neither is my strong suit really.

 

I have briefly thumbed through The Forlorn Watchman quest and its associated data in CS, but it's quite a bit more involved than what I am thinking and I am having trouble sorting out the salient info that would pertain to what I'm attempting to do. Also, I thought about looking for something similar in a mod here on the Nexus, so that I could shamelessly cannibalize it study its example, but nothing's jumping out at me.

 

If anyone reading this has any experience with making ghost NPCs and would like to volunteer some notes, or, failing that, if anyone knows of an example of this sort of behavior in another mod that I might be able to at least study and possibly replicate, I'd really appreciate it.

 

Thanks in advance!

Link to comment
Share on other sites

Warning: Oblivion NPC AI is stubborn and you'll spend hours making them do extremely simple things! With that out of the way, here's how I would do it. You'll need at least one script that can be run in GameMode - either an object script (perhaps on the ghost itself) or a quest script with fQuestDelay time set to a very low value.

 

Create a custom animation and token:

Create some sort of token with a unique name - modifying a generic gold ring is a popular way to do this. You'll be using this token as a condition: the NPC will only use your custom idle animation if it has this token in its inventory.

Now create a custom Idle Animation in GamePlay > Idle Animations - you can re-use an existing .kf file for this. The condition for the custom animation is the presence of that token that you created earlier (GetItemCount [token] > 0).

 

In the CS:

In the CS, place the ghost exactly where you want facing the direction you want it to. Make sure there is a pathgrid node on that exact spot. Package should be Travel to Editor location with a radius of 0. This (hopefully) ensure the NPC will stay still. I'd use SetGhost 1 command in the ghost's OnLoad block to ensure that it can't be killed.

 

As the player approaches:

Method 1: Use a GameMode Script to determine the distance to the player and trigger the next step once the player is within range (you can use a short within the script, or a SetStage command).

Method 2: Use a Trigger Zone to trigger the next step. Make sure you disable the trigger zone as soon as it's been triggered once otherwise it will keep triggering repeatedly!

 

Once triggered:

Add the token the the ghost's inventory, and then use the PickIdle command. Start a timer for 5 seconds or however long you want.

 

Once the timer has expired:

Simply disable the NPC and it will disappear from view. No need to move it elsewhere.

 

And that my friend is why modders who use a lot of NPCs usually have hair loss problems. ;)

Link to comment
Share on other sites

Warning: Oblivion NPC AI is stubborn and you'll spend hours making them do extremely simple things! With that out of the way, here's how I would do it. You'll need at least one script that can be run in GameMode - either an object script (perhaps on the ghost itself) or a quest script with fQuestDelay time set to a very low value.

 

Create a custom animation and token:

Create some sort of token with a unique name - modifying a generic gold ring is a popular way to do this. You'll be using this token as a condition: the NPC will only use your custom idle animation if it has this token in its inventory.

Now create a custom Idle Animation in GamePlay > Idle Animations - you can re-use an existing .kf file for this. The condition for the custom animation is the presence of that token that you created earlier (GetItemCount [token] > 0).

 

In the CS:

In the CS, place the ghost exactly where you want facing the direction you want it to. Make sure there is a pathgrid node on that exact spot. Package should be Travel to Editor location with a radius of 0. This (hopefully) ensure the NPC will stay still. I'd use SetGhost 1 command in the ghost's OnLoad block to ensure that it can't be killed.

 

As the player approaches:

Method 1: Use a GameMode Script to determine the distance to the player and trigger the next step once the player is within range (you can use a short within the script, or a SetStage command).

Method 2: Use a Trigger Zone to trigger the next step. Make sure you disable the trigger zone as soon as it's been triggered once otherwise it will keep triggering repeatedly!

 

Once triggered:

Add the token the the ghost's inventory, and then use the PickIdle command. Start a timer for 5 seconds or however long you want.

 

Once the timer has expired:

Simply disable the NPC and it will disappear from view. No need to move it elsewhere.

 

And that my friend is why modders who use a lot of NPCs usually have hair loss problems. ;)

 

Thanks very much for your reply!

 

I'll be reading over this (a few times) and diving back in.

 

Thanks again!

Link to comment
Share on other sites

  • 3 weeks later...

Ok, well, if Lanceor is reading this or if anyone else reading this is interested, I did manage, using Lanceor's suggestions, to produce the following script:

 

 

scn HackdirtCabinGhostScript

float timer

short doOnce

begin gamemode
     HackdirtCabinGhostREF.SetGhost 1
     HackdirtCabinGhostREF.AddItem HackdirtCabinToken 1
     HackdirtCabinGhostREF.PickIdle

    if ( doOnce )         
        return            
    elseif( timer > 5 )    
        set doOnce to 1
        HackdirtCabinGhostREF.Disable  
    else
        set timer to timer + getSecondsPassed
    endif
end

 

 

Which does generally result in the effect I originally set out to achieve.

 

However, because I can never just be satisfied with things, I decided that the effect achieved was kind of shabby, so I set about making something a little more involved.

 

Which brings me to:

 

 

Scn HackdirtCabinGhostScript

Float Timer

Short doOnce

Begin OnActivate   
  If isActionRef player == 1      
     Messagebox "Though the shade utters not a word, you sense some measure of acceptance in his mournful eyes. You will likely not see him again."
     Set doOnce to 1
     Set Timer to 5
  EndIf
End

Begin GameMode
     HackdirtCabinGhostREF.SetGhost 1
     HackdirtCabinGhostREF.AddItem HackdirtCabinToken 1
     HackdirtCabinGhostREF.PickIdle
  If ( doOnce )
     Return   
  ElseIf ( doOnce == 1 )
     HackdirtCabinGhostREF.AddItem HackdirtCabinToken02 1
     HackdirtCabinGhostREF.PickIdle      
  EndIf

  If ( Timer > 0 )
     Set Timer to Timer - getSecondsPassed
  ElseIf ( Timer == 0 ) && ( doOnce == 1 ) 
     HackdirtCabinGhostREF.Disable
  EndIf
End

 

 

In a nutshell, this script is a dismal failure. The only thing that works at this point is the messagebox. The animations are conditional (animation 1 should only work if there are 0 token 2s and >0 token 1s, animation 2 should only work if there are >0 token 2s and >0 token 1s) but neither they nor the timer seems to be working.

 

If anyone has any further suggestions or, even better, an working example script (a man can hope!), I would love to read them.

Edited by FiendishGhoul
Link to comment
Share on other sites

Ok, well, if Lanceor is reading this or if anyone else reading this is interested, I did manage, using Lanceor's suggestions, to produce the following script:

 

 

scn HackdirtCabinGhostScript

float timer

short doOnce

begin gamemode
     HackdirtCabinGhostREF.SetGhost 1
     HackdirtCabinGhostREF.AddItem HackdirtCabinToken 1
     HackdirtCabinGhostREF.PickIdle

	if ( doOnce ) 		
		return            
	elseif( timer > 5 )    
		set doOnce to 1
		HackdirtCabinGhostREF.Disable  
	else
		set timer to timer + getSecondsPassed
	endif
end

 

 

Which does generally result in the effect I originally set out to achieve.

 

However, because I can never just be satisfied with things, I decided that the effect achieved was kind of shabby, so I set about making something a little more involved.

 

Which brings me to:

 

 

Scn HackdirtCabinGhostScript

Float Timer

Short doOnce

Begin OnActivate   
  If isActionRef player == 1      
     Messagebox "Though the shade utters not a word, you sense some measure of acceptance in his mournful eyes. You will likely not see him again."
     Set doOnce to 1
     Set Timer to 5
  EndIf
End

Begin GameMode
     HackdirtCabinGhostREF.SetGhost 1
     HackdirtCabinGhostREF.AddItem HackdirtCabinToken 1
     HackdirtCabinGhostREF.PickIdle
  If ( doOnce )
     Return   
  ElseIf ( doOnce == 1 )
     HackdirtCabinGhostREF.AddItem HackdirtCabinToken02 1
     HackdirtCabinGhostREF.PickIdle      
  EndIf

  If ( Timer > 0 )
     Set Timer to Timer - getSecondsPassed
  ElseIf ( Timer == 0 ) && ( doOnce == 1 ) 
     HackdirtCabinGhostREF.Disable
  EndIf
End

 

 

In a nutshell, this script is a dismal failure. The only thing that works at this point is the messagebox. The animations are conditional (animation 1 should only work if there are 0 token 2s and >0 token 1s, animation 2 should only work if there are >0 token 2s and >0 token 1s) but neither they nor the timer seems to be working.

 

If anyone has any further suggestions or, even better, an working example script (a man can hope!), I would love to read them.

 

Your script is not getting past this (Return'ing) once the OnActivate has occured, since it sets doOnce to 1 -- 'If ( doOnce )' == 'If ( doOnce == 1 )':

  If ( doOnce )
     Return   
  ElseIf ( doOnce == 1 )

 

Try:

  If ( doOnce == 0)
  	Return   
  Else
  	HackdirtCabinGhostREF.AddItem HackdirtCabinToken02 1
  	HackdirtCabinGhostREF.PickIdle      
  EndIf

 

Also global (quest) scripts update every 5 seconds by default, and your timer is only 5 seconds, so you want to force the script to update every frame:

float fQuestDelayTime

 

And at the start of the GameMode block:

If fQuestDelayTime != 0.01
Set fQuestDelayTime To 0.01
EndIf

Link to comment
Share on other sites

  • Recently Browsing   0 members

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