AnimeOtaku102 Posted November 20, 2013 Share Posted November 20, 2013 Well, this is somewhat annoying, but I've been working on a mod that attaches a script to a piece of armor that adds a spell ability to the character when it is equipped; the ability, in turn, tracks OnHit events on the player and directly changes values in the armor's script as well as the armor itself. An example of the script is as follows: Scriptname armorTestScript extends Armor Armor Property armorRef Auto Spell Property spellRef Auto int count Event OnEquipped(Actor akActor) debug.notification("Armor equipped.") akActor.AddSpell(spellRef, false) endEvent Event OnUnequipped(Actor akActor) debug.notification("Armor unequipped.") akActor.RemoveSpell(spellRef) endEvent Scriptname aaDAFEffectScript extends ActiveMagicEffect armorTestScript Property armorScriptRef Auto float temp Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked) Actor actorRef = GetTargetActor() if ((abHitBlocked != true) && (akProjectile == None)) debug.notification("Damage taken.") if (abPowerAttack == true) armorRef.count += 1 endif endif if (armorScriptRef.count > 5) temp == armorRef.GetItemHealthPercent() if (temp > 1.0) armorRef.SetItemHealthPercent(temp - 0.1) endif armorScriptRef.count == 0 endif endEvent Basically in this iteration it's just a simple mod to track how many times the PC gets smacked by a power attack, if they get hit more than five times (and didn't block), the armor loses a tempering level; the magic effect script directly alters the armor script's count variable so the "damage" persists (no taking the armor off after four power attacks to reset the progress). Now the problem is if I extend the first script to Armor, OnEquipped and OnUnequipped don't work, which pretty much screws the mod over since I can't add the spell ability; however if I extend it as an ObjectReference I can't assign the armor to the magic effect script's property because it wants a Cell and Reference (presumably a piece of furniture, because I get the option to pick the object from the render window, but refuses to list the armor as an option) instead, which also screws the mod over because now the spell ability is added but never triggers because it doesn't know what armor (or actor that has the armor equipped) to track. Is there any way for an Armor script to use OnEquipped/OnUnequipped or an ObjectReference script to accept an inventory item as a property? Thanks in advance. Edit: main reason I wanted to do it this way is so multiple instances of the same armor equipped by the PC and NPCs can be tracked separately, without having to resort to some kind of global variable shuffling (though I suppose I would have to do that if there's no other way) that might lead to incorrect values being passed around. Link to comment Share on other sites More sharing options...
Xander9009 Posted November 20, 2013 Share Posted November 20, 2013 First, a question. Was either 'armorRef.count += 1' or 'armorScriptRef.count == 0' atually working? I ask because count isn't a property and I didn't think a normal variable could be accessed from outside the script. Second, you could forget about the setting the armor as a reference. Instead, set a globalvariable or a quest script which both the armor and the effect access. In fact, using a question script, you could forget about the magic effect altogether. In the armor script, then, instead of adding the spell, you could set the script's variable (possible: 'Bool IsWorn' or something) to true and false as the armor is equipped and unequipped. And the armor script can actually change its own tempering grade. You might be forced to do this anyway since (I could be wrong about this) the ActiveMagicEffect's event OnHit won't fire since OnHit is an ObjectReference event. It needs to be on an ObjectReference, not a magic effect. But, using the quest, you can set an alias to apply to the player and run the script on the player directly. If you decided to go this route, you'd need to make a quest and check Star Game Enabled. Make an Reference Alias, set it to specific alias, force that specific alias to the player (by choosing "Cell: Any"), and attach your magic effect script to the alias. That script would need to be altered slightly. Scriptname aaDAFEffectScript extends ReferenceAlias aaDAFQuestScript Property aaDAFQuest Auto Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked) If ((aaDAFQuest as aaDAFQuestScript).IsWorn == True) if ((abHitBlocked != true) && (akProjectile == None)) debug.notification("Damage taken.") if (abPowerAttack == true) (aaDAFQuest as aaDAFQuestScript).Count += 1 endif endif EndIf endEventOn the Script tab for the quest, add a new script called aaDAFQuestScript ScriptName aaDAFQuestScript extends Quest Int Property Count Auto Bool IsWorn And the armor script would need to be changed to this Scriptname armorTestScript extends ObjectReference aaDAFQuestScript Property aaDAFQuest Auto Float temp Event OnEquipped(Actor akActor) debug.notification("Armor equipped.") RegisterForSingleUpdate(2) (aaDAFQuest as aaDAFQuestScript).IsWorn = True endEvent Event OnUnequipped(Actor akActor) (aaDAFQuest as aaDAFQuestScript).IsWorn = False endEvent Event OnUpdate() if ((aaDAFQuest as aaDAFQuestScript).Count > 5) temp == armorRef.GetItemHealthPercent() if (temp > 1.0) armorRef.SetItemHealthPercent(temp - 0.1) endif (aaDAFQuest as aaDAFQuestScript).count == 0 endif If ((aaDAFQuest as aaDAFQuestScript).IsWorn == True) RegisterForSingleUpdate(2) EndIf EndEvent You might be able to access the alias script directly, but I don't know how. This way, the quest has a small script which is nothing but a communication line between the armor and the player scripts. The player script registers the OnHits and increments the count if the armor is on. The armor updates every two seconds while it's worn and lowers its own health if the count is over 5 and resets the count. If you notice it starts slowing the game down, you can raise the update interval so it updates less often. If you notice it's not counting correctly when attacked in rapid succession, you can lower the update interval so it updates more often. Also, I put in the ReferenceAlias in the "extends" section of the player alias manually. I mention it because it might be backwards. It might need to be AliasReference. Let me know if that works or if you don't want to try it. Oh, and as an additional note, if you WANT the spell effect, you can still add it so the player can see it's on there. It just won't actually be used for anything. Link to comment Share on other sites More sharing options...
AnimeOtaku102 Posted November 20, 2013 Author Share Posted November 20, 2013 Whoops, actually that line should be "int count Auto", which makes it a property accessible outside the script; I also believe OnHit will work with ActiveMagicEffect much in the same way it does with ReferenceAlias from what I've been reading, since they're both treating the actor they're pointing at as the object in question (ReferenceAlias has to specify the object via the Quest Alias tab, while ActiveMagicEffect uses the target it's cast on as the object), though admittedly I haven't had the chance to try due to this "extends Actor/extends ObjectReference" issue. The previous version of this script I'm working on actually used the Quest method, but the problem I ran into that is if I want it to work with NPCs, I'll need to create a new Quest Alias for each unique NPC, which is a bit of a pain and also makes it incompatible with custom NPC companions; I asked in this forum if there was a way to dynamically assign which NPC to track and was pointed toward a slaving mod, but couldn't figure out how to get that to work with my mod (if it was possible at all), so I decided to try this armor/magic effect method instead. Everything would be so simple if OnHit automatically tracked the actor wearing the object it's attached to :pinch: Link to comment Share on other sites More sharing options...
Xander9009 Posted November 20, 2013 Share Posted November 20, 2013 If you're wanting it to work with other NPCs, then there are a couple ways you could do it using a quest. If there'll only be one instance of the armor, then just have the armor ForceRefToAlias or ForceAliasToRef (I don't remember which it is) and fill an alias with the person equipping it. If there'll only be a limited number, you could do the same thing, but check to see if an alias is filled already. If it's not filled, fill it; if it is filled, move on to the next one. But anyway, so long as the OnHit will work, then I'm not sure why this isn't working. I tried pasting your first script and compiling and it compiles without a problem. It's currently extending Armor and is using OnEquipped(). Or did you mean that while it does compile, it doesn't function in game? I'm a bit confused about exactly what's going wrong, so I'm not sure about where precisely to look for a solution. Link to comment Share on other sites More sharing options...
AnimeOtaku102 Posted November 21, 2013 Author Share Posted November 21, 2013 Yeah, that's the problem, when it's compiled as extending Armor it fails to work in-game; the only event listeners that work are universal ones like OnInit, but none of them (what few there are) are of any use. It appears the engine doesn't recognize Armor as a type of ObjectReference, so it might just be a lost cause. I'll just have to go with something using global variables and hope no weird Skyrim magic causes the wrong value to be written/read between OnEquipped/Unequipped and OnEffectStart/Finish events. I'm probably just being paranoid. Scriptname armorTestScript extends ObjectReference Spell Property spellRef Auto GlobalVariable Property currentCount auto int count Event OnEquipped(Actor akActor) debug.notification("Armor equipped.") currentCount.SetValueInt(count) akActor.AddSpell(spellRef, false) endEvent Event OnUnequipped(Actor akActor) debug.notification("Armor unequipped.") akActor.RemoveSpell(spellRef) count ==currentCount.GetValueInt() endEvent Scriptname aaDAFEffectScript extends ActiveMagicEffect Armor Property armorRef Auto GlobalVariable Property currentCount auto float temp int count Event OnEffectStart(Actor akTarget, Actor akCaster) count ==currentCount.GetValueInt() endEvent Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked) Actor actorRef = GetTargetActor() if ((abHitBlocked != true) && (akProjectile == None)) debug.notification("Damage taken.") if (abPowerAttack == true) count += 1 endif endif if (count > 5) temp == armorRef.GetItemHealthPercent() if (temp > 1.0) armorRef.SetItemHealthPercent(temp - 0.1) endif count == 0 endif endEvent Event OnEffectFinish(Actor akTarget, Actor akCaster) currentCount.SetValueInt(count) endEvent Link to comment Share on other sites More sharing options...
Xander9009 Posted November 21, 2013 Share Posted November 21, 2013 Trying to think of a way for this to work for any number of NPCs and all I can come up with is an array or a formlist. The formlist would be tricky, but the array should work. You can look up arrays on the CK website. They're declared with 'Float[] NameOfArray' (and obviously replace Float with whatever variable type you need). They're accessed by calling 'NameOfArray[7]' or whatever number you need for the index of the variable (they start at 0). This would require a quest again, since the array would have to be universally accessible. I don't think you can use a global variable as an array or that would be even easier. But, doing it that way, you could make a set of functions in the quest script to handle passing information from the armor to the MagicEffect. The armor would check an array for the first available slot and fill it. When it fills it, it would mark an int Busy to the array index of the value stored by the armor. When the MagicEffect starts, it would wait for that busy int to be filled with a number, and then store that number and set Busy back to -1. Now, both the armor and the effect can communicate with one another. If you make it so the armor doesn't apply the effect until it has verified Busy is -1 and it can change it, the the magic effects wouldn't interfere with one another. Make sense? It the best way I can think of to make it work for an unlimited number of NPCs. And if you stored the armor's ID in that array, and in a secondary array kept track of the armor's hits until damage, then you could make it so the armor being unequipped and re-equipped wouldn't reset the count. Because the armor could scan for its ID in the array before filling an empty slot. Link to comment Share on other sites More sharing options...
AnimeOtaku102 Posted November 21, 2013 Author Share Posted November 21, 2013 Hm, yeah, I understand what you're saying, basically the array will act as a global variable and the quest will just function like a router to make sure the armor and magic effect scripts are paired up to the same entry in the array. The only limitation I can see would be that you have to declare the size of the array in the CK, but realistically speaking it's unlikely you'll ever see more than a handful of NPCs wearing this armor at a time, so it's a moot concern. Thanks for the help, it's quite a lot to think about. Link to comment Share on other sites More sharing options...
Xander9009 Posted November 21, 2013 Share Posted November 21, 2013 If you do decide to use the arrays, you should safely be able to set it to its max of 128. If you wanted even more, you could consider using Chesko's array functions. http://forums.bethsoft.com/topic/1365378-exampleresourcegeneral-purpose-array-functions/ Link to comment Share on other sites More sharing options...
Recommended Posts