ryanshowseason2 Posted September 5, 2012 Share Posted September 5, 2012 Hey all, I'm a programmer by trade but just starting out in the world of skyrim. I'm looking to script some neat stuff related to shouts. Basically I just want to make each shout have a mutually exclusive cooldown. I was figuring on storing each current cooldown value in an array and swapping each one in on equipping the shout. Then creating some timer that would manually decrement all cooldowns in the array and set the cooldown timer on the ui. Problem is I'm unsure as to how to accomplish this. I'm not even sure I can trigger the OnSpellCast event for "shouts" Does it only work for the spells that the shouts use? If it does how can I find the associated cooldown I should place in the array? I'm just jotting down some cursory code which probably isn't anywhere close to feasible. So where is my idea flawed so far? float[] shoutCooldowns = new float[20] Event OnSpellCast(Form akshout) Shout spellCast = akshout as Shout // Can I even get a shout object out of that form? or is it always a spell? Is there an OnShoutCast? if akshout && akshout == BecomeEtherealShout // checking for null? shoutCooldowns[0] = akshout.GetCooldown() //?? dunno how to get at this Link to comment Share on other sites More sharing options...
steve40 Posted September 5, 2012 Share Posted September 5, 2012 (edited) Hmm... something like this would be a compact way of doing it. I haven't tested it, and don't know if it's possible to fetch the cooldown time. I'm assuming that shouts are really spells. I'm also not sure if the cooldown time can be modified using scripts. REQUIRES SKSE. Oh, you can only define arrays like you did above within functions or blocks. ScriptName ShoutCooldownScript extends ObjectReference float[] Property shoutCooldowns auto ; define the array as a property, and set its default values in the CK using the Properties button spell[] Property shoutFormArray auto ; life will be easier if you also put all the shouts into an array (use the Properties button in CK) Event OnSpellCast(Form akshout) Spell spellCast = akshout as Spell If spellcast != None ; ignore potions, enchantments, etc int i = shoutFormArray.length While i > 0 i -= 1 If spellcast == shoutFormArray[i] debug.messagebox("[shoutCooldownScript]) Shout spell " + shoutFormArray[i] + " was detected!") shoutCooldowns[i] = spellcast.GetNthEffectDuration(0) //requires SKSE. Dunno if this is the right function for shouts Return ; our job is done, so we don't need to process the rest of the array EndIf EndWhile debug.messagebox("[shoutCooldownScript]) A spell was cast, but it was not recognized as a shout.") Else debug.messagebox("[shoutCooldownScript]) Something was cast, but it was not a spell.") EndIf EndEvent Edit: fixed some errors. Edited September 5, 2012 by steve40 Link to comment Share on other sites More sharing options...
steve40 Posted September 5, 2012 Share Posted September 5, 2012 (edited) Just realized that you get the shout cooldown time like this: game.GetPlayer().GetVoiceRecoveryTime() and you set it like this: game.GetPlayer().SetVoiceRecoveryTime() This doesn't allow for setting individual spells. So what you need to do is to set recovery time to ZERO, then use the script to set timers for each individual shout, and block the shouts if the timer hasn't expired. So you will need to save the time that each shout was cast into a third array, so that you can check it against the cooldown array on each attempted cast. Edited September 5, 2012 by steve40 Link to comment Share on other sites More sharing options...
ryanshowseason2 Posted September 6, 2012 Author Share Posted September 6, 2012 Thanks for the reply! Hmm nice idea there. I'm unfamiliar with setting these arrays up but I think I'll figure it out. I was thinking of preventing them from using the shout again by detecting which shout is equipped though. Any idea if Event OnObjectEquipped(Form akBaseObject, ObjectReference akReference) detects spells as well as weapons? After that I was going to handle all the cooldowns in the array myself with some other function running on a timer... if that makes any sense in papyrus land. Link to comment Share on other sites More sharing options...
steve40 Posted September 6, 2012 Share Posted September 6, 2012 (edited) Any idea if Event OnObjectEquipped(Form akBaseObject, ObjectReference akReference) detects spells as well as weapons? Interesting idea. I don't know if it will work, but conceptually I think it should. However, I wonder if this block will detect when voice slots are equipped, or whether it only applies to armor and weapon slots? Try something like this: Event OnObjectEquipped(Form akBaseObject, ObjectReference akReference) If akBaseObject as Weapon Debug.MessageBox("This actor just equipped a weapon!") ElseIf akBaseObject as Spell Debug.MessageBox("This actor just equipped a spell!") EndIf EndEvent I'm not sure if you can cast akBaseObject as a shout, but you might like to try that also. Edit: a possible alternative would be to create a quest, then add an alias for every shout, then add a script with "OnEquipped" block in it to each shout alias . When this block is triggered, it could call a custom function on your shout script to let it know that it has been equipped. Edited September 6, 2012 by steve40 Link to comment Share on other sites More sharing options...
ryanshowseason2 Posted September 6, 2012 Author Share Posted September 6, 2012 Good point, I keep forgetting these are shouts and not really spells. The spell is just being cast. I'm not sure if its being equipped at all or if that can be detected. It might be too late by the time it is... By the text in the CK it indicates that the spell is simply cast based on what word is activated, I'd likely have to try and detect when a shout is equipped and not a spell. Link to comment Share on other sites More sharing options...
Cipscis Posted September 6, 2012 Share Posted September 6, 2012 OnEquipped is only called on ObjectReferences, which includes inventory items like equipment but not other equippable Forms like Shouts and Spells. While it's entirely possible to define such an event in a script extending Shout or Spell, the game engine will never call it on those forms so it won't act as the entry point you're looking for there, unfortunately. Cipscis Link to comment Share on other sites More sharing options...
ryanshowseason2 Posted September 6, 2012 Author Share Posted September 6, 2012 (edited) Hmm Can I add multiple instances of a shout to an array consecutively? For the shoutFormArray I'd add three instances of each shout so I could match it up to the cooldowns and spell form array since there are three spells for every shout! float[] Property shoutCooldowns auto ; storing the cooldowns here. spell[] Property shoutSpellFormArray auto ; for detection of casting shout[] Property shoutFormArray auto ; for the on update function detection of which shout is equipped. Since the spell isn't equipped the 'shout' is. Event OnUpdate() ; register for updates every second Shout equipped = game.GetPlayer().GetEquippedShout() ;right about here loop through the shoutFormArray to match up the equipped to one of the known shouts. Then use that index to look and see if there is already a cooldown here. Set the cooldown via the setshoutcooldown function. ; right about here increment through the shout cooldowns array and decrement each by one if > 0 EndIf EndEvent Also I'm thinking of adding a case where if you increment through the entire shout list without finding a match a backup index in the cooldowns array is used instead, this would be for use with shouts created by other mods but I don't know how to detect when they are used in order to set the value... I don't know the order in which things happen but it may be possible that the shout cooldown is set by the time the onspellcast event is activated. If I detect that the shout cooldown is non zero without detecting one of the base game shouts I might be able to fill that backup index in... Just theory crafting though, does this approach make sense? hmmm is there a way to get the equip type out of a spell? I noticed that the shout spells are in a seperate section in the ck. Edited September 6, 2012 by ryanshowseason2 Link to comment Share on other sites More sharing options...
jshepler Posted September 9, 2012 Share Posted September 9, 2012 Interesting, I have the same basic idea. Here's what I've got so far... ScriptName sgc_PlayerAliasScript Extends ReferenceAlias { detects equipping/casting shouts and manually manages the global cooldown } Actor player Shout[] shoutArray Float[] recoveryArray Float[] timestampArray int howManyStored = 0 int MAXNUMBER = 128 Event OnInit() player = GetActorReference() shoutArray = New Shout[128] ;MAXNUMBER recoveryArray = New Float[128] ;MAXNUMBER timestampArray = New Float[128] ;MAXNUMBER EndEvent ; ReferenceAlias scripts receive ObjectReference events ; shouting triggers OnSpellCast for the spell on the shout word ; record currently equipped shout and current recovery/time Event OnSpellCast(Form akSpell) Spell sp = akSpell as Spell ;TODO: determine if spell type is "Voice Power" bool isVoicePower = (sp != None) If isVoicePower Shout currentShout = player.GetEquippedShout() Float recovery = player.GetVoiceRecoveryTime() ;seconds Float timestamp = Utility.GetCurrentRealTime() ;seconds int found = shoutArray.Find(currentShout) If found == -1 If howManyStored < MAXNUMBER shoutArray[howManyStored] = currentShout recoveryArray[howManyStored] = recovery timestampArray[howManyStored] = timestamp howManyStored += 1 EndIf Else recoveryArray[found] = recovery timestampArray[found] = timestamp EndIf EndIf EndEvent ; ReferenceAlias scripts receive Actor events if pointing to an Actor ; equipping shouts triggers OnObjectEquipped, contrary to what wiki says ; check if equipped shout in array, calc/set remaining recovery Event OnObjectEquipped(Form akBaseObject, ObjectReference akReference) Shout theShout = akBaseObject as Shout If theShout Float newRecovery = 0.0 int found = shoutArray.Find(theShout) If found >= 0 Float now = Utility.GetCurrentRealTime() ;seconds Float diff = now - timestampArray[found] If diff < recoveryArray[found] newRecovery = recoveryArray[found] - diff EndIf EndIf player.SetVoiceRecoveryTime(newRecovery) EndIf EndEvent It mostly works. I'm stuck at determining if the spell being cast is of type "Voice Power". On the other hand, the way this is coded, it might be ok that we don't know. If you cast a normal spell, it'll will save the current shout/recovery/time. If recovery is 0, then 0 is stored and nothing breaks. If recovery > 0, it gets saved as if you had shouted but it's still going to be an accurate value as far as how much recovery is left for the currently-equipped shout. So again, I don't think anything breaks here. I haven't fully tested this out yet by watching all the data being tracked and making sure it's all working as intended, but the core idea appears to be working. Link to comment Share on other sites More sharing options...
jshepler Posted September 9, 2012 Share Posted September 9, 2012 I should add that the script is attached to a reference alias, set to the player, on a "hidden" quest. I don't know if I create the quest correctly or not. I just started learning this stuff yesterday, so please forgive any noobish mistakes I made - but please let me know of them. - new quest- set ID and uncheck "Run Once"- save (*)- on quest aliases, add new reference alias- set name- set Fill Type to Specific Reference- click Select Forced Reference- set Cell to (any)- wait a bit- ref should set itself to PlayerRef ('Player') by default, select it if not- save (*)- add script to the reference alias (*) On my first attempt, I created the quest, alias, added the script and then clicked OK all the way out and CK crashed on me. I read that if you create the quest and save it (and your active file) before adding the script, it won't crash. I tried that and it worked. Link to comment Share on other sites More sharing options...
Recommended Posts