Limiting custom Lesser Powers to X times per day

Post » Sun May 18, 2014 2:26 am

Hello everyone,

I am in the process of creating a Mod which adds numerous magical items to the game and am looking for some help. These items, when equipped, add abilities to the player (in the form of a Lesser Power) which mimic various standard and custom spell effects.

For example:

Ring of Firebolt - the player can launch a Fire Bolt (per the spell)

Ring of Fire Cloak - the player can activate a Fire Cloak (per the spell) for 1m or so

Amulet of Healing - the player can heal themselves

My challenge is that I would like to balance these magic items by only letting the player use the power a certain # times per day, or have to wait a certain # seconds or minutes between uses.

My first question is, does anyone know how to temporarily "disable" a Lesser Power? Ideally, I'd just like to have it greyed out in the magic menu and when you press your "activate" button, nothing happens.

My next question is, how might I go about timing the use of an item?

I have tried a couple of methods, with only limited success:

1) used a timed magic effect - when the Lesser Power's spell is cast, in addition to the Item's main effects (like a firebolt, cloak, or healing), have a "recharge" magic effect on the player. If this recharge effect is present, do not do the item's main effects. This works well if the item only effects the player (healing, cloak, etc) - although the "spell" is still cast - it just does nothing. This does not work if the magic effect is targeted.

2) use a script and global variables - the idea being when the Lesser Power is cast, a global variable is updated to the current time. If not enough time has past, do not fire the spell. I have not got this to work as my scripting talents are very rusty. I have not been able to detect when the spell is cast (and thus set the variables), let alone figure out how to prevent the spell from being cast in the first place!

Does anyone have any ideas or experience with this?

The community's help is much appreciated!

User avatar
Tina Tupou
 
Posts: 3487
Joined: Fri Mar 09, 2007 4:37 pm

Post » Sun May 18, 2014 6:41 am

-Create a global variable called AllowSpell01, set the value to 1.0 (true)

-Add this condition to your MagicEffect in the upper-right corner of the MagicEffect Window:

GetGlobalValue AllowSpell01 == 1.0

-Attach this script to the Magic Effect in the script section below the effects list.

Scriptname testScript extend ActiveMagicEffectGlobalVariable AllowSpell01Event OnEffectStart(Actor akTarget, Actor akCaster)  AllowSpell01.SetValue(0.0)  registerForSingleUpdateGameTime(24.0) ;twenty-four hoursEndEventEvent OnUpdateGameTime()  AllowSpell01.SetValue(1.0)EndEvent

Edit: I don't think there's any way to change the UI (i.e. greying out powers when they cant be used) without some very complex scripting, and I wouldn't know where to start for that. However, you could easily send a message to the user by adding a second "dummy" magic effect to the spell that doesn't have any conditions (meaning it will still fire when the global == 0). Make that second magic effect of the "script" type, and then add a script similar to the one above, except OnEffectStart() it would just check whether AllowSpell01 == 0.0, and if so, send a message to the screen (e.g. "you have already used this power today").

User avatar
Emerald Dreams
 
Posts: 3376
Joined: Sun Jan 07, 2007 2:52 pm

Post » Sun May 18, 2014 1:05 am

Thanks for your reply - this idea has helped me progress quite a bit! I am still having some issues, however.

I've tweaked your code a bit and it is working well for my first test, which is a Ring of Summoning (Flame Atronach). In my test, the update gets registered promptly and ultimately gets run on-time.

My second test, a Ring of Destruction (Firebolt) - which essentially just lets you fire off a firebolt at a target, is a bit more perplexing. If you target a non-actor target (ie the ground, or a tree), the spell fires off just fine and no update event - as if the script is not run. If you fire it at an actor target (like a follower or an enemy), the register event happens. Now a couple of wierd things happen: 1) you can continue to fire the spell, which the visual effects still run, but no damage is applied to your target; 2) the registered event never completes (I use a couple minute gametime for testing).

Below is the script that I'm using so far. I had to add the "Property" part to the GlobalVariable in order to make it work... but that was good as I am building this to work with multiple item types, multiple global variables, and multiple recharge times anyways! :smile:

Scriptname GBobMagicItemRecharge extends ActiveMagicEffect;===============================================import utility;===============================================GlobalVariable Property RechargeVar AutoFloat Property RechargeTimeHrs AutoEvent OnEffectStart(Actor akTarget, Actor akCaster)	Wait(0.5)	RechargeVar.SetValue(0.0)     ; item power is recharging and may not be used	registerForSingleUpdateGameTime(RechargeTimeHrs)	Debug.Notification("Item is now recharging..." + RechargeTimeHrs + "hrs" )EndEventEvent OnUpdateGameTime()	RechargeVar.SetValue(1.0)     ; item power is now ready to use	Debug.Notification("Item is ready to used again!!")EndEvent

As a side note, at least with the Ring of Summoning, the lesser power is greyed out in the magic menu while the item is recharging. I"m not sure how or why that is happening, but it is what I want in the end - maybe just a happy coincidence.

Does anyone have any further ideas on how to solve the perplexing issues I am seeing?

As a thought - is there a good way to simply detect when a spell is being cast (or a Lesser Power is being used) - trap on that and set the global variables?

Again, thanks for the help so far - the Skyrim modding community is fantastic!

User avatar
Maria Garcia
 
Posts: 3358
Joined: Sat Jul 01, 2006 6:59 am

Post » Sat May 17, 2014 10:30 pm

I might have a guess at part of what is going on.

1) Event OnEffectStart will not run unless you hit at actor.

I believe Event OnInit() will immediately trigger as your spell is cast.

2) When the spell effect is dispelled, your update registration unregisters.

This one might require a bit more scripting. One idea I have is to call a function from a quest script. Create your own quest, have it start game enabled, and attach a script to it.

Scriptname _test_testscript extends ActiveMagicEffect_test_testquest Property YourQuestNameHere AutoEvent OnInit()    YourQuestNameHere.RegisterFireball()endEvent
Scriptname _test_testquest extends QuestGlobalVariable Property kFireRecharge AutoFunction RegisterFireball()    kFireRecharge.SetValue(1.0)    RegisterForSingleUpdateGameTime(24.0)endFunctionEvent OnUpdateGameTime()    kFireRecharge.SetValue(0.0)endEvent

3) Sounds like the projectile is firing but the magic effect isn't actually getting applied because the condition failed. Here's an idea though...

Remove the condition function from the magic effect window. Put it in the Spell window instead where you select what magic effects you want (and their duration/magnitude/etc). Then (this part may or may not be needed) add a second magic effect with the opposite condition (ex: GlobalVariable == 0). In the dead magic effect, use an empty projectile (there are a few premade ones) and remove all the hit FX. Select script as the archetype (and don't attach a script, or attach one and tell is to play a message with the OnInit event saying the spell is on recharge). Hopefully instead of firing a harmless fireball, it will fire an invisible spell effect.

If you still want to do the idea where the player can only use it a certain amount of times per day, but each instance has its own recharge, scripting that could be a bit trickier. You can only register for one update game time in a script so you'd have to get creative. Let me know if you need help with that idea; I think I got something in mind.

User avatar
Add Me
 
Posts: 3486
Joined: Thu Jul 05, 2007 8:21 am

Post » Sun May 18, 2014 12:50 am

Thanks for the help so far - I think we are on the right track!

egocarib - your initial idea really got me off on the right foot and I may utilize those thoughts in other areas of my mod!

Currently, I am going with the last idea from mojo22... which is to utilize two separate spells. This roughly follows the logic:

1) the Lesser Power casts a spell which has a single Magic Effect which simply calls the script listed below

2) the script tests to see when the lesser power was last used

2a) global variables for each of the possible magic items are defined to ultimately store when the item was last used

2b) if the item was last used long enough ago (ie current time - last used time > recharge time), the real spell is cast

2c) if the item is still within its recharge period, nothing happens (might work on adding a fail sound effect, etc)

This method is working great so far. It has the advantage of preventing the end-spell from being cast (if the item is still recharging) and it works with all spell types so far that I've tested (spells cast on yourself, targeted spells).

Below is my current working script.

Scriptname GBobMagicItemCastSpell extends activemagiceffect  GlobalVariable Property LastTimeUsed Auto			; Last Time item was usedSpell property SpelltoCast1 auto						; which spell we are ultimately going to castFloat Property RechargeTimeMin Auto				; recharge time (in game minutes) until usable againInt Property SpellType auto							; 1=Self, 0=TargetedFloat MinSinceLastUsedFloat RechargePercentEvent OnEffectStart(Actor myTarget, Actor myCaster)	; calculate # minutes since item was last used	MinSinceLastUsed = (Utility.GetCurrentGameTime() - LastTimeUsed.GetValue()) * 24 * 60	RechargePercent = (MinSinceLastUsed / RechargeTimeMin) * 100	If ( RechargePercent > 100 )		RechargePercent = 100	EndIf	;Debug.Notification("Item was last used: " + MinSinceLastUsed + " min ago")	If ( MinSinceLastUsed > RechargeTimeMin )		; item is recharged and ready to use		Debug.Notification("Activating Item's Power...")		; cast actual spell		If ( SpellType == 1)			SpelltoCast1.Cast(myCaster, myCaster)		Else			SpelltoCast1.Cast(myCaster, myTarget)		EndIf		; set item to be recharging		LastTimeUsed.SetValue(Utility.GetCurrentGameTime())     ; item power is now recharging	Else		; item is recharging and may NOT be used yet		Debug.Notification("This item is recharging and may NOT be used yet. " + RechargePercent + "%")		; maybe play some cool wa-wa-waaaah sound/visual effects	EndIfEndEvent

Thanks to everyone for their help so far - I'll continue tweaking the script as I update my Mod (I have *many* magic items with unique powers)!

A couple of followup questions if anyone has some knowledge to share...

1) In the above script, how do I play an "item is recharging - fail" sort of sound (I assume I can find one in the creation kit to use)?

2) I've read about, but am unfamiliar with, techniques to make the above script play nicer with the overall game (including if the mod is undeleted, etc). I *think* the above script only runs for a max of 1 second (the duration of the magic effect that calls it) and therefore it does not persist, but I want to make sure. Any ideas?

Thanks!

User avatar
Mélida Brunet
 
Posts: 3440
Joined: Thu Mar 29, 2007 2:45 am

Post » Sat May 17, 2014 10:19 pm

Looks like you've got a well-constructed script there. Glad things are working now!

Regarding sounds, the easiest method would be to use some pre-existing sounds in the CK. Head to the "Sound Descriptor" section and you will be able to open up and test-play any of the sounds from the game. The sounds that start with MAG might be your best bet, as those are the sounds associated with magic-related stuff (although sounds starting with NPC also have some good stuff--all the weird creature sounds are here). You can play with frequency and such to change the dynamics of each sound. Once you find one you like, duplicate it and give it your own name, then create a new "Sound Marker" and point it toward your Sound Descriptor. You will be able to fill a property in your script with that sound marker using the Sound-type variable (e.g. Sound property mySpellSound auto). You can then use the command mySpellSound.play() to play the sound. See the wiki's page on http://www.creationkit.com/Sound_Script for more info.

You can also use visual effects if you want (noticed your script comment). One idea you might find useful: I wanted some visual effects too, so I recently made a simple script that used a formlist of all the EffectShaders in the CK and played them one by one on my character every few seconds (also did the same with visual effects). Was an awesome way to see all the possible effects that you can play on the player (or other NPCs). if you include a debug.notification for each new effect telling you the index number in the formlist, you can write down the ones you like and go back to your formlist to find out which ones they were afterward, and add them to your script. (Effect shaders are good place to start, they have some great visuals and are also easy to modify the color and other attributes in the CK).

Regarding script and uninstall: The script will "run" as long as the magic effect lasts, even if it's not doing anything. It should definitely "play nice" with anything else, though, no need to worry there (especially if these are new effects unique to your mod). For uninstall, just be sure to tell people to check their active effects window and make sure they don't have any active magic effects from your mod still active on their character when they uninstall. If they do that, it should be a relatively safe uninstall. Scripts will always technically exist in a save game even after uninstall, but something like this wont do any harm if the effects are dispelled before uninstall.

User avatar
Mario Alcantar
 
Posts: 3416
Joined: Sat Aug 18, 2007 8:26 am

Post » Sun May 18, 2014 10:13 am

If you're interested, here is the EffectShader script (easily adaptable to VisualEffects, Hazards, Explosions, etc).

Spoiler
Scriptname FXShaderTestScript extends referenceAlias{you will have to create a start-game enabled quest with a reference alias for the player, then attach this script to the reference alias}ObjectReference property playerRef autoFormlist property FXShadersList autoint FXindex = -1   ;will be incremented to start at zero before first shader playsint newIndexEvent OnInit()  registerForSingleUpdate(3.0)EndEventEvent OnUpdate()    ;How this script works:  ;  ; It will begin playing FXShaders on the player when the game boots up, proceeding one  ; by one through FXShadersList.  ;  ; Crouching will cause the script to pause at the current FXShader and keep playing it  ; (in case you see something you like and want to take a longer look at it)  ;  ; opening the console and typing "player.setav variable09 " will cause the script  ; to jump to the FXShader indicated by . It will then proceed playing forward  ; one by one through the formlist again.playerRef.setActorValue("Variable09", -1.0)   ;default valuewhile FXindex < 500 newIndex = playerRef.getActorValue("Variable09") as int if newIndex >= 0   FXindex = newIndex   playerRef.setActorValue("Variable09", -1.0)   ;set back to default elseif playerRef.isSneaking()   ;pause FXindex else   FXindex += 1   ;normal increment endif (FXShadersList.GetAt(FXindex) as EffectShader).Play(playerRef) debug.notification("FX Shader number " + FXindex) utility.wait(4.0) (FXShadersList.GetAt(FXindex) as EffectShader).Stop(playerRef)endWhileEndEvent
User avatar
CArla HOlbert
 
Posts: 3342
Joined: Wed Feb 21, 2007 11:35 pm


Return to V - Skyrim