lesi123 Posted December 20, 2016 Author Share Posted December 20, 2016 Sorry I haven't kept a very close tabs on this thread since my last post but I think I found a workaround with the script after lots (and lots...) of debug notifications. Scriptname BTDCREATUREtoPLAYERDmg extends ReferenceAlias {Script that handles Creature to Player bleed damage} ;--------------------------------------------------------------------------------------------------------------------------------------- ; The HitChance conditions in the function blocks control the hit chances to apply the bleed damage spells to targets. To increase the chances of applying a bleed, use a lower number. To reduce the chances of applying a bleed, use a higher number. ;--------------------------------------------------------------------------------------------------------------------------------------- Actor Property PlayerRef Auto Race Property WolfRace Auto Race Property SlaughterfishRace Auto Race Property SabreCatRace Auto Race Property SabreCatSnowyRace Auto Race Property BearBlackRace Auto Race Property BearBrownRace Auto Race Property BearSnowRace Auto Race Property IceWraithRace Auto Race Property WerewolfBeastRace Auto Race Property SprigganRace Auto Race Property SprigganMatronRace Auto Race Property TrollRace Auto Race Property TrollFrostRace Auto Race Property DwarvenSphereRace Auto Race Property DwarvenCenturionRace Auto Race Property DLC1DeathHoundRace Auto Race Property DLC1SabreCatGlowRace Auto Race Property SprigganEarthMotherRace Auto Race Property DLC1GargoyleRace Auto Race Property DLC1GargoyleVariantBossRace Auto Race Property DLC1GargoyleVariantGreenRace Auto Race Property DLC2SprigganBurntRace Auto Race Property DLC2WerebearBeastRace Auto Race Property DLC1LD_ForgemasterRace Auto Race Property DLC2DwarvenBallistaRace Auto Race Property DLC2dunKarstaagIceWraithRace Auto Race Property DragonRace Auto Spell Property BTDSpellCREATURESmalltoPLAYERBleedDmg Auto Spell Property BTDSpellCREATUREMediumtoPLAYERBleedDmg Auto Spell Property BTDSpellCREATURELargetoPLAYERBleedDmg Auto Spell Property BTDSpellCREATUREXLargetoPLAYERBleedDmg Auto Keyword Property ActorTypeAnimal Auto Keyword Property ActorTypeCreature Auto Keyword Property ActorTypeDwarven Auto Actor Aggressor Race AggressorRace Int HitChance ; Dragons and hagravens had to be excluded since their breaths and spells would apply bleeds to the player ;------------------------------------------------------------------------------------------------------------------------ ; HIT REGISTERED ON PLAYER ;------------------------------------------------------------------------------------------------------------------------ Auto State Ready Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked) GoToState("Busy") ; Don't run this OnHit Event again until it's finished and the cooldown is up Aggressor = akAggressor as Actor if (akAggressor != None) && (akSource as Weapon) && (abHitBlocked != true) && (Aggressor.GetRace() != DragonRace) && !(akSource as Spell) if (Aggressor.HasKeyword(ActorTypeAnimal)) PlayerHitByAnimal(Aggressor) elseif (Aggressor.HasKeyword(ActorTypeCreature)) PlayerHitByCreature(Aggressor) elseif (Aggressor.HasKeyword(ActorTypeDwarven)) PlayerHitByDwarven(Aggressor) else Utility.Wait(0.5) GoToState("Ready") ; The OnHit Event has finished and cooldown is up, so it can be called again endif else Utility.Wait(0.5) GoToState("Ready") ; The OnHit Event has finished and cooldown is up, so it can be called again endif EndEvent EndState State Busy Event OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, bool abPowerAttack, bool abSneakAttack, bool abBashAttack, bool abHitBlocked) ; Nothing EndEvent EndState ;------------------------------------------------------------------------------------------------------------------------ ; FUNCTION BLOCKS ;------------------------------------------------------------------------------------------------------------------------ ; ---------- Player hit by an animal ---------- Function PlayerHitByAnimal(Actor Param1) AggressorRace = Aggressor.GetRace() HitChance = Utility.RandomInt() if ((AggressorRace == WolfRace) && (HitChance >= 70)) || ((AggressorRace == SlaughterfishRace) && (HitChance >= 30)) BTDSpellCREATURESmalltoPLAYERBleedDmg.cast(PlayerRef,PlayerRef) elseif ((AggressorRace == SabreCatRace) && (HitChance >= 60)) || ((AggressorRace == SabreCatSnowyRace) && (HitChance >= 50)) || ((AggressorRace == BearBlackRace) && (HitChance >= 50)) || ((AggressorRace == BearBrownRace) && (HitChance >= 60)) || ((AggressorRace == BearSnowRace) && (HitChance >= 50)) || ((AggressorRace == DLC1SabreCatGlowRace) && (HitChance >= 50)) BTDSpellCREATUREMediumtoPLAYERBleedDmg.cast(PlayerRef,PlayerRef) elseif ((AggressorRace == TrollRace) && (HitChance >= 60)) || ((AggressorRace == TrollFrostRace) && (HitChance >= 50)) BTDSpellCREATURELargetoPLAYERBleedDmg.cast(PlayerRef,PlayerRef) endif Utility.Wait(0.5) GoToState("Ready") ; The OnHit Event has finished and cooldown is up, so it can be called again EndFunction ; ---------- Player hit by a creature ---------- Function PlayerHitByCreature(Actor Param1) AggressorRace = Aggressor.GetRace() HitChance = Utility.RandomInt() if ((AggressorRace == DLC1DeathHoundRace) && (HitChance >= 70)) BTDSpellCREATURESmalltoPLAYERBleedDmg.cast(PlayerRef,PlayerRef) elseif ((AggressorRace == IceWraithRace) && (HitChance >= 50)) || ((AggressorRace == DLC2dunKarstaagIceWraithRace) && (HitChance >= 50)) BTDSpellCREATUREMediumtoPLAYERBleedDmg.cast(PlayerRef,PlayerRef) elseif ((AggressorRace == WerewolfBeastRace) && (HitChance >= 50)) || ((AggressorRace == SprigganRace) && (HitChance >= 60)) || ((AggressorRace == SprigganMatronRace) && (HitChance >= 50)) || ((AggressorRace == SprigganEarthMotherRace) && (HitChance >= 40)) || ((AggressorRace == DLC1GargoyleRace) && (HitChance >= 50)) || ((AggressorRace == DLC1GargoyleVariantBossRace) && (HitChance >= 40)) || ((AggressorRace == DLC1GargoyleVariantGreenRace) && (HitChance >= 50)) || ((AggressorRace == DLC2SprigganBurntRace) && (HitChance >= 60)) || ((AggressorRace == DLC2WerebearBeastRace) && (HitChance >= 50)) BTDSpellCREATURELargetoPLAYERBleedDmg.cast(PlayerRef,PlayerRef) endif Utility.Wait(0.5) GoToState("Ready") ; The OnHit Event has finished and cooldown is up, so it can be called again EndFunction ; ---------- Player hit by a dwarven automaton ---------- Function PlayerHitByDwarven(Actor Param1) AggressorRace = Aggressor.GetRace() HitChance = Utility.RandomInt() if ((AggressorRace == DwarvenSphereRace) && (HitChance >= 50)) BTDSpellCREATURELargetoPLAYERBleedDmg.cast(PlayerRef,PlayerRef) elseif ((AggressorRace == DwarvenCenturionRace) && (HitChance >= 20)) || ((AggressorRace == DLC1LD_ForgemasterRace) || (AggressorRace == DLC2DwarvenBallistaRace) && (HitChance >= 10)) BTDSpellCREATUREXLargetoPLAYERBleedDmg.cast(PlayerRef,PlayerRef) endif Utility.Wait(0.5) GoToState("Ready") ; The OnHit Event has finished and cooldown is up, so it can be called again EndFunction My thought was by adding a Utility.Wait(X) before the script is to head back into the Ready state, the script would be forced to chill out in the busy state until he "cooldown" was up. I just got finished a fight that dang sun dragon for 20 minutes and then a 5 minute fight with a pack of 5 wolves; bleeds were being applied appropriately and no errors or stack dumps showed up in the log from the session. ReDragon, thank you very much for the rewrite! I'll have to read through it, I'm still not the best at scripting and it takes awhile to grasp things. I'll have to do more testing later though, work comes early in the morning. I'll update this topic if I have anything else to report. Again, thank you everyone for your help! Link to comment Share on other sites More sharing options...
lesi123 Posted December 20, 2016 Author Share Posted December 20, 2016 If you get a stack dump I would expect one or two instances of the script to appear somewhere, the problem is that you seem to have more than that. Does the scripting system recover after the combat is over? Stack dumps aren't inherently a critical problem, they just mean the scripting system isn't keeping up with all of the action. Your mod is adding more scripting activity to an already heavy load and you're trying to stress it out so it does make sense you can trigger them. Maybe the problem is related to the fact that you're casting a spell on the player (which has its own hit effect) and under heavy load the game isn't getting that fully processed until after the state has changed, but even if that were the case there shouldn't be a way for multiple cases to stack up. There's also a chance you've got some sort of locking problem which is preventing scripts from completing. If the scripting system eventually stops applying the effect and then doesn't recover after combat is over that would be the most likely problem. Since I was fighting a single sun dragon and the only real mods I have are my mod and Deadly Dragons, I wouldn't have thought the system would overload as much as it did. That, and the dragon was part of the DragonRace, I had expected the script to stop at the (Aggressor.GetRace() != DragonRace) on the first line. I'm seriously stumped on that one. Link to comment Share on other sites More sharing options...
Masterofnet Posted December 20, 2016 Share Posted December 20, 2016 (edited) My thought was by adding a Utility.Wait(X) before the script is to head back into the Ready state, the script would be forced to chill out in the busy state until he "cooldown" was up. I just got finished a fight that dang sun dragon for 20 minutes and then a 5 minute fight with a pack of 5 wolves; bleeds were being applied appropriately and no errors or stack dumps showed up in the log from the session. The utility wait is a good idea. Did you notice RedDragon did not have the event active in the Busy state? That is a complicated script of Red Dragons, I would like to know what the outcome is should you choose to try it. Please also consider other options for what you are doing here. Placing a spell or perk on the NPCs would be less taxing if you are able to do it. BTW How can your script be working with animals when you shut it down if the hit did not come from a weapon?? if (akAggressor != None) && (akSource as Weapon) && (abHitBlocked != true) && (Aggressor.GetRace() != DragonRace) && !(akSource as Spell) Edited December 20, 2016 by Masterofnet Link to comment Share on other sites More sharing options...
lesi123 Posted December 20, 2016 Author Share Posted December 20, 2016 (edited) The utility wait is a good idea. Did you notice RedDragon did not have the event active in the Busy state? That is a complicated script of Red Dragons, I would like to know what the outcome is should you choose to try it. Please also consider other options for what you are doing here. Placing a spell or perk on the NPCs would be less taxing if you are able to do it. BTW How can your script be working with animals when you shut it down if the hit did not come from a weapon?? if (akAggressor != None) && (akSource as Weapon) && (abHitBlocked != true) && (Aggressor.GetRace() != DragonRace) && !(akSource as Spell) I had added in the OnHit event inside the Busy state so I could fire a debug notification to see how many times the event was firing while in that state. Without the utility.wait, I never saw my message fire from the Busy state during a fight. I've tried different methods of accomplishing what I wanted over the past few years (abilities, perks, spells), but many would conflict with other mods and I wanted to avoid that as much as possible. Also, since this script is attached to a quest on the player, it can be turned on or off which I find very nice. Most sources of damage that hit the player returns as a weapon so I had to get more specific with keywords. That's why I had to take out dragons and hagravens from the script because dragon breaths and hagraven firebolt spells were returning as weapons and applying bleeds to the player. I used these in my OnHit events for testing: debug.notification("Attacker is" + akAggressor) debug.notification("Source is" + akSource) I don't get it, but I'll roll with the punches. Edited December 20, 2016 by lesi123 Link to comment Share on other sites More sharing options...
cdcooley Posted December 20, 2016 Share Posted December 20, 2016 I do not want to interrupt your disput about states and flages, but sometimes it is a good idea to look at Bethesda wikihttp://www.creationkit.com/index.php?title=States_(Papyrus) cdcooley, I do not hate states. Please edit your posting.My comments on the relative merits of states and flags for optimizing Papyrus scripts are based on comments from a developer of the system. SmkViper has made multiple posts on the topic over the years, here's one of the most recent.Please be careful when using OnHit - especially with a spell like flames. Flames hits you very, very quickly and can easily overwhelm your script without using states to control it. Example: Event OnHit(...) GotoState("ProcessingHit") ; Do stuff GotoState("") EndEvent State ProcessingHit Event OnHit(...) ; make sure this is empty - comments are ok, anything else isn't EndEvent EndState Unfortunately it's very difficult to find older postings on the Bethesda forums or I would quote one of his earlier postings where he explained how the state system optimizes access in a way that flag variables can't. Optimizing with flag variables and early return statements was the technique we used in the old scripting language from previous games and it worked very well there, but Papyrus is internally structured very differently and different optimization techniques are needed. Flags are certainly still useful but not for protecting from script overload for the OnHit or inventory events. Link to comment Share on other sites More sharing options...
Masterofnet Posted December 20, 2016 Share Posted December 20, 2016 (edited) Most animals do unarmed damage and it is hard to believe that a spell would return as a weapon. Also you are shutting the script down if the damage comes from a spell so I don't see how a Shout or Spell from a Hagraven would work. However I have not tested that on an OnHit event. I had a go at the script myself. It restricts your ability to apply the chance of bleed damage based on the attacker a little bit but I do not think it would be noticeable in game. Scriptname BTDCREATUREtoPLAYERDmg extends ReferenceAlias {rewritten by Big Man 2016} ; handles creature to Player bleed damage ; source: Big Man -------------------------------------------------------------------------------------------------------------------------------- Spell PROPERTY SmallBleed auto Spell PROPERTY MediumBleed auto Spell PROPERTY LargeBleed auto Spell PROPERTY XLargeBleed auto Keyword PROPERTY ActorTypeAnimal auto Keyword PROPERTY ActorTypeCreature auto Keyword PROPERTY ActorTypeDwarven auto FormList Property SmallAttacker auto FormList Property MediumAttacker auto FormList Property LargeAttacker auto FormList Property XLargeAttacker auto int i = Utility.RandomInt() ; = Utility.RandomInt(0,100) Spell BleedUm Auto State Ready ; HIT REGISTERED ON PLAYER EVENT OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, Bool abPowerAttack, Bool abSneakAttack, Bool abBashAttack, Bool abHitBlocked) gotoState("Busy") Actor Attacker = (AkAggressor As Actor) Race R = Attacker.GetRace() IF (( abHitBlocked ) || (akSource as Spell)) || (!(Attacker.HasKeyword(ActorTypeDwarven)) && !(Attacker.HasKeyword(ActorTypeAnimal))&& !(Attacker.HasKeyword(ActorTypeCreature))) gotoState("Ready") ElseIf (i >= 50) && SmallAttacker.HasForm(R) BleedUm = SmallBleed ElseIf (i >= 50) && MediumAttacker.HasForm(R) BleedUm = MediumBleed ElseIf (i >= 50) && LargeAttacker.HasForm(R) BleedUm = LargeBleed ELseIf (i >= 50) && XLargeAttacker.HasForm(R) BleedUm = XLargeBleed EndIf If (BleedUm) BleedUm.Cast((Self.GetReference() As Actor),(Self.GetReference() As Actor)) EndIf gotoState("Ready") EndEvent EndState State Busy EVENT OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, Bool abPowerAttack, Bool abSneakAttack, Bool abBashAttack, Bool abHitBlocked) ; Nothing EndEvent EndState Edited December 21, 2016 by Masterofnet Link to comment Share on other sites More sharing options...
ReDragon2013 Posted December 20, 2016 Share Posted December 20, 2016 Hi cdcooley, I am far away to know all about papyrus scripting, but during the last two years I learned a lot about it.Let me say thank you for your always good postings.My comments on the relative merits of states and flags for optimizing Papyrus scripts are based on comments from a developer of the system. SmkViper has made multiple posts on the topic over the years, here's one of the most recent. SmkViper, on 06 Oct 2015 - 6:52 PM, said: Please be careful when using OnHit - especially with a spell like flames. Flames hits you very, very quickly and can easily overwhelm your script without using states to control it. Event OnHit(...) GotoState("ProcessingHit") ; Do stuff GotoState("") EndEvent State ProcessingHit Event OnHit(...) ; make sure this is empty - comments are ok, anything else isn't EndEvent EndState you wrote: "Flags are certainly still useful but not for protecting from script overload for the OnHit or inventory events." That is right and the reason why some events should be protected by states, especially OnHit(). But if you would like remember the initial posting here was written about functions.Functions and events are different. An event may trigger always and that can be very quickly. A function wont do that, she has to be called by another function or from event. What is the point, events need states to prevent stack overload, functions are fine with a global boolVar as thread lock. Cheers.. Link to comment Share on other sites More sharing options...
ReDragon2013 Posted December 20, 2016 Share Posted December 20, 2016 (edited) Masterofnet wrote: "I do not know how this script is going to fire on animal hits when it is shut down if the hit does not come from a weapon???"I wrote as code description: "all conditions above are thread safe". Maybe you do not noticed it.My conditions are optimized in order and using of temp stack variables.next code is equal in result IF !(akSource as Weapon) RETURN ; - STOP - ENDIFas this script code IF (akSource as Weapon) ELSE RETURN ; - STOP - ENDIFMasterofnet crippled OnHit() version: ;========================= Auto State Ready ; HIT REGISTERED ON PLAYER ;=============== EVENT OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, Bool abPowerAttack, Bool abSneakAttack, Bool abBashAttack, Bool abHitBlocked) gotoState("Busy") IF ( abHitBlocked ) || (akSource as Spell) || !(akAggressor as Actor) || !(akSource as Weapon) ; I do not know how this script is going to fire on animal hits ; when it is shut down if the hit does not come from a weapon??? gotoState("Ready") RETURN Else PlayerHitBy(akAggressor as Actor) EndIf ENDEVENT ;======= endState I do not like to write this down, but you crippled my script version a lot. Because you made it much more unreadable.The use of so many "gotostate" code lines is imho bad script design and the result of your script rewriting.I always try to prevent gotostate inside functions, unfortunately not possible ever.my original hit event version: ;========================= Auto State Ready ; HIT REGISTERED ON PLAYER ;=============== EVENT OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, Bool abPowerAttack, Bool abSneakAttack, Bool abBashAttack, Bool abHitBlocked) IF ( abHitBlocked ) ; IF (abHitBlocked == true) RETURN ; - STOP - /1 hit was blocked ENDIF ;--------------------- IF (akSource as Spell) RETURN ; - STOP - /2 spells are skipped ENDIF ;--------------------- IF (akAggressor as Actor) ELSE RETURN ; - STOP - /3 no actor, no blood ENDIF ;--------------------- IF (akSource as Weapon) ;|| (akProjectile) ELSE RETURN ; - STOP - /4 no weapon, no blood ENDIF ;--------------------- all conditions above are thread safe gotoState("Busy") ; ### STATE ### do not run this function again until it has finished PlayerHitBy(akAggressor as Actor) gotoState("Ready") ; ### STATE ### function has finished back to auto state, it can be called again ENDEVENT ;======= endState Edited December 20, 2016 by ReDragon2013 Link to comment Share on other sites More sharing options...
Masterofnet Posted December 20, 2016 Share Posted December 20, 2016 (edited) Masterofnet wrote: "I do not know how this script is going to fire on animal hits when it is shut down if the hit does not come from a weapon???" I wrote as code description: "all conditions above are thread safe". Maybe you do not noticed it.My conditions are optimized in order and using of temp stack variables. Your script very clearly stated "No Weapon No Blood". It looks to me like if your script detects a hit "not" made by a Weapon that it will not fire the functions. What does your script do if it detects "no weapon"? I do not like to write this down, but you crippled my script version a lot. Because you made it much more unreadable.The use of so many "gotostate" code lines is imho bad script design and the result of your script rewriting.I always try to prevent gotostate inside functions, unfortunately not possible ever. You mean at the end of your script? Ya I had a feeling you were not going to like that. I have never used " Return" the way you did so I was not sure how that would effect the placement of the "GoToStates". Also I do not see where you apply the spell to the player. I think that would be the place to insert gotostate"ready". ;------------------------------------------- Spell FUNCTION myF_GetSX(Int i, Int iChance) ; xLarge ;------------------------------------------- IF (i >= iChance) RETURN BTDSpellCREATUREXLargetoPLAYERBleedDmg ; What exatally will "RETURN" do here?? Will the script continue to run or will it "Quit"? ENDIF RETURN None ; What exatally will "RETURN" do here?? Will the script continue to run or will it "Quit"? ENDFUNCTION Your script fires the Busy State and then immediately fires the Ready State. Why bother with the Busy State?Also this is a OnHit event. An OnHIt event that performs this many functions needs to be shut down until all of the functions complete. It does not look like your script is doing that. What do you think of my version? Is it easy enough for you to read? Hopefully its not "crippled". Scriptname BTDCREATUREtoPLAYERDmg extends ReferenceAlias {rewritten by Big Man 2016} ; handles creature to Player bleed damage ; source: Big Man Spell PROPERTY SmallBleed auto Spell PROPERTY MediumBleed auto Spell PROPERTY LargeBleed auto Spell PROPERTY XLargeBleed auto Keyword PROPERTY ActorTypeAnimal auto Keyword PROPERTY ActorTypeCreature auto Keyword PROPERTY ActorTypeDwarven auto FormList Property SmallAttacker auto FormList Property MediumAttacker auto FormList Property LargeAttacker auto FormList Property XLargeAttacker auto Spell BleedUm Int iChance Auto State Ready ; HIT REGISTERED ON PLAYER EVENT OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, Bool abPowerAttack, Bool abSneakAttack, Bool abBashAttack, Bool abHitBlocked) gotoState("Busy") Actor Herbert = (AkAggressor As Actor) IF (( abHitBlocked ) || (akSource as Spell))||(!Herbert.HasKeyword(ActorTypeDwarven) && !Herbert.HasKeyword(ActorTypeAnimal) && !Herbert.HasKeyword(ActorTypeCreature)) gotoState("Ready") Else Race R = Herbert.GetRace() Int SI = SmallAttacker.Find(R) Int MI = MediumAttacker.Find(R) Int LI = LargeAttacker.Find(R) Int XI = XLargeAttacker.Find(R) int i = Utility.RandomInt() ; = Utility.RandomInt(0,100) If SI > -1 BleedUm = SmallBleed If SI <= 3 iChance = 40 ElseIf SI <= 6 iChance = 60 ElseIf SI <= 9 iChance = 80 EndIf ElseIf MI > -1 BleedUm = MediumBleed If MI <= 3 iChance = 40 ElseIf MI <= 6 iChance = 60 ElseIf MI <= 9 iChance = 80 EndIf ElseIf LI > -1 BleedUm = LargeBleed If LI <= 3 iChance = 40 ElseIf LI <= 6 iChance = 60 ElseIf LI <= 9 iChance = 80 EndIf ElseIf XI > -1 BleedUm = XLargeBleed If XI <= 3 iChance = 40 ElseIf XI <= 6 iChance = 60 ElseIf XI <= 9 iChance = 80 EndIf EndIF If (BleedUm) && (i >= iChance) BleedUm.Cast((Self.GetReference()),(Self.GetReference()) EndIf gotoState("Ready") EndIf EndEvent EndState State Busy EVENT OnHit(ObjectReference akAggressor, Form akSource, Projectile akProjectile, Bool abPowerAttack, Bool abSneakAttack, Bool abBashAttack, Bool abHitBlocked) ; Nothing EndEvent EndState Edited December 24, 2016 by Masterofnet Link to comment Share on other sites More sharing options...
ReDragon2013 Posted December 21, 2016 Share Posted December 21, 2016 Dear Masterofnet,please be a bit more shy, and keep in mind my English skill is not as good as yours. I admire your confidence to your script proposal, but what I have to say is: "Sorry, it is a mess." Let me explain why?1) the script has syntax errors;--------------------------------------------------------------------------------------------------------------------------------; above is code line 6: ..\BTDCREATUREtoPLAYERDmg.psc(6,0): missing EOF at '-'; you forget semicolon;int i = Utility.RandomInt() ; = Utility.RandomInt(0,100); above is code line 25: ..\BTDCREATUREtoPLAYERDmg.psc(25,8): no viable alternative at input 'Utility'; ..\BTDCREATUREtoPLAYERDmg.psc(25,15): required (...)+ loop did not match anything at input '.'; ..\BTDCREATUREtoPLAYERDmg.psc(25,4): Unknown user flag Utility; you cannot use papyrus code on property or variable declaration, the code line has to be inside a function or event !!!2) you have a logical error in the main condition:you took this: IF (( abHitBlocked ) || (akSource as Spell)) || (!(Attacker.HasKeyword(ActorTypeDwarven)) && !(Attacker.HasKeyword(ActorTypeAnimal))&& !(Attacker.HasKeyword(ActorTypeCreature))) gotoState("Ready") else ; formlist action here gotoState("Ready") endif we could break it up into two conditions, which will have the same result like yours: IF (abHitBlocked) || (akSource as Spell) ; this is ok gotoState("Ready") ELSEIF !Attacker.HasKeyword(ActorTypeDwarven) && !Attacker.HasKeyword(ActorTypeAnimal) && !Attacker.HasKeyword(ActorTypeCreature) ; this is wrong! gotoState("Ready") else ; formlist action here gotoState("Ready") endif to make it right you would have to use next conditions: IF (abHitBlocked) || (akSource as Spell) || !Attacker gotoState("Ready") ELSEIF Attacker.HasKeyword(ActorTypeCreature) || Attacker.HasKeyword(ActorTypeAnimal) || Attacker.HasKeyword(ActorTypeDwarven) ; formlist action here gotoState("Ready") ENDIF Have you seen the different?Note: You forgot to check, is the overgiven objectReference akAggressor a valid Actor.3) Regardless of the things form above, you implemented formlists to make your code better looking. bad decision.. You have to create the formlists with the CreationKit. If you make something wrong here it is hard to analyze. In case you want to change the chance of blood by a special race, what do you do? The race conditions (I have used) are much better to handle and I use the native function GetFormID() with modulo like that: int x = r.GetFormID() x = x % 0x00100000 to prevent of binding the mod file (*.esp) to other masterfiles than Skyrim.esm and Update.esm. If you use formlists you have to make sure DLC1 and DLC2 have to be loaded with your mod.4) In case the conditions above would be ok, your code runs through all of the four formlists. Actor Attacker = (AkAggressor As Actor) Race R = Attacker.GetRace() Int SI = SmallAttacker.Find(R) Int MI = MediumAttacker.Find(R) Int LI = LargeAttacker.Find(R) Int XI = XLargeAttacker.Find(R) This is wasting of processor time and could be surely improved. But do you remember my meaning about formlist, it doesn't make sense for me to do that.5) Let us assume we forget all the things above, we should look at the next code: ; here would be the right place inside your script version int i = Utility.RandomInt() ; = Utility.RandomInt(0,100) If (BleedUm) && (i >= iChance) BleedUm.Cast((Self.GetReference() As Actor),(Self.GetReference() As Actor)) EndIf The native method "cast" needs always objectReference as parameter, so you should use that instead If (BleedUm) && (i >= iChance) objectReference oRef = self.GetReference() ; oRef could have any name you like BleedUm.Cast(oRef, oRef) EndIf6) And finally a comparing of stackVars: your version without functions: OnHit .return NONE .paramTable .param akAggressor ObjectReference .param akSource Form .param akProjectile Projectile .param abPowerAttack Bool .param abSneakAttack Bool .param abBashAttack Bool .param abHitBlocked Bool .endParamTable .localTable .local ::nonevar none .local ::temp0 actor .local ::temp1 race .local ::temp2 spell .local ::temp3 bool .local ::temp4 bool .local ::temp5 bool .local Attacker Actor .local R Race .local ::temp6 form .local ::temp7 int .local SI Int .local MI Int .local LI Int .local XI Int .local iChance Int .local ::temp8 bool .local ::temp9 bool .local i int .local ::temp10 objectreference .local ::temp11 actor .local ::temp12 objectreference .endLocalTable my version with functions to divide the code: OnHit .return NONE .paramTable .param akAggressor ObjectReference .param akSource Form .param akProjectile Projectile .param abPowerAttack Bool .param abSneakAttack Bool .param abBashAttack Bool .param abHitBlocked Bool .endParamTable .localTable .local ::temp0 spell .local ::temp1 actor .local ::temp2 weapon .local ::nonevar none .endLocalTable function PlayerHitBy .return NONE .paramTable .param aRef Actor .endParamTable .localTable .local ::temp3 race .local ::temp4 bool .local ::temp6 bool .local r race .local sp spell .local ::temp5 spell .local ::temp7 objectreference .local ::nonevar none .local selfRef objectReference .endLocalTable function PlayerHitByAnimal (these both function PlayerHitByDwarven, PlayerHitByCreature use one temp bool more) .return Spell .paramTable .param r Race .endParamTable .localTable .local ::temp8 int .local ::temp9 bool .local ::temp11 bool .local i int .local sp spell .local ::temp10 spell .local x int .endLocalTable function myF_GetSS (all functions myF_GetSM, myF_GetSL, myF_GetSX have the same header) .return Spell .paramTable .param i Int .param iChance Int .endParamTable .localTable .local ::temp22 bool .local ::temp23 spell .endLocalTable Link to comment Share on other sites More sharing options...
Recommended Posts