Desperate for help with magic effects and HasKeyword

Post » Tue Jun 19, 2012 11:49 pm

Hey guys, I'm working on an update for my Spell Sneak Attack Mod here http://steamcommunity.com/sharedfiles/filedetails/?id=15730 and I recently added dynamic support for sneak attacking with mod spells. The problem is, that I cant also pop up "You have sneak attacked for blah blah" without using a magic effect script. I solved this issue by dynamically assigning scripts to the nearest 30 people around me(http://tinyurl.com/88qtwqh)and whenever they get hit with a spell to figure out if it's a valid spell that can sneak attack.

The problem:
Anytime I cast a spell that should be "caught" by a "HasKeyword" if statement, it simply passes through and moves on.
Spells with "Ritual Spell Effect" keywords will sometimes be caught(the magic effect), but upon triggering again (the same magic effect) will be false. I have no idea why it only sometimes registers the keyword. I have confirmed everything is working EXCEPT those "HasKeyword" statements and have no idea what I'm doing wrong.

-Yes I've properly assigned all my properties(before you ask :tongue:)

Below is the code that attaches dynamically to actors and attempts(unsuccessfully) to weed out "Cloak" and "Ritual" Spells. Please let me know what I'm doing wrong(I'm sure it's something silly but I've been struggling with this for 20+ hours now)

Spoiler
Scriptname AerSpellSneakMessageDisplay extends ReferenceAlias{Shows the message in the upper left hand corner}Perk Property DBBackstab AutoPerk Property AerSneakSpellPerk AutoKeyword Property MagicCloak AutoKeyword Property RitualSpellEffect AutoKeyword Property AerDoNotMessageDisplay AutoMessage Property AerSpellSneakMsg AutoMessage Property AerSpellSneakDBMsg Autobool Function HasKeyword(Keyword akKeyword) nativeint counter = 0Event OnMagicEffectApply(ObjectReference akCaster, MagicEffect akEffect) ;If the source of damage if from the player if(akCaster == Game.GetPlayer())     debug.MessageBox((akEffect as Form).HasKeyword(AerDoNotMessageDisplay))  ;Check if spell is a cloak (Cant sneak attack - target self)   if(((akEffect as Form).HasKeyword(MagicCloak)) == False)              ;Check if spell is a Ritual effect (Cant sneak attack - 2 handed)              if(((akEffect as Form).HasKeyword(RitualSpellEffect)) == False)                    ;Check if spell has any extra affects that mess up display of messages and grant extra experience                    if(((akEffect as Form).HasKeyword(AerDoNotMessageDisplay)) == False)                          ;As long as the play is not in combat (aka unseen)                          if (GetActorReference().GetCombatState() != 1)                                ;If the spell being cast is from the Destruction school                                if((akEffect as MagicEffect).GetAssociatedSkill() == "Destruction" )                                      ;As long as sneaking                                      if (Game.GetPlayer().IsSneaking() == 1)                                           ;Check Which Message to display/can spell sneak attack                                           if (Game.GetPlayer().HasPerk(AerSneakSpellPerk)==1) ;Default Spell Sneak Perk                                                 ;Grant some sneak experience                                                 Game.AdvanceSkill("Sneak", 6)                                                    ;If Player has both perks - Apply Backstab perk 2.25x                                                    if (Game.GetPlayer().HasPerk(DBBackstab)==1)                                                            ;Grant bonus experience if using backstab gloves                                                             Game.AdvanceSkill("Sneak", 2)                                                           AerSpellSneakDBMsg.Show() ;2.25x Message                                                    else ;He only has the default sneak attack - No backstab perk                                                           AerSpellSneakMsg.Show() ;1.5x MessageendifendifendifendifendifendifendifendifendifEndEvent
User avatar
ruCkii
 
Posts: 3360
Joined: Mon Mar 26, 2007 9:08 pm

Post » Wed Jun 20, 2012 1:40 am

I didn't debug your script, but wow, you need to simplify it and learn some OOP base. First, MagicEffect extends Form, so MagicEffect have all the methods, functions, events and properties inherited from his parent, Form. So
if(((akEffect as Form).HasKeyword(AerDoNotMessageDisplay)) == False)

can be wrote :
if akEffect.HasKeyword(AerDoNotMessageDisplay) == False

And as HasKeyword is already a boolean, you can write it with a logical NOT (!) like this :

if !(akEffect.HasKeyword(AerDoNotMessageDisplay))

And so on...
User avatar
Cameron Wood
 
Posts: 3384
Joined: Wed Oct 31, 2007 3:01 pm

Post » Wed Jun 20, 2012 2:54 am

I actually had to do the (akEffect as form) to get it to work at all originally, but it may be something that's obsolete now. Good to know about that last tip though, I'll make sure to clean up my code once it actually works. Appreciated.

For the record, I'm just starting out with scripting in the Creation kit so I know it's not going to be optimal, I'm just going through the tutorials and learning from forum posts.


Edit: I have cleaned up my code just for you :D. Thanks for the helpful tips. I have a bachelors in Computer science but haven't actually done programming in a LONG time. I need a refresher heh.
User avatar
Lloyd Muldowney
 
Posts: 3497
Joined: Wed May 23, 2007 2:08 pm

Post » Wed Jun 20, 2012 8:49 am

bool Function HasKeyword(Keyword akKeyword) native

And what is this declaration ? Do you have an access to the game source and are implementing new native function ? :biggrin:

The "Native" flag indicates a function that does not have a function body, because the function is implemented by the game itself. If you add the native flag to a function the game does not expose, the compiler won't complain, but the game will error at you. The same flag cannot be specified more then once.
User avatar
Blackdrak
 
Posts: 3451
Joined: Thu May 17, 2007 11:40 pm

Post » Wed Jun 20, 2012 2:17 pm

In my frustration I tried just about anything to get it to work. Learning through trial and error, I just posted here what I had when I finally decided to give it a break for a while.
User avatar
Project
 
Posts: 3490
Joined: Fri May 04, 2007 7:58 am

Post » Wed Jun 20, 2012 12:47 am

if (GetActorReference().GetCombatState() != 1) ; <---- and what about 2 ?  Searching ???

Perhaps it's there your problem ?
User avatar
Dan Scott
 
Posts: 3373
Joined: Sun Nov 11, 2007 3:45 am

Post » Wed Jun 20, 2012 1:54 pm

No, the combat states work as intended. My sneak attacks all work appropriately as intended. This script is only so that they get the message that pops up on their screen. I just need to find a way to be able to check a whole spell and all of it's effects before displaying the message. It's a lot harder than it sounds when I can't directly touch the spells/magic effects themselves.
User avatar
Oscar Vazquez
 
Posts: 3418
Joined: Sun Sep 30, 2007 12:08 pm

Post » Wed Jun 20, 2012 4:22 am

while massively nested if blocks are amusing, that whole thing inside the outside if block could be written like this:

  ; Check all Sneak attack prerequisitesif !(akEffect as Form).HasKeyword(MagicCloak))&&!((akEffect as Form).HasKeyword(RitualSpellEffect)) /	&& !((akEffect as Form).HasKeyword(AerDoNotMessageDisplay)) && (GetActorReference().GetCombatState() != 1) /	&& ((akEffect as MagicEffect).GetAssociatedSkill() == "Destruction" ) && (Game.GetPlayer().IsSneaking() == 1) /	&& (Game.GetPlayer().HasPerk(AerSneakSpellPerk)==1)	Game.AdvanceSkill("Sneak", 6) ;Grant some sneak experience	if (Game.GetPlayer().HasPerk(DBBackstab)==1) ;If Player has both perks - Apply Backstab perk 2.25x		Game.AdvanceSkill("Sneak", 2) ;Grant bonus experience if using backstab gloves		AerSpellSneakDBMsg.Show() ;2.25x Message	else ;He only has the default sneak attack - No backstab perk		AerSpellSneakMsg.Show() ;1.5x Message	endifendif
User avatar
Mrs shelly Sugarplum
 
Posts: 3440
Joined: Thu Jun 15, 2006 2:16 am

Post » Wed Jun 20, 2012 5:12 am

Ah! I really appreciate the formatting tips guys, I promise if I ask for more help it will look better, I just wish I could get it to work! :/
User avatar
Raymond J. Ramirez
 
Posts: 3390
Joined: Sun Oct 14, 2007 8:28 am

Post » Wed Jun 20, 2012 12:31 am

(akEffect as MagicEffect) is a little redundant. :biggrin:
User avatar
e.Double
 
Posts: 3318
Joined: Tue Jul 24, 2007 11:17 pm

Post » Wed Jun 20, 2012 2:13 am

Yes I'm aware :P. Could someone help me with the debugging and not with my formatting? :P
User avatar
Alex Vincent
 
Posts: 3514
Joined: Thu Jun 28, 2007 9:31 pm

Post » Wed Jun 20, 2012 4:03 am

Poor Syntax can lead to errors too. No one knows that better than me -.-.
User avatar
His Bella
 
Posts: 3428
Joined: Wed Apr 25, 2007 5:57 am

Post » Tue Jun 19, 2012 10:11 pm

I really don't see anything wrong with the script. It could be that it's working just fine, the problem is how you're using it. Spells can have more than one magic effect. Look at the firebolt spell for example. It has a fire damage effect, an impact stagger effect, and a intense flames demoralize effect.

It could be that a spell has a magic effect that has your keyword "AerDoNotMessageDisplay" and a second magic effect that doesn't. So when you cast the spell at an NPC, it would still say that there was a successful sneak attack because the second magic effect got through the filters just fine.
User avatar
Sheeva
 
Posts: 3353
Joined: Sat Nov 11, 2006 2:46 am

Post » Wed Jun 20, 2012 8:49 am

while massively nested if blocks are amusing, that whole thing inside the outside if block could be written like this:

  ; Check all Sneak attack prerequisitesif !(akEffect as Form).HasKeyword(MagicCloak))&&!((akEffect as Form).HasKeyword(RitualSpellEffect)) /	&& !((akEffect as Form).HasKeyword(AerDoNotMessageDisplay)) && (GetActorReference().GetCombatState() != 1) /	&& ((akEffect as MagicEffect).GetAssociatedSkill() == "Destruction" ) && (Game.GetPlayer().IsSneaking() == 1) /	&& (Game.GetPlayer().HasPerk(AerSneakSpellPerk)==1)	Game.AdvanceSkill("Sneak", 6) ;Grant some sneak experience	if (Game.GetPlayer().HasPerk(DBBackstab)==1) ;If Player has both perks - Apply Backstab perk 2.25x		Game.AdvanceSkill("Sneak", 2) ;Grant bonus experience if using backstab gloves		AerSpellSneakDBMsg.Show() ;2.25x Message	else ;He only has the default sneak attack - No backstab perk		AerSpellSneakMsg.Show() ;1.5x Message	endifendif

Agreed, although I prefer to invert the logic and dispose of the uninteresting cases first:

Scriptname AerSpellSneakMessageDisplay extends ReferenceAlias{Shows the message in the upper left hand corner}Perk Property DBBackstab AutoPerk Property AerSneakSpellPerk AutoKeyword Property MagicCloak AutoKeyword Property RitualSpellEffect AutoKeyword Property AerDoNotMessageDisplay AutoMessage Property AerSpellSneakMsg AutoMessage Property AerSpellSneakDBMsg Autobool Function HasKeyword(Keyword akKeyword) nativeint counter = 0Event OnMagicEffectApply(ObjectReference akCaster, MagicEffect akEffect)	;If the source of damage if from the player	if(akCaster != Game.GetPlayer())		return	endif	debug.MessageBox((akEffect as Form).HasKeyword(AerDoNotMessageDisplay))	;Check if spell is a cloak (Cant sneak attack - target self)	if(((akEffect as Form).HasKeyword(MagicCloak)) )		return	endif	;Check if spell is a Ritual effect (Cant sneak attack - 2 handed)	if(((akEffect as Form).HasKeyword(RitualSpellEffect)))	    return	endif	;Check if spell has any extra affects that mess up display of messages and grant extra experience	if(((akEffect as Form).HasKeyword(AerDoNotMessageDisplay)))		return	endif		;As long as the play is not in combat (aka unseen)	if (GetActorReference().GetCombatState() == 1)		return	endif	;If the spell being cast is from the Destruction school	if((akEffect as MagicEffect).GetAssociatedSkill() != "Destruction" )		return	endif		;As long as sneaking	if (Game.GetPlayer().IsSneaking() != 1)		return	endif		;Check Which Message to display/can spell sneak attack	if (Game.GetPlayer().HasPerk(AerSneakSpellPerk)!=1) ;Default Spell Sneak Perk		return	endif		;Grant some sneak experience	Game.AdvanceSkill("Sneak", 6)	if (Game.GetPlayer().HasPerk(DBBackstab)==0)		;He only has the default sneak attack - No backstab perk		AerSpellSneakMsg.Show() ;1.5x Message		return	endif	;Player has both perks - Apply Backstab perk 2.25x	;Grant bonus experience if using backstab gloves	Game.AdvanceSkill("Sneak", 2)	AerSpellSneakDBMsg.Show() ;2.25x MessageEndEvent

Sorry, I know we're drifting off topic here.
User avatar
Vicky Keeler
 
Posts: 3427
Joined: Wed Aug 23, 2006 3:03 am

Post » Wed Jun 20, 2012 2:23 am

Um, why are you using "True" instead of "Return" in your Ritual magic case? Pretty sure that doesn't do anything.
User avatar
Betsy Humpledink
 
Posts: 3443
Joined: Wed Jun 28, 2006 11:56 am

Post » Wed Jun 20, 2012 12:49 am

Um, why are you using "True" instead of "Return" in your Ritual magic case? Pretty sure that doesn't do anything.

Cut and paste error. Good catch :)
User avatar
Andrew Perry
 
Posts: 3505
Joined: Sat Jul 07, 2007 5:40 am

Post » Tue Jun 19, 2012 10:25 pm

@Randomnoob, I know that spells can have many effects, which is why I have "AerDoNotMessageDisplay" I attach this keyword to any script relating to perks so that the player doesn't get extra experience/messages. I have ran multiple debug attempts and I know for a fact every single "Magic effect" in the spells should be getting caught, but simply aren't. Would you have a different suggestion other than using onmagiceffectapply? I tried using OnHit but that ran into the same issue and as far as I am aware, those are the only two options.

Edit: The sneak attack calculation that I use works(that isn't apart of this script) because I am able (through the perk I use) to check the spell being cast for its delivery type and casting type. Anyone know a way to check for these via script(not in the creation kit wiki) OR be able to show messages on a perk being activated?
User avatar
Emerald Dreams
 
Posts: 3376
Joined: Sun Jan 07, 2007 2:52 pm

Post » Tue Jun 19, 2012 10:40 pm

If you're sure you covered every single magic effect in the spells that should be caught, but they aren't, then I have no idea what's going on. You can try this:

Spoiler
Scriptname AerSpellSneakMessageDisplay extends ReferenceAlias{Shows the message in the upper left hand corner}Perk Property DBBackstab AutoPerk Property AerSneakSpellPerk AutoKeyword Property MagicCloak AutoKeyword Property RitualSpellEffect AutoKeyword Property AerDoNotMessageDisplay AutoMessage Property AerSpellSneakMsg AutoMessage Property AerSpellSneakDBMsg AutoBool RegisteredBool Display = TrueEvent OnMagicEffectApply(ObjectReference akCaster, MagicEffect akEffect)	if !(akCaster == Game.GetPlayer())		Return	elseif !Display		Return	endif		if !Registered		Register = True		RegisterForSingleUpdate(0.25)	endif		if (akEffect as Form).HasKeyword(MagicCloak)) || ((akEffect as Form).HasKeyword(RitualSpellEffect)) /		|| ((akEffect as Form).HasKeyword(AerDoNotMessageDisplay)) || (GetActorReference().GetCombatState() == 1) /		|| ((akEffect as MagicEffect).GetAssociatedSkill() != "Destruction" ) || (Game.GetPlayer().IsSneaking() == 0) /		|| (Game.GetPlayer().HasPerk(AerSneakSpellPerk)== 0)				Display = False		endifEndEventEvent OnUpdate()	if (Display == True)		Game.AdvanceSkill("Sneak", 6) ;Grant some sneak experience		if (Game.GetPlayer().HasPerk(DBBackstab)==1) ;If Player has both perks - Apply Backstab perk 2.25x			Game.AdvanceSkill("Sneak", 2) ;Grant bonus experience if using backstab gloves			AerSpellSneakDBMsg.Show() ;2.25x Message		else ;He only has the default sneak attack - No backstab perk			AerSpellSneakMsg.Show() ;1.5x Message		endif	endif	Registered = False	Display = TrueEndEvent

It's to double-check that you really are filtering the magic effects from every spell. If that doesn't help, maybe you should forget about using the keywords altogether. Instead, you can add all the spells you want to ignore to a formlist and just ignore the event if the spell is in that formlist:

Spoiler
Scriptname AerSpellSneakMessageDisplay extends ReferenceAlias{Shows the message in the upper left hand corner}Perk Property DBBackstab AutoPerk Property AerSneakSpellPerk AutoKeyword Property MagicCloak AutoKeyword Property RitualSpellEffect AutoKeyword Property AerDoNotMessageDisplay AutoMessage Property AerSpellSneakMsg AutoMessage Property AerSpellSneakDBMsg AutoFormlist Property IgnoredSpells AutoBool RegisteredBool DisplayBool IgnoreEvent OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, \  bool abBashAttack, bool abHitBlocked)    if (akAggressor == Game.GetPlayer()) && (akSource as Spell) && (akProjectile != None)        if (IgnoredSpells.HasForm(akSource)            Ignore = True        endif        if !Registered            Registered = True            RegisterForSingleUpdate(0.25)        endif    endifEndEventEvent OnMagicEffectApply(ObjectReference akCaster, MagicEffect akEffect)    if !(akCaster == Game.GetPlayer()) || Ignore        Return    endif        if (GetActorReference().GetCombatState() != 1) && ((akEffect as MagicEffect).GetAssociatedSkill() == "Destruction" ) /        && (Game.GetPlayer().IsSneaking() == 1) && (Game.GetPlayer().HasPerk(AerSneakSpellPerk)== 1)                Display = True        endifEndEventEvent OnUpdate()    if (Display == True) && (Ignore == False)        Game.AdvanceSkill("Sneak", 6) ;Grant some sneak experience        if (Game.GetPlayer().HasPerk(DBBackstab)==1) ;If Player has both perks - Apply Backstab perk 2.25x            Game.AdvanceSkill("Sneak", 2) ;Grant bonus experience if using backstab gloves            AerSpellSneakDBMsg.Show() ;2.25x Message        else ;He only has the default sneak attack - No backstab perk            AerSpellSneakMsg.Show() ;1.5x Message        endif    endif    Registered = False    Display = False    Ignore = FalseEndEvent
User avatar
Russell Davies
 
Posts: 3429
Joined: Wed Nov 07, 2007 5:01 am

Post » Wed Jun 20, 2012 1:14 pm

Thanks randomnoob, I'm checking it out now and seeing if this helps. I appreciate it!
User avatar
Cameron Wood
 
Posts: 3384
Joined: Wed Oct 31, 2007 3:01 pm

Post » Wed Jun 20, 2012 9:12 am

So, after many more hours trying to figure this whole thing out I finally found out that "Stagger" perks were being triggered silently and making the game think the spell was unable to be sneak attacked. After I cleaned up that mess, I also had a logical error with your code where cloaks and other spells that were casted frequently could potentially be cut off mid spell check causing the last few magic effects to register and make a spell seem like it could sneak attack. After some re-arranging of your code, and some other error catching if statements it works perfectly. I am really so grateful randomnoob for your assistance :). It inspired me to keep working and improve my sneak attack checking system and I'm going to update the mod very shortly here. I appreciate all the help guys! :D
User avatar
luis ortiz
 
Posts: 3355
Joined: Sun Oct 07, 2007 8:21 pm


Return to V - Skyrim