I will actually be writing a script soon with the same function but for a different purpose. I'll point out somethings I noticed.
Scriptname corePassiveReflectSpells extends ActiveMagicEffectActor Property player Auto ;;; Define this as the player in "any" cell, this is the most efficient way to do it.Event OnHit(ObjectReference akAgressor, Form akSource, Projectile akProjectile, Bool abPowerAttack, Bool abSneakAttack, Bool abBashAttack, Bool abHitBlocked) If akSource.GetType() == 22 || akSource.GetType() == 119 If akAgressor != player Spell reCast = akSource as Spell ;; not sure what this will do to shouts reCast.Cast(player, akAgressor) EndIf EndIfEndEvent
Now that doesn't help much with your issues. But I wanted to do that first to break it down my self.
This is from the wiki:
"Actor races can be set to cast magic only in the direction that the actor is facing; if the source is an actor with this racial setting, this parameter will be ignored."
I'm not 100% what there saying here but it sounds like your problem. Perhaps you can make an invisible object that appears at the player that will do a remote cast and blame it on you. You can also try out DoCombatSpellApply, I've never tried that before.
Looks like they changed how the cast function works. It used to not consume mana. You can do one of two things. You can get the mana pool before and after the cast then replace the mana, but this will require some temporary mana. Or you can use the function GetMagickaCost() on the spell and add the needed mana beforehand. I don't believe this gives the exact mana cost and I'm not sure how it works on channeled spells.
You could just use DispelSpell() after a set amount of time. Another method that may work is to find all the magic effects associated with the spell. Then compare those effect either against a formlist you build or a keyword. If it is a concentration spell, you cast it until HasMagicEffect no longer passes. The you dispel it. Not sure if that will work.
There is a way of fixing this I think may work. Basically you put OnHit in two different states. One fills an effect array by checking the effects associated with the spell and cast it, then it switches to the other state. The other state is an empty onhit command. You then use OnMagicEffectApply to check for each effect in the array then remove that effect as it passes. Once the array is empty again you switch back to the original state. Not sure how the timing of this would work. I can think of a few other crude ways to over come this.
I'm not sure what to do about the leveling issue, but where there's a will there's a way. Let me know if you make any progress on this. Like I said earlier, I will be attempting to do the same thing soon but for another purpose. If your still stuck I'll be writing the code for all this probably next weekend. Might be able to help each other. I know the explanations above can be hard to understand or put to use with out any real code.
Hey! Thanks for the detailed reply !
I'm not actually sure how I missed the part in that wiki about the spell going where the actor is facing. I read that block several times lol. Thanks for pointing that out.
So, I was reading your reply this morning on my tablet and noted the first suggestion of spawning an invisible. I realized that this actually might solve a lot of problems. For starters, it has the advantages of:
- It's an object we can control the location of, and delete when ready. Being able to be deleted, this actually has another added advantage of causing it to not sit there and channel forever.
- The object would be casting the spell and blaming me, it probably won't use my mana (And doesn't after testing).
- It's an object an not an actor and, like you said, doesn't suffer from the restriction of having to fire where I'm facing.
So here's what I changed so far, taking into account your advice on the player reference (Thanks for that, btw), also any input on how this could be done better is welcome. (Also got the code block to properly tab this \o/)
Scriptname corePassiveReflectSpells extends ActiveMagicEffect{Passive non-ward script to reflect any spell that hits the player.}Actor Property player AutoImport StringUtilEvent OnHit(ObjectReference akAgressor, Form akSource, Projectile akProjectile, Bool abPowerAttack, Bool abSneakAttack, Bool abBashAttack, Bool abHitBlocked) ;Debug.MessageBox("Hit by " + akAgressor + " using " + akSource + " and " + akProjectile) if akAgressor != player Int sourceType = akSource.GetType(); if sourceType == 22 || sourceType == 119 Spell recast = akSource as Spell if recast.IsHostile() ; Let's spawn an invisible object at the player from which we can cast the reflected spells. Form invisibleObjectForm = Game.GetForm(0x00109AC3) ; I'm going to make this a proper proptery in a bit. Testing for now first. ; Also need a better "invisible" object. This technically shows up for a min. ; Also noting that this is the form named MAGINVInvisibility static object. ObjectReference invisibleObject = player.PlaceAtMe(invisibleObjectForm) invisibleObject.MoveTo(player, 30.0, 30.0, 150.0) ; So, the object was too close to me and somewhat in the floor. ; When I got hit by something like a fireball, the reflected fireball ; hit me or the floor. This seems to be fixing it pretty good so far. recast.RemoteCast(invisibleObject, player, akAgressor) Utility.Wait(1) ; Keep the object spawned for a second so it actually has time to channel something meaningful. invisibleObject.Delete() ; Delete the object, we don't want to litter or cause turrets or endless channeling. EndIf EndIf EndIfEndEvent
So, this seemed to fix most of my problems. The leveling still exists from what I can tell, but honestly it doesn't bother me that much. I could probably fix the leveling by changing it to a Cast instead of RemoteCast (I don't really care about getting credit, unless there's some benefit I'm not realising).
OnHit still seems to get called, but I would expect this (We're just spawning an object, and not doing anything to throttle that to once per actual spell instead of once per magic effect). I'm not exactly sure how to implement the suggestions you had, however from my understanding a form list and a keyword check, these may make this not take into account new spells from mods since the creator may not add keywords that I use or I would have to add their spell to the list and create a compatability patch of sorts containing the new form list. If possible I'd really prefer it to reflect pretty much any damaging spell that hits me (Which reminds me, that is another thing I actually need to check for, IsHostile, but I'll add that in a bit. It looks easy enough).
Another bug that seems to have come about is the fact that sometimes when stuff gets channeled at me a lot and this is triggered a lot from it, the sound of the spell gets stuck where the object was even after it's gone.
The next thing is, I don't really know how to create a "true" invisible object. Right now this shows up as a cool purple diamond shaped thing for a second. I'm also not sure if moving the object is the best way to overcome the apparent collisions it has. For instance, if I'm in a tight spot and it moves up into the ceiling, it's going to be pretty worthless and may even splash damage myself. Now, I'm fine with it casting the spell at where the NPC was and it hits an object on the way (for instance it was hitting poles and stuff between me and the person attacking me because the NPC was moving - but this is fine and makes sense). It's mostly when it hits me with it because it's technically inside of me, or hits the floor because it's too low, etc.
Right now this object spawns, gets placed just a little bit above and to the side of me, casts the spell and is deleted after a second.
Thanks again for your reply.
Also this has the hilarious side effect of causing NPCs to almost instantly get hit by a powerful spell, making them flee yelling. But fairly sure that's just due to combat mechanics and my char being pretty powerful. I think the spell might even be affected by my skills, which means they would be hitting me with it, it gets amplified by about 5x (Other things I'm testing / messing with) and sent back to them.
Edit: Updated with the IsHostile() check. I should probably check to make sure the NPC is actually in combat with me too, I'm not sure if there are quests out there that cast spells at me, but I don't want to reflect something back at a quest NPC and cause a problem.
Edit2: So I got the chance to try this on a dragon... Yeah, it spawned a ton of the objects, created this wall of fire breath that pretty much made seeing anything else impossible and left this really loud sound effect hovering in the world. It also didn't appear to do all that much damage to the dragon (Where the mages that were hitting me were almost getting insta-killed). I also had this effect applied to a ward spell about two days ago using OnWardHit and it did quite a bit of damage to the dragon doing it that way. This seemed like it was missing and aiming in the wrong direction sometimes.
It would appear the next big thing to really fix is the OnHit spam.
Edit3: The sound bug doesn't persist through saves, thankfully.
Edit4: Fixed some alignment issues with the post and the comments in my code.