I'm making an automatic perks mod for user's who don't use SKSE or Script Dragon.
I've created a test PC with varying skill levels and no perks in a clean save.
I've taken the same PC and added several perks in several skills in a different clean save.
With the non-perk PC, the script below appears to work perfectly - both adding and removing the perks.
With the perked PC, the script aborts with an array index out of range error (as shown in the papyrus log) when the first active perk is found.
The script should simply bypass that perk and move to the next available perk for the skill level.
I need a fresh set of eyes on this.
This is my working copy, so please excuse all the debugs.
Also it is almost 500 lines, so if anyone has suggestions as to how I might make it more efficient, i'm open to suggestions.
Spoiler
Scriptname ASAPScript extends Quest{Monitors and adds skill perks as earned.}int SkillNameElementint TempPerksElementEvent OnInit()RegisterForUpdate(1)RegisterForTrackedStatsEvent()endEventEvent OnUpdate();Initialization;;;;;;;;;;;;;;;If GetStage() <=10 SetStage (20) debug.MessageBox("ASAP is initializing. Do not perform any action that will increase any skill levels until initialization is complete. Wait for the 'Finished' message.") ; Sort through skills and initialize temporary arrays to skill arrays. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; SkillNameElement = 0 While (SkillNameElement < SkillName.Length) if SkillName[SkillNameElement] == "Alchemy" TempPerks = AlchemyPerks TempPerksBreakpoints = AlchemyPerksBreakpoints TempPerksAdded = AlchemyPerksAdded elseif SkillName[SkillNameElement] == "ALTERATION" TempPerks = AlterationPerks TempPerksBreakpoints = AlterationPerksBreakpoints TempPerksAdded = AlterationPerksAdded elseif SkillName[SkillNameElement] == "Marksman" TempPerks = ArcheryPerks TempPerksBreakpoints = ArcheryPerksBreakpoints TempPerksAdded = ArcheryPerksAdded elseif SkillName[SkillNameElement] == "Block" TempPerks = BlockPerks TempPerksBreakpoints = BlockPerksBreakpoints TempPerksAdded = BlockPerksAdded elseif SkillName[SkillNameElement] == "CONJURATION" TempPerks = ConjurationPerks TempPerksBreakpoints = ConjurationPerksBreakpoints TempPerksAdded = ConjurationPerksAdded elseif SkillName[SkillNameElement] == "DESTRUCTION" TempPerks = DestructionPerks TempPerksBreakpoints = DestructionPerksBreakpoints TempPerksAdded = DestructionPerksAdded elseif SkillName[SkillNameElement] == "Enchanting" TempPerks = EnchantingPerks TempPerksBreakpoints = EnchantingPerksBreakpoints TempPerksAdded = EnchantingPerksAdded elseif SkillName[SkillNameElement] == "HeavyArmor" TempPerks = HeavyArmorPerks TempPerksBreakpoints = HeavyArmorPerksBreakpoints TempPerksAdded = HeavyArmorPerksAdded elseif SkillName[SkillNameElement] == "ILLUSION" TempPerks = IllusionPerks TempPerksBreakpoints = IllusionPerksBreakpoints TempPerksAdded = IllusionPerksAdded elseif SkillName[SkillNameElement] == "LightArmor" TempPerks = LightArmorPerks TempPerksBreakpoints = LightArmorPerksBreakpoints TempPerksAdded = LightArmorPerksAdded elseif SkillName[SkillNameElement] == "Lockpicking" TempPerks = LockpickingPerks TempPerksBreakpoints = LockpickingPerksBreakpoints TempPerksAdded = LockpickingPerksAdded elseif SkillName[SkillNameElement] == "OneHanded" TempPerks = OneHandedPerks TempPerksBreakpoints = OneHandedPerksBreakpoints TempPerksAdded = OneHandedPerksAdded elseif SkillName[SkillNameElement] == "Pickpocket" TempPerks = PickpocketPerks TempPerksBreakpoints = PickpocketPerksBreakpoints TempPerksAdded = PickpocketPerksAdded elseif SkillName[SkillNameElement] == "RESTORATION" TempPerks = RestorationPerks TempPerksBreakpoints = RestorationPerksBreakpoints TempPerksAdded = RestorationPerksAdded elseif SkillName[SkillNameElement] == "Smithing" TempPerks = SmithingPerks TempPerksBreakpoints = SmithingPerksBreakpoints TempPerksAdded = SmithingPerksAdded elseif SkillName[SkillNameElement] == "Sneak" TempPerks = SneakPerks TempPerksBreakpoints = SneakPerksBreakpoints TempPerksAdded = SneakPerksAdded elseif SkillName[SkillNameElement] == "Speechcraft" TempPerks = SpeechPerks TempPerksBreakpoints = SpeechPerksBreakpoints TempPerksAdded = SpeechPerksAdded else TempPerks = TwoHandedPerks TempPerksBreakpoints = TwoHandedPerksBreakpoints TempPerksAdded = TwoHandedPerksAdded endif ; Get skill level, check if perk is already active, add it if not and store if existing for removal. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; TempPerksElement = 0 int SkillLevel = (Game.GetPlayer().GetBaseAV(SkillName[SkillNameElement])) as int While (TempPerksElement < TempPerks.Length) if SkillLevel < 20 if (Game.GetPlayer().HasPerk(TempPerks[TempPerksElement])) == 0 debug.notification(SkillName[SkillNameElement] + " is " + SkillLevel + ". Checking base perk only.") (Game.GetPlayer().AddPerk(TempPerks[TempPerksElement])) TempPerksAdded[TempPerksElement].Enable() TempPerksElement = TempPerks.Length endif elseif SkillLevel >= 20 && SkillLevel < 25 if (Game.GetPlayer().HasPerk(TempPerks[TempPerksElement])) == 0 debug.notification(SkillName[SkillNameElement] + " is " + SkillLevel + ", Checking perks available. Index No.: " + TempPerksElement) (Game.GetPlayer().AddPerk(TempPerks[TempPerksElement])) TempPerksAdded[TempPerksElement].Enable() TempPerksElement += 1 if TempPerksElement == TempPerksBreakpoints[0] TempPerksElement = TempPerks.Length endif endif elseif SkillLevel >= 25 && SkillLevel < 30 if (Game.GetPlayer().HasPerk(TempPerks[TempPerksElement])) == 0 debug.notification(SkillName[SkillNameElement] + " is " + SkillLevel + ", Checking perks available. Index No.: " + TempPerksElement) (Game.GetPlayer().AddPerk(TempPerks[TempPerksElement])) TempPerksAdded[TempPerksElement].Enable() TempPerksElement += 1 if TempPerksElement == TempPerksBreakpoints[1] TempPerksElement = TempPerks.Length endif endif elseif SkillLevel >= 30 && SkillLevel < 40 if (Game.GetPlayer().HasPerk(TempPerks[TempPerksElement])) == 0 debug.notification(SkillName[SkillNameElement] + " is " + SkillLevel + ", Checking perks available. Index No.: " + TempPerksElement) (Game.GetPlayer().AddPerk(TempPerks[TempPerksElement])) TempPerksAdded[TempPerksElement].Enable() TempPerksElement += 1 if TempPerksElement == TempPerksBreakpoints[2] TempPerksElement = TempPerks.Length endif endif elseif SkillLevel >= 40 && SkillLevel < 50 if (Game.GetPlayer().HasPerk(TempPerks[TempPerksElement])) == 0 debug.notification(SkillName[SkillNameElement] + " is " + SkillLevel + ", Checking perks available. Index No.: " + TempPerksElement) (Game.GetPlayer().AddPerk(TempPerks[TempPerksElement])) TempPerksAdded[TempPerksElement].Enable() TempPerksElement += 1 if TempPerksElement == TempPerksBreakpoints[3] TempPerksElement = TempPerks.Length endif endif elseif SkillLevel >= 50 && SkillLevel < 60 if (Game.GetPlayer().HasPerk(TempPerks[TempPerksElement])) == 0 debug.notification(SkillName[SkillNameElement] + " is " + SkillLevel + ", Checking perks available. Index No.: " + TempPerksElement) (Game.GetPlayer().AddPerk(TempPerks[TempPerksElement])) TempPerksAdded[TempPerksElement].Enable() TempPerksElement += 1 if TempPerksElement == TempPerksBreakpoints[4] TempPerksElement = TempPerks.Length endif endif elseif SkillLevel >= 60 && SkillLevel < 70 if (Game.GetPlayer().HasPerk(TempPerks[TempPerksElement])) == 0 debug.notification(SkillName[SkillNameElement] + " is " + SkillLevel + ", Checking perks available. Index No.: " + TempPerksElement) (Game.GetPlayer().AddPerk(TempPerks[TempPerksElement])) TempPerksAdded[TempPerksElement].Enable() TempPerksElement += 1 if TempPerksElement == TempPerksBreakpoints[5] TempPerksElement = TempPerks.Length endif endif elseif SkillLevel >= 70 && SkillLevel < 75 if (Game.GetPlayer().HasPerk(TempPerks[TempPerksElement])) == 0 debug.notification(SkillName[SkillNameElement] + " is " + SkillLevel + ", Checking perks available. Index No.: " + TempPerksElement) (Game.GetPlayer().AddPerk(TempPerks[TempPerksElement])) TempPerksAdded[TempPerksElement].Enable() TempPerksElement += 1 if TempPerksElement == TempPerksBreakpoints[6] TempPerksElement = TempPerks.Length endif endif elseif SkillLevel >= 75 && SkillLevel < 80 if (Game.GetPlayer().HasPerk(TempPerks[TempPerksElement])) == 0 debug.notification(SkillName[SkillNameElement] + " is " + SkillLevel + ", Checking perks available. Index No.: " + TempPerksElement) (Game.GetPlayer().AddPerk(TempPerks[TempPerksElement])) TempPerksAdded[TempPerksElement].Enable() TempPerksElement += 1 if TempPerksElement == TempPerksBreakpoints[7] TempPerksElement = TempPerks.Length endif endif elseif SkillLevel >= 80 && SkillLevel < 90 if (Game.GetPlayer().HasPerk(TempPerks[TempPerksElement])) == 0 debug.notification(SkillName[SkillNameElement] + " is " + SkillLevel + ", Checking perks available. Index No.: " + TempPerksElement) (Game.GetPlayer().AddPerk(TempPerks[TempPerksElement])) TempPerksAdded[TempPerksElement].Enable() TempPerksElement += 1 if TempPerksElement == TempPerksBreakpoints[8] TempPerksElement = TempPerks.Length endif endif elseif SkillLevel >= 90 && SkillLevel < 100 if (Game.GetPlayer().HasPerk(TempPerks[TempPerksElement])) == 0 debug.notification(SkillName[SkillNameElement] + " is " + SkillLevel + ", Checking perks available. Index No.: " + TempPerksElement) (Game.GetPlayer().AddPerk(TempPerks[TempPerksElement])) TempPerksAdded[TempPerksElement].Enable() TempPerksElement += 1 if TempPerksElement == TempPerksBreakpoints[9] TempPerksElement = TempPerks.Length endif endif else if (Game.GetPlayer().HasPerk(TempPerks[TempPerksElement])) == 0 debug.notification(SkillName[SkillNameElement] + " is " + SkillLevel + ", Checking perks available. Index No.: " + TempPerksElement) (Game.GetPlayer().AddPerk(TempPerks[TempPerksElement])) TempPerksAdded[TempPerksElement].Enable() TempPerksElement += 1 endif endif EndWhile SkillNameElement += 1 endWhile debug.MessageBox("ASAP initialization is complete.") RegisterForUpdate(1)endIfif GetStage() == 20 SetStage(30) debug.notification("Stage 20")endifif GetStage() == 40 UnRegisterForUpdate() debug.MessageBox("ASAP is removing perks it added. Do not perform any action that will increase any skill levels until removal is complete. Wait for the 'Finished' message.") ; first while loop - sort through skills and initialize temporary arrays to equal skill arrays ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; SkillNameElement = 0 While (SkillNameElement < SkillName.Length) if SkillName[SkillNameElement] == "Alchemy" TempPerks = AlchemyPerks TempPerksAdded = AlchemyPerksAdded elseif SkillName[SkillNameElement] == "Alteration" TempPerks = AlterationPerks TempPerksAdded = AlterationPerksAdded elseif SkillName[SkillNameElement] == "Marksman" TempPerks = ArcheryPerks TempPerksAdded = ArcheryPerksAdded elseif SkillName[SkillNameElement] == "Block" TempPerks = BlockPerks TempPerksAdded = BlockPerksAdded elseif SkillName[SkillNameElement] == "Conjuration" TempPerks = ConjurationPerks TempPerksAdded = ConjurationPerksAdded elseif SkillName[SkillNameElement] == "Destruction" TempPerks = DestructionPerks TempPerksAdded = DestructionPerksAdded elseif SkillName[SkillNameElement] == "Enchanting" TempPerks = EnchantingPerks TempPerksAdded = EnchantingPerksAdded elseif SkillName[SkillNameElement] == "HeavyArmor" TempPerks = HeavyArmorPerks TempPerksAdded = HeavyArmorPerksAdded elseif SkillName[SkillNameElement] == "Illusion" TempPerks = IllusionPerks TempPerksAdded = IllusionPerksAdded elseif SkillName[SkillNameElement] == "LightArmor" TempPerks = LightArmorPerks TempPerksAdded = LightArmorPerksAdded elseif SkillName[SkillNameElement] == "Lockpicking" TempPerks = LockpickingPerks TempPerksAdded = LockpickingPerksAdded elseif SkillName[SkillNameElement] == "OneHanded" TempPerks = OneHandedPerks TempPerksAdded = OneHandedPerksAdded elseif SkillName[SkillNameElement] == "Pickpocket" TempPerks = PickpocketPerks TempPerksAdded = PickpocketPerksAdded elseif SkillName[SkillNameElement] == "Restoration" TempPerks = RestorationPerks TempPerksAdded = RestorationPerksAdded elseif SkillName[SkillNameElement] == "Smithing" TempPerks = SmithingPerks TempPerksAdded = SmithingPerksAdded elseif SkillName[SkillNameElement] == "Sneak" TempPerks = SneakPerks TempPerksAdded = SneakPerksAdded elseif SkillName[SkillNameElement] == "Speechcraft" TempPerks = SpeechPerks TempPerksAdded = SpeechPerksAdded else TempPerks = TwoHandedPerks TempPerksAdded = TwoHandedPerksAdded endif ; Check if perk was added and remove it ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; TempPerksElement = 0 While (TempPerksElement < TempPerks.Length) debug.notification("Checking " + SkillName[SkillNameElement] + " perk " + TempPerksElement + ".") if (Game.GetPlayer().HasPerk(TempPerks[TempPerksElement])) && (TempPerksAdded[TempPerksElement].IsEnabled()) debug.notification("This perk is to be removed.") Game.GetPlayer().RemovePerk(TempPerks[TempPerksElement]) TempPerksAdded[TempPerksElement].Disable() if (Game.GetPlayer().HasPerk(TempPerks[TempPerksElement])) debug.notification("This perk has not been removed.") else debug.notification("This perk has been removed.") endif else debug.notification("This perk was existing.") endif TempPerksElement += 1 ; second While loop end ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; EndWhile SkillNameElement += 1 endWhile debug.MessageBox("ASAP removal is complete. Save your game. Exit Skyrim. Uninstall ASAP.esp.")endIfendEventEvent OnTrackedStatsEvent(string statFilter, int statValue); if GetStage() == 30; if (statFilter == "Skill Increases"); Tracking code here;;;;;;;;;;;;;;;;;;;;; endif; endifEndEventString[] Property SkillName AutoPerk[] Property AlchemyPerks AutoPerk[] Property AlterationPerks AutoPerk[] Property ArcheryPerks AutoPerk[] Property BlockPerks AutoPerk[] Property ConjurationPerks AutoPerk[] Property DestructionPerks AutoPerk[] Property EnchantingPerks AutoPerk[] Property HeavyArmorPerks AutoPerk[] Property IllusionPerks AutoPerk[] Property LightArmorPerks AutoPerk[] Property LockpickingPerks AutoPerk[] Property OneHandedPerks AutoPerk[] Property PickpocketPerks AutoPerk[] Property RestorationPerks AutoPerk[] Property SmithingPerks AutoPerk[] Property SneakPerks AutoPerk[] Property SpeechPerks AutoPerk[] Property TwoHandedPerks AutoPerk[] Property TempPerks AutoInt[] Property AlchemyPerksBreakpoints AutoInt[] Property AlterationPerksBreakpoints AutoInt[] Property ArcheryPerksBreakpoints AutoInt[] Property BlockPerksBreakpoints AutoInt[] Property ConjurationPerksBreakpoints AutoInt[] Property DestructionPerksBreakpoints AutoInt[] Property EnchantingPerksBreakpoints AutoInt[] Property HeavyArmorPerksBreakpoints AutoInt[] Property IllusionPerksBreakpoints AutoInt[] Property LightArmorPerksBreakpoints AutoInt[] Property LockpickingPerksBreakpoints AutoInt[] Property OneHandedPerksBreakpoints AutoInt[] Property PickpocketPerksBreakpoints AutoInt[] Property RestorationPerksBreakpoints AutoInt[] Property SmithingPerksBreakpoints AutoInt[] Property SneakPerksBreakpoints AutoInt[] Property SpeechPerksBreakpoints AutoInt[] Property TwoHandedPerksBreakpoints AutoInt[] Property TempPerksBreakpoints AutoQuest Property ASAP AutoObjectReference[] Property AlchemyPerksAdded AutoObjectReference[] Property AlterationPerksAdded AutoObjectReference[] Property ArcheryPerksAdded AutoObjectReference[] Property BlockPerksAdded AutoObjectReference[] Property ConjurationPerksAdded AutoObjectReference[] Property DestructionPerksAdded AutoObjectReference[] Property EnchantingPerksAdded AutoObjectReference[] Property HeavyArmorPerksAdded AutoObjectReference[] Property IllusionPerksAdded AutoObjectReference[] Property LightArmorPerksAdded AutoObjectReference[] Property LockpickingPerksAdded AutoObjectReference[] Property OneHandedPerksAdded AutoObjectReference[] Property PickpocketPerksAdded AutoObjectReference[] Property RestorationPerksAdded AutoObjectReference[] Property SmithingPerksAdded AutoObjectReference[] Property SneakPerksAdded AutoObjectReference[] Property SpeechPerksAdded AutoObjectReference[] Property TwoHandedPerksAdded AutoObjectReference[] Property TempPerksAdded Auto
