Jump to content

Help with a script


senterpat

Recommended Posts

So I'm using this script to try and basically recreate the frozen orb spell from Diablo II, but have reached a point where I am completely befuddled. I have an explosion that is placed as the orb moves, and that is triggering just fine, but the projectiles I tell to shoot from the same spot I placed the explosion at, for some reason are firing from the player, and not registering the rotation I'm trying to input. Hopefully someone can help me with this. So the script is as follows:

scriptName patDestructFrozenOrbTriggerBoxScript extends ObjectReference
;this is the script to attach to the triggerbox i spawn

Projectile Property MyProjectile Auto
Activator Property XMarkerHeading Auto
Spell Property IceBoltSpell Auto
Float Property fTRotation = 20.0 Auto
Explosion Property ExplosionRef Auto

Float PosX 
Float PosY  
Float PosZ 
Float AngX 
Float AngY 
Float AngZ
Int IceboltCount
ObjectReference XMarkerHeadingRef
ObjectReference FrozenOrb
Actor Player

Event OnTriggerEnter(ObjectReference akActionRef)
    Form Base = akActionRef.GetBaseObject() 
	FrozenOrb = akActionRef
    If Base as Projectile 
        If Base == MyProjectile 
			Player = Game.GetPlayer()
			XMarkerHeadingRef = FrozenOrb.PlaceAtMe(XMarkerHeading)
			StartChain()
        Endif 
    Endif 
EndEvent

Function StartChain()
  RegisterForSingleUpdate(0.1) 
EndFunction
 
Event OnUpdate()
	Bool bKeepUpdating = True
		if IceboltCount < 27
			AngX = XMarkerHeadingRef.GetAngleX()
			AngY = XMarkerHeadingRef.GetAngleY()
			AngZ = XMarkerHeadingRef.GetAngleZ()
			AngZ = (AngZ + fTRotation)
			XMarkerHeadingRef.placeatme(ExplosionRef)
			XMarkerHeadingRef.Moveto(FrozenOrb, abMatchRotation = False)
			XMarkerHeadingRef.SetAngle(AngX, AngY, AngZ)
			IceBoltSpell.RemoteCast(XMarkerHeadingRef, Player)
			IceboltCount = (IceboltCount + 1)
			RegisterForSingleUpdate(0.1)
		else
			FrozenOrb.placeatme(ExplosionRef)
			FrozenOrb.Disable()
			IceboltCount = (IceboltCount + 0)
		endif
		
					
EndEvent

Originally I tried using remotecast on the projectile reference, but that ended up firing from the player as well, and had the added effect of the projectile altering course. But the explosions trigger at the location of the orb, so am I maybe using remotecast indirectly?

 

edit: so I tried using cast instead of remote cast, which seems to be working a bit better, it is now firing the projectiles from around where the orb is. but the script is firing a bunch of projectiles in one direction, then a bunch in another direction, and doesnt seem to be able to keep up with the projectile (200 speed).

Is there an issue with my Update Block that would cause it to rapid fire like that? I tried to set it up to fire one, wait a moment, and then rotate and fire another.

Edited by senterpat
Link to comment
Share on other sites

Hmmm, it looks like it should be working. Try messing around with the update time. Reducing it or increasing it, and maybe reduce the script a bit:

 

Projectile Property MyProjectile Auto
Activator Property XMarkerHeading Auto
Spell Property IceBoltSpell Auto
Float Property fTRotation = 20.0 Auto
Explosion Property ExplosionRef Auto

Int IceboltCount
ObjectReference XMarkerHeadingRef
ObjectReference FrozenOrb
Actor Player

Event OnTriggerEnter(ObjectReference akActionRef)
    Form Base = akActionRef.GetBaseObject() 
    If Base as Projectile 
        If Base == MyProjectile 
            FrozenOrb = akActionRef
            Player = Game.GetPlayer()
            XMarkerHeadingRef = FrozenOrb.PlaceAtMe(XMarkerHeading)
            IceboltCount = 0
            RegisterForSingleUpdate(0.05)
        Endif 
    Endif 
EndEvent

Event OnUpdate()
    if IceboltCount < 27
        XMarkerHeadingRef.placeatme(ExplosionRef)
        XMarkerHeadingRef.Moveto(FrozenOrb, abMatchRotation = False)
        XMarkerHeadingRef.SetAngle(XMarkerHeadingRef.GetAngleX(), XMarkerHeadingRef.GetAngleY(), (XMarkerHeadingRef.GetAngleZ() + fTRotation))
        IceBoltSpell.Cast(XMarkerHeadingRef)
        IceboltCount += 1 ;add 1 to IceboltCount
        RegisterForSingleUpdate(0.05)
    else
        FrozenOrb.placeatme(ExplosionRef)
        FrozenOrb.Disable()
    endif
EndEvent

 

Link to comment
Share on other sites

Much appreciated for cleaning up the script, I'm no professional scripter. But after adding it in and setting it back up its functioning much better, the ice spikes are firing with the orb now, not at an even pace, but that's likely script latency and I can live with.. But its still not registering the rotation. I can't for the life of me work this out.

 

Is there possibly a setting on the XMarkerHeadingRef I'm missing? Its just a XMarkerHeading mesh, with default settings. I used it to create the trigger box that gets teleported to the player using an ability spell. Or something on the triggerbox?

Link to comment
Share on other sites

No problem. So I did some testing, and it turns out using .Cast or .RemoteCast on an object reference, it doesn't matter what angle it is, it always casts in the same direction. I tested with a Bee Activator, a Static, a Misc Object and a Movable Static. Using an Actor though, the spell fires from the correct direction. So, make a dummy invisible actor to use as the XMarkerHeading instead. Then modify the script slightly:

Projectile Property MyProjectile Auto
ActorBase Property ActorMarkerHeading Auto
Spell Property IceBoltSpell Auto
Float Property fTRotation = 20.0 Auto
Explosion Property ExplosionRef Auto

Int IceboltCount
Actor ActorMarkerHeadingRef
ObjectReference FrozenOrb
Actor Player


Event OnTriggerEnter(ObjectReference akActionRef)
    Form Base = akActionRef.GetBaseObject() 
    If Base as Projectile 
        If Base == MyProjectile 
            FrozenOrb = akActionRef
            Player = Game.GetPlayer()
            ActorMarkerHeadingRef = FrozenOrb.PlaceActorAtme(ActorMarkerHeading)
            ActorMarkerHeadingRef.EnableAi(False) ;disable actor 
            ActorMarkerHeadingRef.SetAlpha(0) ;make actor invisible
            IceboltCount = 0
            RegisterForSingleUpdate(0.05)
        Endif 
    Endif 
EndEvent

Event OnUpdate()
    if IceboltCount < 27
        ActorMarkerHeadingRef.placeatme(ExplosionRef)
        ActorMarkerHeadingRef.Moveto(FrozenOrb, abMatchRotation = False)
        ActorMarkerHeadingRef.SetAngle(ActorMarkerHeadingRef.GetAngleX(), ActorMarkerHeadingRef.GetAngleY(), (ActorMarkerHeadingRef.GetAngleZ() + fTRotation))
        IceBoltSpell.Cast(ActorMarkerHeadingRef)
        IceboltCount += 1 ;add 1 to IceboltCount
        RegisterForSingleUpdate(0.05)
    else
        FrozenOrb.placeatme(ExplosionRef)
        FrozenOrb.Disable()
        ActorMarkerHeadingRef.Disable() 
        ActorMarkerHeadingRef.Delete()
    endif
EndEvent

If the actor is invisible already the SetAlpha line isn't necessary. Hope that helps!

Link to comment
Share on other sites

Awesome. That helped out a lot. For some reason the script won't use moveto on the projectile with AI disabled (tho I can move it to the player via console while disabled). Easily circumvented by enabling AI before moving the NPC and then disabling again. I had to also add an Int to check for if the orb was active. Firing an additional spell would make the triggerbox ignore the original, causing the NPC activator to not be deleted. I tried using OnTriggerLeave, but the trigger box was proving to be a pain to get to the proper size to register the projectile without starting the effect too long after the spell was fired. So unless there is a way to tell the script to keep running on both projectiles I'll have to deal with it. Thank you so much for your help dylbill. The final script in case anyone wants to do anything similar:

Projectile Property MyProjectile Auto
ActorBase Property ActorMarkerHeading Auto
Spell Property IceBoltSpell Auto
Float Property fTRotation = 20.0 Auto
Explosion Property ExplosionRef Auto

Int  OrbActive
Int IceboltCount
Actor ActorMarkerHeadingRef
ObjectReference FrozenOrb
Actor Player


Event OnTriggerEnter(ObjectReference akActionRef)
	if OrbActive != 1
		Form Base = akActionRef.GetBaseObject() 
		If Base as Projectile 
			If Base == MyProjectile 
				FrozenOrb = akActionRef
				Player = Game.GetPlayer()
				ActorMarkerHeadingRef = FrozenOrb.PlaceActorAtme(ActorMarkerHeading)
				ActorMarkerHeadingRef.EnableAi(False) ;disable actor 
				IceboltCount = 0
				RegisterForSingleUpdate(0.05)
				OrbActive = 1
			Endif 
		Endif 
	Endif
EndEvent

Event OnUpdate()
    if IceboltCount < 27
        ActorMarkerHeadingRef.EnableAi(True)
        ActorMarkerHeadingRef.Moveto(FrozenOrb, abMatchRotation = False)
		ActorMarkerHeadingRef.EnableAi(False)
        ActorMarkerHeadingRef.SetAngle(ActorMarkerHeadingRef.GetAngleX(), ActorMarkerHeadingRef.GetAngleY(), (ActorMarkerHeadingRef.GetAngleZ() + fTRotation))
        IceBoltSpell.RemoteCast(ActorMarkerHeadingRef, Player)
        IceboltCount += 1 ;add 1 to IceboltCount
        RegisterForSingleUpdate(0.05)
    else
        FrozenOrb.placeatme(ExplosionRef)
        FrozenOrb.Disable()
        ActorMarkerHeadingRef.Disable() 
        ActorMarkerHeadingRef.Delete()
		OrbActive = 0
    endif
EndEvent

I also had to set the casting NPC to .1 in order to get the spell to fire from the orb rather then above it.

 

Friendly NPCs such as riverwood citizens also report the crime, but do not start combat with the player(not red on compass) but do try and attack the ActorMarkingHeadingRef. I may be able to get around this by making the ice spike magic effect painless while attaching a script that forces targets hit into combat with the player.

Edited by senterpat
Link to comment
Share on other sites

No problem, glad you got it working mostly. Is the player the only one that will use the spell? If not, and you want NPC's to use, you can set up a caster actor property in the trigger box script, and set the property when casting the spell. Something like this:

 

 

 

Projectile Property MyProjectile Auto
ActorBase Property ActorMarkerHeading Auto
Spell Property IceBoltSpell Auto
Float Property fTRotation = 20.0 Auto
Explosion Property ExplosionRef Auto
Actor Property Caster Auto 

Int  OrbActive
Int IceboltCount
Actor ActorMarkerHeadingRef
ObjectReference FrozenOrb
Actor Player

Event OnTriggerEnter(ObjectReference akActionRef)
    if OrbActive != 1
        Form Base = akActionRef.GetBaseObject() 
        If Base as Projectile 
            If Base == MyProjectile 
                FrozenOrb = akActionRef
                Player = Game.GetPlayer()
                ActorMarkerHeadingRef = FrozenOrb.PlaceActorAtme(ActorMarkerHeading)
                ActorMarkerHeadingRef.EnableAi(False) ;disable actor 
                IceboltCount = 0
                RegisterForSingleUpdate(0.05)
                OrbActive = 1
            Endif 
        Endif 
    Endif
EndEvent

Event OnUpdate()
    if IceboltCount < 27
        ActorMarkerHeadingRef.EnableAi(True)
        ActorMarkerHeadingRef.Moveto(FrozenOrb, abMatchRotation = False)
        ActorMarkerHeadingRef.EnableAi(False)
        ActorMarkerHeadingRef.SetAngle(ActorMarkerHeadingRef.GetAngleX(), ActorMarkerHeadingRef.GetAngleY(), (ActorMarkerHeadingRef.GetAngleZ() + fTRotation))
        IceBoltSpell.RemoteCast(ActorMarkerHeadingRef, Caster)
        IceboltCount += 1 ;add 1 to IceboltCount
        RegisterForSingleUpdate(0.05)
    else
        FrozenOrb.placeatme(ExplosionRef)
        FrozenOrb.Disable()
        ActorMarkerHeadingRef.Disable() 
        ActorMarkerHeadingRef.Delete()
        OrbActive = 0
    endif
EndEvent

Then when spawning the trigger box do something like this:
Static Property IceTriggerBox Auto 

Event OnEffectStart(Actor akTarget, Actor akCaster) 
    ObjectReference IceTriggerBoxRef = akCaster.PlaceAtMe(IceTriggerBox, 1) 
    (IceTriggerBoxRef as patDestructFrozenOrbTriggerBoxScript).Caster = akCaster
EndEvent
But if the blame for the remoteCast function isn't working, then the point is moot anyway.
Link to comment
Share on other sites

  • Recently Browsing   0 members

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