Jump to content

Reference Spell (target) location in Papyrus


Recommended Posts

Hi All, I'm getting a little vexed with Papyrus right now as it seems intent on not letting me use any of the functions I want on the objects I'm trying to apply them to o.o I'm hoping there's an answer I'm just missing or a workaround I haven't tried yet.

 

Without giving anything mod specific away, I'm trying to summon a creature to a targetted point. I have the actorbase value of the creature, but can't work out how to get them to appear at a target location, in the way that the standard Summon spells work. There is a good reason for doing it via a script, rather than a standard summon spell, or I wouldn't have been at it all evening. :wallbash:

 

My spell is a F&F/Target Location. Is there a way to reference said location (ie. where the player is aiming?) in Papyrus?

I've tried using an invisible actor, an explosion but my troubles stem from functions that apply to objectreferences and actorbases and what have you not working on the other.

 

What I need to do is along the lines of:

- Player casts aimed spell at target location

- Explosion occurs at target location

- PlaceActorAtMe at explosion

 

I just can't for the life of me obtain the location in papyrus. :-\ Many thanks in advance.

Link to comment
Share on other sites

To elaborate a little, I can get my spell to work using Game.GetPlayer().PlaceActorAtMe()

 

But it would really be great to know how to place an object at a spell hit location.

 

Also, another question...I've attached this to my NPC but it doesn't fire off.

 

Scriptname NPCDeath extends ObjectReference  
{Script triggers on NPC death}

Event OnDeath()

Self.Disable(True)
Self.Delete()

EndEvent

 

One last question...is there a function to return the player character's name as a string? SKSE includes GetName() but it doesn't seem to work on the player.

Link to comment
Share on other sites

I'll try to answer each of your questions in turn:

 

Your summon question:

  1. Add an XMarker to your script (you can place it at some storage cell location, disabled, until you need it for your script).
  2. Move the XMarker to the target point you want.
  3. Trigger the visual effects you want against the XMarker ObjectReference, and do your PlaceAtMe.

 

Your NPC: I'd recommend not attaching the script to your Actor record directly, but against a reference alias. Also, I'd recommend using DeleteWhenAble() rather than a straight delete.

 

Player name as string: Use <Alias=Player> in whatever text area you wish (dialogue, books, messages, etc.).

Link to comment
Share on other sites

I'll try to answer each of your questions in turn:

 

Your summon question:

  1. Add an XMarker to your script (you can place it at some storage cell location, disabled, until you need it for your script).
  2. Move the XMarker to the target point you want.
  3. Trigger the visual effects you want against the XMarker ObjectReference, and do your PlaceAtMe.

Step 2 is where my trouble lies. I can't work out how to return the target point to my script. :-(

 

Your NPC: I'd recommend not attaching the script to your Actor record directly, but against a reference alias. Also, I'd recommend using DeleteWhenAble() rather than a straight delete.
The trouble is that I want the NPC to fade away immediately on death, akin to a normal summon. It works fine, for example if I summon a second one, but not if they die by any other means. The only event I can think of that would help here is an ondeath called by the actor itself, but I can't see how to reference the calling actor (ie. the now deceased summoned NPC). Self doesn't seem to do it :-\

 

Player name as string: Use <Alias=Player> in whatever text area you wish (dialogue, books, messages, etc.).
It was really in Papyrus that I wanted to access the name, along the lines of the following:

ActorBase SummonedNPC.SetName(Game.GetPlayer().GetName() + "'s NPC")

The SetName() function works, but GetName() (the SKSE function) doesn't work on the player (or at least it doesn't return their character's name).

Link to comment
Share on other sites

Well, given that you've given me somewhat limited information to work with, I'll try to answer again as best I can. More information makes it easier on us. :)

 

Your summon question: I don't know how exactly you've set up your script, so I can't really say exactly how to go about setting this up. How is your target location being determined? Anywhere the player aims? What archetype effect are you using, or just plain script? IOW, depending on how you set it up, you may be able to just tag against your OnEffectStart()'s akTarget. If it's a spell that can target anything and everything (e.g., floors, walls, whatever), you may have to "fake" the situation by using the projectile + explosion approach, with your marker dropped by the explosion and, finally, creating whatever effect that point on the marker. This latter approach is less a scripting exercise than a pure CK exercise.

 

Your death question: You're missing an effect of what you're trying to do. You probably want something like the following, which is what I've used in a couple of my mods; just substitute the effect you want to use.

Event OnDying(Actor myKiller)
AtronachUnsummonDeathFXS.Play(Self.GetActorReference())
endEvent

Event OnDeath(Actor myKiller)
Self.GetActorReference().Disable(true)
Self.GetActorReference().DeleteWhenAble()
endEvent

Your player name question: I guess I'm not understanding exactly what you're trying to do via direct script with the player name that can't be done with <Alias=Player>. Again, maybe I'm missing something because you're not really giving a whole lot of info. :P

Link to comment
Share on other sites

Well, given that you've given me somewhat limited information to work with, I'll try to answer again as best I can. More information makes it easier on us. :)

 

Your summon question: I don't know how exactly you've set up your script, so I can't really say exactly how to go about setting this up. How is your target location being determined? Anywhere the player aims? What archetype effect are you using, or just plain script? IOW, depending on how you set it up, you may be able to just tag against your OnEffectStart()'s akTarget. If it's a spell that can target anything and everything (e.g., floors, walls, whatever), you may have to "fake" the situation by using the projectile + explosion approach, with your marker dropped by the explosion and, finally, creating whatever effect that point on the marker. This latter approach is less a scripting exercise than a pure CK exercise.

I guess the trouble is that I can't work out how to determine the target location. I want to reference the target location the player aims at/fires at, but nothing I've tried has worked.

 

I tried creating an inivisible actor, using FindClosestReferenceOfTypeFromRef to find him, place my real actor there and delete the invisible one, but it didn't work either.

I have an explosion that drops a marker, but again using the above function, I can't get its location into Papyrus.

 

In pseudo code, this would be the effect I'd like. When player casts F&F spell at target location:

 

If NPC already exists, delete it (this part is working, but not if they are killed in any other manner)

Create explosion and marker at impact point

Create Actor at marker

Delete Marker

 

Your death question: You're missing an effect of what you're trying to do. You probably want something like the following, which is what I've used in a couple of my mods; just substitute the effect you want to use.

 

Event OnDying(Actor myKiller)
AtronachUnsummonDeathFXS.Play(Self.GetActorReference())
endEvent

Event OnDeath(Actor myKiller)
Self.GetActorReference().Disable(true)
Self.GetActorReference().DeleteWhenAble()
endEvent

Darn it, this looks great but I can't get it to compile :-( I tried substituting GetActorBase() too, but as far as I can tell, Disable and Delete work on the Actor, rather than the ActorBase. Removing the Self part entirely, the script compiles but still doesn't work :-| I must be missing something here. It can't be this hard to reference the actor that called the script. o.o

 

Your player name question: I guess I'm not understanding exactly what you're trying to do via direct script with the player name that can't be done with <Alias=Player>. Again, maybe I'm missing something because you're not really giving a whole lot of info. :P
In this case, I'm trying to rename the Summoned NPC to be "Player's NPC" similar to "Player's Flame Atronach" or what have you when one casts a vanilla conjuration spell.

 

This is my code that works using the player as the location:

Scriptname SummonNPC extends ActiveMagicEffect
{Summons NPC}

GlobalVariable Property SummonedNPC auto
Explosion Property MyExplosion auto
ActorBase Property NPC auto
Actor SummonedNPC

EVENT OnEffectStart(Actor Target, Actor Caster)

float NPCActive = SummonedNPC.GetValue()
ObjectReference SummonPortal

if (NPCActive == 0)
	SummonPortal = Game.GetPlayer().PlaceAtMe(ExplosionNPC)
	SummonedNPC = SummonPortal.PlaceActorAtMe(NPC)
;		NPC.SetName(Game.GetPlayer().GetName()+ "'s NPC") *Note: Can't get this working
	Utility.Wait(2)
	SummonPortal.DisableNoWait(True)
	SummonedNPC.SetValue(1)
else
	KillNPC(SummonedNPC)
	SummonPortal = Game.GetPlayer().PlaceAtMe(ExplosionNPC)
	SummonedNPC = SummonPortal.PlaceActorAtMe(NPC)
;		NPC.SetName(Game.GetPlayer().GetName()+ "'s NPC") *Note: Can't get this working
	Utility.Wait(2)
	SummonPortal.DisableNoWait(True)
endif

endEvent

Event OnEffectFinish(Actor akTarget, Actor akCaster)

KillNPC(SummonedNPC)
SummonedNPC.SetValue(0)

EndEvent

Function KillNPC(Actor NPCToKill)
NPCToKill.Disable(True)
NPCToKill.Delete()
EndFunction

I've modified it a touch as it's my personal twist that is a surprise :-) But really I'd like to use "Target Location" in lieu of Game.GetPlayer().

Link to comment
Share on other sites

Re Target Location: You really shouldn't "need" the exact coordinates, but if you do, you could use GetPosX/Y/Z() for whatever object you're dropping via explosion. If the explosion technique didn't work for you, did you verify that you have all 3 components set up (projectile + explosion + drop object) and have the magic effect set up properly? Once you've verified the drop object is handled properly, you don't need the actual coordinates, but can simply do stuff like yourSummon.MoveTo(dropObject) and vxEffect.Play(dropObject).

 

Re "Unsummon" Effect: I'm not sure why it's not compiling; note that my example uses ReferenceAlias rather than binding the script directly to the Actor(base). If you're binding directly to the Actor, get rid of GetActorReference() (which is only needed because I was using ReferenceAlias).

 

Re Player Name in Summmon's Name: It seems that you want to stay outside the vanilla Skyrim summoning framework, which is fine, but you can use the same technique the vanilla engine uses to handle your naming, which is via <Alias=Player>. Again, this is less of a scripting exercise than a CK exercise. I'm assuming you have at least an admin quest framework set up, so you'd simply need to do the following:

 

  1. Create a Message with title "<Alias=Player>'s Summon Name" and leave the message text box empty
  2. In your quest framework, set up a ReferenceAlias to your summon, make sure you check the boxes for "Uses Stored Text" and "Stores Text", and from the "Display Name" dropdown, select the Message you created above ... beyond that, it's really up to you in terms of how you want the alias set up (forced vs. non, optional, etc., as I don't know the parameters around your summon. If this summon recurs whenever the player casts the spell, etc., set it up as Optional and just fill the ReferenceAlias on-the-fly in the summoning script. Once the alias is filled, the name gets displayed automatically, no need for SKSE, SetName(), etc.

If you need an example framework on this, consider how vanilla "horses" are handled in terms of naming (Player Name's Horse); this is done via an admin quest that handles stables and horse purchases.

Link to comment
Share on other sites

I'm almost there now, made some breakthroughs.

 

I'm giving up on changing the name. Ultimately, it's not that important, more for the sake of "consistency" than anything else.

Actor OnDeath script now works. I declared it as "extends ObjectReference" instead of "extends Actor" :rolleyes:

I've just now cracked the behaviour so on spawning in, they *should* behave as a follower. I have yet to work out how the game tracks summons though, else this one would be in addition to the vanilla ones. Probably a global.

For Projectile -> Explosion, my mistake here was not creating a custom projectile, which I didn't realise in turn created the explosion. Now I can successfully fire a projectile, watch an (extremely obnoxious!) explosion and spawn an item (tested with something visible) at a target location.

Now the last challenge is how can I obtain the reference of the object in the script? FindClosest doesn't seem to be helping. I think this is my last major hurdle. :facepalm: I'm using a static object with "Is Marker" ticked, if that makes any difference.

 

SpawnPoint = Game.FindClosestReferenceOfTypeFromRef(MyMarker, Game.GetPlayer(), 1024)

 

Really appreciate the help BTW. I didn't think such a simple idea turned out to be so ambitious. Had to do several things that individually are a mod by themselves. :mellow:

 

And as an aside, I've spent 45 minutes looking at projectiles and explosions. My favourite is Sun Fire but using it would mean Dawnguard requirement (which I have so far managed to avoid!) :-(

Link to comment
Share on other sites

Congrats! The CK / scripting doesn't always make "straight line", intuitive sense on accomplishing what would be perceived as "routine" or "simple" things at times. :P Regarding your location, I believe you're making your life more difficult than it needs to be. Just bind a script to your drop object that does whatever you need it to do at the impact point, something to the effect of:

 

yourScript extends ObjectReference
... your properties ...

Event OnInit()
    ; do whatever you need to have done at impact point, e.g., yourEffect.Play(Self)
    Self.GetPosX() ; if you really need the coords, but you could just bypass this and do the effects, etc., at "Self"
    Self.GetPosY()
    Self.GetPosZ()
endEvent

Link to comment
Share on other sites

Well I finally got over the last major scripting hurdle, namely killing an existing Summoned NPC if one already exists. Took most of yesterday failing before i had an epiphany. Sadly, they don't work with regard to existing vanilla summoned creatures (ie. an existing Flame Atronach or zombie won't disappear when mine appears) but I think it will take too long to work out how the vanilla system works to integrate that in. Last couple of questions if anyone can help with while I'm adding some polish.

 

- Does anyone know how to change the level of "soul" that's captured when a creature is slain (with soul trap active)? eg. How would I change a wolf to give a greater soul, or a skeever a grand one, etc?

- How would one go about making an NPC use an ability? I've worked out "Combat Styles" and have customised them (barring a little tweaking) to balance magic/melee etc, but custom abilities don't get used.

- Out of curiosity, does anyone know where the game stores info on current summons? Further to that, how the game calculates and manipulates "Twin Souls" perk. Is there a method of reading the objectref of the current summon?

 

Will be sharing my scripts soon in the hope that another may find parts useful, but will do so in a new thread for the sake of search engine parsing.

Link to comment
Share on other sites

  • Recently Browsing   0 members

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