Jump to content

Get the soul size of the target of a spell


Recommended Posts

I would like to display the size of the soul when I (the PC) cast any soultrap spell.

 

Here is the only thing I can think of:

 

Create an event for the spellcast:

Begin GameMode
    if GetGameRestarted
       PlayerRef.SetEventHandler "OnSpellCast", FnOnSpellCast
    endif
End

In the function, display the soul size of the target:

scn FnOnSpellCast

ref refActor
ref refSpell
short iSoulSize

Begin Function { refActor, refSpell }
    if MagicItemHasEffect STRP, refSpell
      set refActor to player.GetCrosshairRef
      if refActor
          if refActor.IsActor
              set iSoulSize to GetActorSoulLevel refActor
              if iSoulSize == 5
                 Message "Target soul level is GRAND" 4
              else
                  if refActor.GetLevel >= 18
                      Message "Target soul level is GRAND" 4
                  elseif refActor.GetLevel >= 13
                      Message "Target soul level is GREATER" 4
                  elseif refActor.GetLevel >= 7
                      Message "Target soul level is COMMON" 4
                  elseif refActor.GetLevel >= 2
                      Message "Target soul level is LESSER" 4
                  else
                      Message "Target soul level is PETTY" 4
                  endif
             endif
         else
             Message "Target is not an Actor" 4
         endif
     else
          Message "No Target Detected" 4
     endif
     return
    endif
end

This technique misses a lot, and displays "No Target Detected". It seems to be hit or miss even if it seems like I had the crosshair on the target. Is where Is there any other way to get a ref of the target?

Edited by GamerRick
Link to comment
Share on other sites

GetCrosshairRef only returns the target within activation distance. You can dynamically change the related game setting to make it return far away target, but for what you want to do it would be much easier to use OnMagicEffectHit event handler instead.
Link to comment
Share on other sites

GetCrosshairRef only returns the target within activation distance. You can dynamically change the related game setting to make it return far away target, but for what you want to do it would be much easier to use OnMagicEffectHit event handler instead.

Thanks!

Link to comment
Share on other sites

And if you find it usefull, I present here a function which returns 0 or 1 if target of spell was hit by particular effect and a player is responsible:

scn RomRFnHitByPlayer
; this script returns 0 or 1 if a target was hit by particular effect made by player
ref target ;target of a spell,enchant etc.
ref caster
ref m_item
int index
int size
int effect_code
string_var m_effect ;effect code in a form of string, for example "SEFF"
string_var m_effect_active
short result ;variable for return
array_var effects

begin function { target, m_effect }
	set result to 0
	let size := ar_Size effects
	if size == -1
		let effects := ar_Construct array
		let size := ar_Size effects
	endif
	if target != 0 && sv_Length m_effect == 4
		; fill up a field
		let effects := target.GetActiveEffectCodes
		let size := ar_Size effects
		if size > 0 ; active effects exist?
			set index to 0
			while index < size ;scan
				let effect_code := effects[index]
				;convert code to string first
				let m_effect_active := GetMagicEffectCharsC effect_code
				if eval (m_effect == m_effect_active) ;found requested effect code
					let m_item := target.GetNthActiveEffectMagicItem index ;what enchant, spell etc. 
					if m_item != 0
						let caster := target.GetNthActiveEffectCaster index ;who is responsible?
						if caster == player ;it is a player
							set result to 1
							break
						endif															
					endif
				endif
				set index to index + 1
			loop
		endif
	endif
	SetFunctionValue result
	if size > 0
		ar_Resize effects 0
	endif
	let effects := ar_Null
	sv_Destruct m_effect m_effect_active
end

Function is used like this:

scn SomeScript
...
ref actor
short result
...

begin ScriptEffectStart ;for example spell
...
   set actor to GetSelf
   ; someone was hit by script spell effect cast by player
   let result := Call RomRFnHitByPlayer actor "SEFF"
   if result != 0 ;yes
      ...
   endif
...
end
Edited by RomanR
Link to comment
Share on other sites

Wait a sec.... If I use OnMagicEffectHit, I can make sure to not run if I am the target, but how would I know if another NPC cast the spell at another NPC or creature? I only want it to run when I (the playerRef) am the caster.

 

Thanks.

 

I can't get it to work at all:

 

This won't compile without an error saying it will treat "object" as a script

SetEventHandler "OnMagicEffectHit" FnOnSoulTrap object::"STRP"

These compile, but obviously I don't want it to only work when I am the target or not filter for only STRP commands.

SetEventHandler "OnMagicEffectHit" RFFnOnSoulTrap
or
SetEventHandler "OnMagicEffectHit" RFFnOnSoulTrap ref::PlayerRef object::"STRP"
Edited by GamerRick
Link to comment
Share on other sites

I think you can safely use GetSelf command. For example as I used for "OnMagicEffectApply" event.

(borrowed setting a handler from my Counter Effect framework):

...
	; setting an event
	set restart to 0
	if GetGameRestarted
		set restart to 1
	endif
	if restart
		let good := SetEventHandler "OnMagicApply" ShowSoulLevelScript
		if good == 0
			Message "Counter Effect Mod: Creation of event handler failed."
		endif
		set restart to 0
	endif
...

And then for your case it can look like this:

scn ShowSoulLevelScript
ref magic_item
ref caster
ref target
short hit
(another variables for showing soul level)

begin function { magic_item, caster }
  if magic_item != 0
     set target to GetSelf
     if target != 0 && target != player ;valid target, but no player
        if target.IsActor != 0 ;want NPC or creature
           let hit := Call RomRFnHitByPlayer target "STRP" ;using function posted before
           if hit != 0
              (your commands for showing soul level here)
           endif
        endif
     endif
  endif
end

Edited by RomanR
Link to comment
Share on other sites

Seems editor won't let add lines after a code box, so I would only add that for me using OnMagicApply event can be a best solution.

 

But for OnMagicEffectHit filtering a target is easier.

scn RFFnOnSoulTrap
ref target
int effect_code
string_var ascii_code

begin function { target, effect_code }
   if target != 0 
      if target.IsActor != 0 && target != player
         let ascii_code := GetMagicEffectCharsC effect_code
         if eval (ascii_code == "STRP")
            ....
         endif
      endif
   endif
   sv_Destruct ascii_code
end

Edited by RomanR
Link to comment
Share on other sites

The last thing I tried last night is this:

let iResult := SetEventHandler "OnMagicEffectHit" RFFnOnSoulTrap
PrintC"RFLightSpellQuestScript - SetEventHandler result = %g" iResult

Even without any filters on it, it just won't call my function when I cast a STRP spell on a creature. Nothing happens. So, I have given up for now.

Also, according to your script, I could have just done a GetSelf to get the target of the spell??? I find it hard to believe that would work from within a custom function. However, if it does work, wouldn't it also work if my event were OnSpellCast?

"OnMagicApply" is a function for Skyrim.


EDIT: I finally got this to work. Gotta use COMMAS to separate the variables in the command in spite of what the OBSE docs say.
I tried the GetSelf command and it crashes the script.

The quest script (note how using object::PlayerRef changes it to look for the player to cast the spell, whereas ref::PlayerRef looks for the player to be the target of the spell):

let iResult := SetEventHandler "OnMagicEffectHit" RFFnOnSoulTrap, object::PlayerRef, object::"STRP"

The function (same as before) EDIT: Just remembered that I also had to change the 2nd parameter of the function to a long instead of a string_var.

scn RFFnOnSoulTrap
ref rTarget
long lEffect
short iSoulSize
begin Function { rTarget, lEffect }
PrintC"RFFnOnSoulTrap called on %n" rTarget
if rTarget.GetIsReference player
  return
endif
if rTarget.IsActor
  set iSoulSize to GetActorSoulLevel rTarget
  if iSoulSize == 5
   Message "Target soul level is GRAND" 4
   Message "Target soul level is GRAND" 4
   PrintC "Target soul level is GRAND"
  else
   if rTarget.GetLevel >= 18
    Message "Target soul level is GRAND" 4
    Message "Target soul level is GRAND" 4
    PrintC "Target soul level is GRAND"
   elseif rTarget.GetLevel >= 13
    Message "Target soul level is GREATER" 4
    Message "Target soul level is GREATER" 4
    PrintC "Target soul level is GREATER"
   elseif rTarget.GetLevel >= 7
    Message "Target soul level is COMMON" 4
    Message "Target soul level is COMMON" 4
    PrintC "Target soul level is COMMON"
   elseif rTarget.GetLevel >= 2
    Message "Target soul level is LESSER" 4
    Message "Target soul level is LESSER" 4
    PrintC "Target soul level is LESSER"
   else
    Message "Target soul level is PETTY" 4
    Message "Target soul level is PETTY" 4
    PrintC "Target soul level is PETTY"
   endif
  endif
else
  Message "Target is not an Actor" 4
  Message "Target is not an Actor" 4
endif
end

The downside is that if I don't have a soulgem that is big enough for the target, I no longer get the usual message about it.

Edited by GamerRick
Link to comment
Share on other sites

As function is also an object type script, GetSelf returns the object which runs onto. So in the case of events it's no wonder that for "OnMagicApply" you get a target this way. In fact you will get all you need: a magic item (spell, power, enchanment) which caused it, caster and target. You just need a check if this spell has particular effect. I presented a function if target has active effect on it, but as I'm looking, the MagicItemHasEffect should be enough to use in the end.

scn ShowSoulLevelScript
;function for "OnMagicApply" event
ref magic_item
ref caster
ref target
short hit
(another variables for showing soul level)

begin function { magic_item, caster }
  if magic_item != 0
     set target to GetSelf
     if target != 0 && target != player ;valid target, but no player
        if target.IsActor != 0 ;want NPC or creature
           let hit := MagicItemHasEffect "STRP" magic_item ;I am not sure about quotes
           if hit != 0 && caster == player
              (your commands for showing soul level here)
           endif
        endif
     endif
  endif
end

With OnMagicEffectHit, GetSelf should return target too, but as it's already filled in variable by event, you don't need it. With OnSpellCast you don't need it too and if you use it, it will return a caster.

 

Regarding events - is return value from SetEventHandler non zero? How do you know that your function wasn't called? It often helps adding print commads for showing used variables while running a script to view if script is at least doing something.

 

Edit: As I see your new post - no, OnMagicApply isn't only for Skyrim. See the OBSE command docs Event Handlers part and you will see this type of event in the table. It's almost at the end, right under OnMagicCast. But as I see SetEventCommand - doesn't it set the event only for player as a target?

Edited by RomanR
Link to comment
Share on other sites

  • Recently Browsing   0 members

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