Jump to content

Help with creating a script for a spell


Gardden

Recommended Posts

Hello!

 

I'm trying to create a spell that works like the Quen sign from The Witcher game series.

 

The spell will work like a stoneflesh spell, boosting the player's damage resistance, and also reflects some of the damage back to the attacker.

For now it lasts for 30 seconds, but I wanted to make it also dispell once the player is hit a certain number of times (like 3, for example).

I have zero knowledge in scripting, can someone help me make this work?

 

Thanks!

Link to comment
Share on other sites

Make a quest that you will start when your spell is cast. So you may need to make another magic effect for your spell to hold a small script which tells the quest to start.

 

 

Not tested for function or compilation

Scriptname SomeMagicEffectScript Extends ActiveMagiceEffect

Quest Property myQuest Auto

Event OnEffectStart(Actor akTarget, Actor akCaster)
  If !myQuest.IsRunning()  ;is quest not running
    myQuest.Start()             ;start quest
  EndIf
EndEvent

 

 

On the quest, create an alias that points to the player. Attach a script to this player alias which will use the OnHit event to track how many times the player gets hit. When the correct number is reached, dispel the spell and stop the quest.

 

 

Not tested for function or compilation

Scriptname SomeAliasScript Extends ReferenceAlias

Quest Property myQuest Auto
Spell Property mySpell Auto
Int Property numHitsRequired = 3 Auto
Int numHitsCurrent = 0

Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked)
  numHitsCurrent += 1
  If numHitsCurrent == numHitsRequired
    (Self.GetReference() as Actor).DispelSpell(mySpell)
    myQuest.Stop()
  EndIf
EndEvent
;note - no need to reset the numHitsCurrent variable as it will be reset each time the quest is started.

 

 

But, keep in mind that the OnHit event can register multiple hits from the same source. This is especially true of weapons with enchantments. Each enchantment effect will count as a hit.

 

Also, lets leave some wiggle room for others who may know of different or better ways to do what you are asking. :D

Link to comment
Share on other sites

As IsharaMeradin has written, there is another way to reach your aim.

 

Your spell is using different magicEffects.. one of these effects should be a scripted effect, which has a special keyword attached

next script may help to explain the structure, I am not sure about caster or target.. try out!

 

gardPlayerStoneEffectScript

 

Scriptname gardPlayerStoneEffectScript extends ActiveMagicEffect
; https://forums.nexusmods.com/index.php?/topic/8152913-help-with-creating-a-script-for-a-spell/
; spell should be casted as cloak effect with duration limit of 30 sec

  Spell   PROPERTY mySpell auto             ; the spell that was casted with this magic effect
  Keyword PROPERTY myKeywo auto             ; a unique keyword which should be attached to this effect

  Int PROPERTY iMaxHits = 3 auto            ; [default=3]
  Int PROPERTY iHitCounter  auto Hidden     ; [default=0]


; -- EVENTs -- 3 + "Waiting"

EVENT OnEffectStart(Actor akTarget, Actor akCaster)
IF (akTarget == akCaster) && (akTarget == Game.GetPlayer())
ELSE
    akTarget.DispelSpell( mySpell )
    RETURN    ; - STOP -    not the player, remove this spell immediately
ENDIF
;---------------------
IF akTarget.HasEffectKeyword(myKeywo)
    RETURN    ; - STOP -    effect is already running
ENDIF
;---------------------
    gotoState("Waiting")            ; ### STATE ###
    Debug.Trace(" Effect started.. " +self)                  ; for debugging only
ENDEVENT


EVENT OnEffectFinish(Actor akTarget, Actor akCaster)
    Debug.Trace(" Effect has been finished.. " +self)        ; for debugging only
ENDEVENT


EVENT OnHit(ObjectReference akAggressor, Form akSource, Projectile akProj, Bool b1, Bool b2, Bool b3, Bool b4)
; received when this "object" is hit by a source (weapon, spell, explosion) or projectile attack
IF ( b4 )
    RETURN    ; - STOP -    hit blocked
ENDIF
;---------------------
IF (akSource as Weapon)
    gotoState("Waiting")            ; ### STATE ###
    myF_Action()
    Utility.Wait(0.25)
    gotoState("")                   ; ### STATE ###
    RETURN    ; - STOP -    take the weapon effect only, not the enchantment hit
ENDIF
;---------------------
    myF_Action()
ENDEVENT


;===========================
state Waiting  ; look at papyrus source script "ActiveMagicEffect.psc"
;============
EVENT OnHit(ObjectReference akAggressor, Form akSource, Projectile akProj, Bool b1, Bool b2, Bool b3, Bool b4)
ENDEVENT
;=======
endState


; -- FUNCTION --
; https://www.creationkit.com/index.php?title=ActiveMagicEffect_Script

;--------------------
FUNCTION myF_Action()
;--------------------
    iHitCounter+= 1                                  ; counter +1
    IF (iHitCounter >= iMaxHits)
        GetTargetActor().DispelSpell( mySpell )      ; GetCasterActor()
    ENDIF
ENDFUNCTION

 

 

 

I think each way is good there is no way better.

Edited by ReDragon2013
Link to comment
Share on other sites

Thank you both for answering my topi, it's much appreciated! :D

 

Unfortunately, I could not get it to work :(

I'm sure it's a problem on my end. Here's what I did:

 

Option 1 (IsharaMeradin)

 

Created a new Magic Effect (W_SignQuenEffect_1Script)

Archetype: Script

Casting Type: Fire and Forget

Delivery: Self

 

Added your script to Papyrus Script:

 

Scriptname W_QuenSign01EffectScript extends activemagiceffect
{Script for Sign Quen Quest}
Quest Property W_QuenSign01Quest Auto
Event OnEffectStart(Actor akTarget, Actor akCaster)
If !W_QuenSign01Quest.IsRunning() ;is quest not running
W_QuenSign01Quest.Start() ;start quest
EndIf
EndEvent
Created a new quest (W_QuenSign01Quest)
Have "start game enabled" selected
On Aliases, have an Alias named "player" with specific reference set to "PlayerRef"
Added you script to Alias Papyrus Scripts:
Scriptname W_QuenSign01Script extends ReferenceAlias
{Stops Quen Sign Effects after player is hit a certain amount of times.}
Quest Property W_QuenSign01Quest Auto
Spell Property W_SignQuen01 Auto
Int Property numHitsRequired = 3 Auto
Int numHitsCurrent = 0
Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked)
numHitsCurrent += 1
If numHitsCurrent == numHitsRequired
(Self.GetReference() as Actor).DispelSpell(W_SignQuen01)
W_QuenSign01Quest.Stop()
EndIf
EndEvent
Added the magic effect to the Spell (W_SignQuen01)
Option 2 (ReDragon2013)

Created a new Magic Effect (W_SignQuenEffect_1Script)

Archetype: Cloak

Casting Type: Concentration (required for cloak)

Delivery: Aimed (required for cloak)

 

Added you script to it's Parpyrus Scripts:

 

Scriptname W__QuenSignEffectScript01 extends activemagiceffect
{Quen Sign OnHit script}
Spell PROPERTY W_SignQuen01 auto
Keyword PROPERTY W_QuenSignKeyword auto
Int PROPERTY iMaxHits = 3 auto ; [default=3]
Int PROPERTY iHitCounter auto Hidden ; [default=0]
; -- EVENTs -- 3 + "Waiting"
EVENT OnEffectStart(Actor akTarget, Actor akCaster)
IF (akTarget == akCaster) && (akTarget == Game.GetPlayer())
ELSE
akTarget.DispelSpell(W_SignQuen01)
RETURN ; - STOP - not the player, remove this spell immediately
ENDIF
;---------------------
IF akTarget.HasEffectKeyword(W_QuenSignKeyword)
RETURN ; - STOP - effect is already running
ENDIF
;---------------------
gotoState("Waiting") ; ### STATE ###
Debug.Trace(" Effect started.. " +self) ; for debugging only
ENDEVENT
EVENT OnEffectFinish(Actor akTarget, Actor akCaster)
Debug.Trace(" Effect has been finished.. " +self) ; for debugging only
ENDEVENT
EVENT OnHit(ObjectReference akAggressor, Form akSource, Projectile akProj, Bool b1, Bool b2, Bool b3, Bool b4)
; received when this "object" is hit by a source (weapon, spell, explosion) or projectile attack
IF ( b4 )
RETURN ; - STOP - hit blocked
ENDIF
;---------------------
IF (akSource as Weapon)
gotoState("Waiting") ; ### STATE ###
myF_Action()
Utility.Wait(0.25)
gotoState("") ; ### STATE ###
RETURN ; - STOP - take the weapon effect only, not the enchantment hit
ENDIF
;---------------------
myF_Action()
ENDEVENT
;===========================
state Waiting ; look at papyrus source script "ActiveMagicEffect.psc"
;============
EVENT OnHit(ObjectReference akAggressor, Form akSource, Projectile akProj, Bool b1, Bool b2, Bool b3, Bool b4)
ENDEVENT
;=======
endState
; -- FUNCTION --
;--------------------
FUNCTION myF_Action()
;--------------------
iHitCounter += 1 ; counter +1
IF (iHitCounter >= iMaxHits)
GetTargetActor().DispelSpell(W_SignQuen01) ; GetCasterActor()
ENDIF
ENDFUNCTION
When I tried to cast the spell, i got a CTD. But it's not because of the script, I tested it without the scrip. This Quen Spell is marked as a Lesser Power, because the player will get it from a Perk (a spell flagged as "spell" won't show up in the menu after you get the perk). Maybe a lesser power can't cast a concentration/aimed spell?
Before it as flagged as "fire and forget" and "self"
Hope it didn't get confusing, haha
Link to comment
Share on other sites

On my option, you do not check the "start game enabled" box. The magic effect you created to hold the one script is to be added to your spell (lesser power). Thus it will run when the spell is cast.

 

One thing that you did not mention with either option is filling in the properties. Without filling in the properties, the script(s) cannot be expected to behave properly.

Link to comment
Share on other sites

Ha! You were right, I didn't fill the properties (I didn't even kown that I was supposed to do that, lol)

 

It's now working flawlessly :D

I also removed the "start game enabled" option as you said. Thanks you so much! I've been trying the whole day to make it work, lol

 

I also filled the properties for ReDragon2013, but instead of make it a cloak spell, I left it with "fire and forget" "self" to avoid the CTD. It also works fine as far as I can tell from the tests I've done. :D

Link to comment
Share on other sites

What's the benefit of creating a quest for a script attached to a spell?

 

Why not creating a spell, an attach a script to the magic effect and using an event like "OnEffectStart" or "OnAnimationEvent"

 

 

Now that I've read basically everything there is to be read about scripting, I'm about to create a thread with several intermediate to advanced question and this one if one of them.

 

I see that mods like this are always made with quests, like combat mods and stamina mods, but....

 

why making a quest that is always active instead of creating a script attached to an object?

 

why making something that will always be active and will consume more resources than making scripts based on events?

 

for mods that affect only the player stamina for example, why not attaching the script to the player reference? why the player actor has no scripts at all?

Link to comment
Share on other sites

What's the benefit of creating a quest for a script attached to a spell?

 

Why not creating a spell, an attach a script to the magic effect and using an event like "OnEffectStart" or "OnAnimationEvent"

 

 

Now that I've read basically everything there is to be read about scripting, I'm about to create a thread with several intermediate to advanced question and this one if one of them.

 

I see that mods like this are always made with quests, like combat mods and stamina mods, but....

 

why making a quest that is always active instead of creating a script attached to an object?

 

why making something that will always be active and will consume more resources than making scripts based on events?

 

for mods that affect only the player stamina for example, why not attaching the script to the player reference? why the player actor has no scripts at all?

 

Depends upon what one is doing to be honest. Perhaps there is data being used within the script that needs to be maintained across spell casts. This cannot be done solely within the magic effect script. Every spell cast is a new instance of the magic effect and the script has no clue about data on the previous instances. A quest allows one to retain and maintain information across multiple spell casts.

 

A spell with a magic effect having a script using OnEffectStart or OnAnimationEvent is totally fine. It depends upon the mod author's vision for their mod as to what they may need to use.

 

Waiting to see your thread... Would prefer to reply to your questions there rather than hijacking someone else's thread.

 

Objects get unloaded as the player leaves the area and there are a lot of script functions that will not run when the 3D is not loaded. Some stuff can be put on an object, but often times doing so makes the object persistent. Which again takes up resources. Better to put things on a quest that can be stopped and thus less likely to cause issues when the mod is removed (even tho it shouldn't be removed mid-game but people will be people).

 

The player should never have a script attached directly. If every mod that needed a script on the player were to attach directly, only the last such mod loaded would be able to work properly.

Link to comment
Share on other sites

Sorry but since his problem was solved...

 

Much thanks for your good willing to help me and a bunch of other new modders around here.

 

"The player should never have a script attached directly. If every mod that needed a script on the player were to attach directly, only the last such mod loaded would be able to work properly"

 

Why? And does other base objects works like this?,

 

an activator for example, if I attach more than one script to the activator, only the last one will work properly?

 

(Can't see why I would make more than one script instead of using states or different events though, but then the vanilla may already have some scripts attached to the object I'm trying to attach a script).

 

 

Edit: there's one thing I'm 99% sure but better safe than sorry. About base objects, references and object references. Let's see if I got it right... And my questions will depend on this answer...

 

A base object is whatever there is in the object windows, a reference is ONLY a base object that is placed in a specific location of world and has a X, Y, Z coordinate.

 

So let's say I create a book, and place it in 2 dungeons, one book in each dungeon, my book is a base object, and has 2 references.

 

A script(that extends book) attached to my book will work in both books, but if I want a script to only affect one of the books I must extend ObjectReference script and attach this script to the book? Is that right?

Edited by TruePooshmeu
Link to comment
Share on other sites

Create two plugins. Edit the same record on each plugin but edit something different. Load both side by side in SSEEdit. You will see that the last one loaded gets to have its data while the other one is unable to. This is why there are a plethora of patch plugins to make two or more mods work together.

 

If you are making a mod and want to have two or more scripts on a single object, you can do so. But if a second mod applies a script to the same object, only the last loaded mod gets to have its script attached. Another reason for using quests, assign the object to an alias, put the script on the alias and now no need to worry about another mod editing the same object and effectively removing the script.

 

You are correct about the books example.

Link to comment
Share on other sites

  • Recently Browsing   0 members

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