Jump to content

GetDistance Script Help


Dark122490

Recommended Posts

Hi,

 

I'm trying to write a script that will cause a spell to be cast (using CastImmediateOnSelf) with the reference as an Actor that has passed a distance threshold stated by the command "GetDistance".

 

I've looked around and saw something called "GetActionRef" but it seems to only work with Trigger Boxes such as those used in quests. I want the player to "be" the trigger box in that when an NPC steps within 30 game units of the player, a spell is cast on the actor.

 

So far I've only built up something like this from the Construction Wiki for Oblivion (the GECK wiki didn't have specific examples):

 

scnSpellProximityScript

 

Ref Actor

 

Begin OnTriggerEnter

set Actor to GetActionRef

if player.Getdistance Actor < 30

Actor.castimmediateonself Myspell

endif

end

 

I placed this object script on a random misc item that I later get in game, however it didn't function. I'm just not sure about the OnTriggerEnter beginner...

 

Anyone experimented with this before?

Link to comment
Share on other sites

OnTriggerEnter won't work in this case. If you want to use an OnTriggerEnter block, then you'd need to have it attached to a trigger box which you move along with the player via script, in which case you wouldn't need to call GetDistance.

 

I don't know it moving a triggerbox along with the player via script would cause any issues, but I'd probably go with a reference walking loop instead. In order to prevent any performance issues caused by calling GetDistance multiple times per frame, I'd recommend using a quest script with a script processing delay. Something like 0.5 should work fine - with the script running twice per second.

 

Try something like this:

ref rCurrentRef

Begin GameMode

set rCurrentRef to GetFirstRef 200 0 0 ; Actors

Label 10
if rCurrentRef
	if rCurrentRef.IsSpellTarget MySpell
	elseif rCurrentRef.GetDistance player < 30
		rCurrentRef.CastImmediateOnSelf MySpell
	endif

	set rCurrentRef to Pencil01 ; Prevent "apple" bug
	set rCurrentRef to GetNextRef
	Goto 10
endif

End

 

P.S. Please use "code" tags when posting scripts. It maintains indentation and forces them to use a fixed width font, making them much easier to read.

 

Cipscis

Link to comment
Share on other sites

OnTriggerEnter won't work in this case. If you want to use an OnTriggerEnter block, then you'd need to have it attached to a trigger box which you move along with the player via script, in which case you wouldn't need to call GetDistance.

 

I don't know it moving a triggerbox along with the player via script would cause any issues, but I'd probably go with a reference walking loop instead. In order to prevent any performance issues caused by calling GetDistance multiple times per frame, I'd recommend using a quest script with a script processing delay. Something like 0.5 should work fine - with the script running twice per second.

 

Try something like this:

ref rCurrentRef

Begin GameMode

set rCurrentRef to GetFirstRef 200 0 0 ; Actors

Label 10
if rCurrentRef
	if rCurrentRef.IsSpellTarget MySpell
	elseif rCurrentRef.GetDistance player < 30
		rCurrentRef.CastImmediateOnSelf MySpell
	endif

	set rCurrentRef to Pencil01 ; Prevent "apple" bug
	set rCurrentRef to GetNextRef
	Goto 10
endif

End

 

P.S. Please use "code" tags when posting scripts. It maintains indentation and forces them to use a fixed width font, making them much easier to read.

 

Cipscis

 

I'm unsure about some parts of your example script, here is my take:

 

ref rCurrentRef

Begin GameMode

       set rCurrentRef to GetFirstRef 200 0 0 ; Actors

       Label 10
       if rCurrentRef
               if rCurrentRef.IsSpellTarget MySpell == 0 && rCurrentRef.GetDistance player < 30
                       rCurrentRef.CastImmediateOnSelf MySpell
               endif

               set rCurrentRef to Pencil01 ; Prevent "apple" bug
               set rCurrentRef to GetNextRef
               Goto 10
       endif
End

 

I looked up all the commands you used (didn't realize GetFirstRef was a FOSE command) and noticed something about IsSpellTarget. Shouldn't there be an integer value for that? Since 1 means the actor has the spell and 0 meaning it doesn't? So I would want to specify that the spell would only be cast if the target is not already under the effects of that spell.

 

Furthermore, I don't understand your use of elseif in line 10 of your script. Would it not make more sense for both conditions to be met before casting the spell? That way it ensures the actor did not already have the spell on it and that the distance is within 30 game units.

 

But besides all that, I still can't seem to implement this in game. I placed the script on a quest and made the script processing delay at 0.5. I clicked the "Start Game Enabled" radio button but it doesn't seem to do a thing. Do I need to add a stage to the quest? I thought quest scripts begin running when "Start Game Enabled" is...well enabled.

 

Also just out of curiosity, what is the "apple" bug?

Link to comment
Share on other sites

No, don't use PlaceAtMe explosions. That method has similar results to a reference walking loop, but is horrendously inefficient in comparison.

 

Conditional statements work by checking if the condition supplied to them evaluates to 0 or not. If the condition evaluates to 0, then the code inside the conditional statement does not run, otherwise it does run. This means that using "== 1" on conditions that evaluate to boolean values (i.e. 1 or 0) do nothing except make the script less efficient.

 

For example:

if IsSpellTarget MySpell == 1

IsSpellTarget can evaluate to 1 or 0, so once it has been called you can imagine the line looking like one of these two lines:

if 1 == 1
if 0 == 1

The "is equal to" operator is then evaluated. This operator returns 1 if both operands are equal, and 0 if they are not, which means that it will not change boolean values in a meaningful way when the second operand is 1 ("1 == 1" returns 1, and "0 == 1" returns 0). The following two lines are equivalent, but the first is more efficient:

if IsSpellTarget MySpell
if IsSpellTarget MySpell == 1

"else" and "elseif" statements have a special extra condition - "and all previously checked conditions in the current block of conditional statements were false (i.e. evaluated to 0)". This means that the following three pieces of code will work in the same way:

if rCurrentRef.IsSpellTarget MySpell
elseif rCurrentRef.GetDistance player < 30
rCurrentRef.CastImmediateOnSelf MySpell
endif

if rCurrentRef.IsSpellTarget MySpell == 0
if rCurrentRef.GetDistance player < 30
	rCurrentRef.CastImmediateOnSelf MySpell
endif
endif

if rCurrentRef.IsSpellTarget MySpell == 0 && rCurrentRef.GetDistance player < 30
rCurrentRef.CastImmediateOnSelf MySpell
endif

In the first two examples, GetDistance will only be called if the IsSpellTarget condition has been evaluated in the intended way, whereas in the third example it will always be called. The first example is also slightly more efficient than the second because it doesn't need to use "== 0" to "invert" the condition - this is done implicitly by using an "elseif" statement.

 

The "apple bug" is a bug in GetNextRef, where it will not always update correctly, which can be fixed by setting it to an arbitrary value before calling GetNextRef. It originated in Oblivion, and is called the "apple bug" because it was named after its solution:

set rCurrentRef to Apple

In Fallout 3, I've always used "Pencil01" as my arbitrary value, but I give it the same name so that anyone familiar with it from Oblivion will know what I'm talking about.

 

You don't need to add a stage to your quest or anything like that to get it working, although I don't know why it isn't working at the moment. Try adding some DebugPrint lines to your script to make sure that it's actually running (use SetDebugMode in the console to activate these statements).

 

Cipscis

Link to comment
Share on other sites

  • Recently Browsing   0 members

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