Anyone interested in optimizing my scripts?

Post » Tue Mar 15, 2011 5:18 am

I know one of the key elements for any well-written script is that it is as efficient as possible, i.e. has as small of a processing footprint as possible. I've written three scripts that are unfortunately quite large, and am having trouble thinking of ways to shrink them. Does anyone want to take a shot at it?

I have attached a copy of the worst offender as a "spoiler" below. This particular script unequips armor if it's broken, replaces that armor with the highest value clothing (of the right type) in inventory, and also scales the enchantments on any magic armor according to the condition (health) of that armor. All armor types are supported, and it does this for the player and all NPCs. Much of the "bulk" of the script deals with multi-slot issues (for example, if slot 2 = Upper Body is open, and slot 3 = Lower Body is broken, then slot 18 = Upper + Lower Body should be available to reequip). Thanks in advance!

Spoiler
;Script written by BFG July, 2010;You may modify this script without notifying me if this heading is not removed, and I am credited in your work!scriptName BFGEnchantedArmor00short fQuestDelayTimeshort ArmorCountershort numbereffectsshort ReEquipshort ObjCurHPfloat ObjTtlHPfloat Percentagefloat tempafloat tempbfloat tempcref Actref Objref probearray_var ArmorSlotarray_var clothingarray_var itemarray_var probevaluearray_var finalarray_var origmagnarray_var origeffectnumarray_var origeffectnumusedarray_var originitializedbegin GameModeset fQuestDelayTime to 1if GetGameLoaded     if GetOBSEVersion < 18          MessageBox "BFG's Enhanced Armory requires Oblivion Script Extender (OBSE) v.18 or higher to run!", "OK"          StopQuest BFGEA00          endif     let ArmorSlot := ar_Construct Array     let tempa := -1     While tempa < 5     let tempa := tempa + 1     let ArmorSlot[tempa] := tempa     loop     let ArmorSlot[6] := 13     let ArmorSlot[7] := 15     let ArmorSlot[8] := 18     let ArmorSlot[9] := 19     let ArmorSlot[10] := 20     let probevalue := ar_construct Map     let final := ar_construct Map     let origmagn := ar_construct StringMap     let origeffectnum := ar_construct StringMap     let originitialized := ar_construct StringMap     endifset Act to PlayerWhile Act     let ReEquip := 0     let ArmorCounter := -1     While ArmorCounter < 10          let ArmorCounter := ArmorCounter + 1          let tempa := ArmorSlot[ArmorCounter]          let final[tempa] := 0          let ObjCurHP := Act.GetEquippedCurrentHealth tempa          if ObjCurHP > 0               let probevalue[tempa] := 999999          ;prohibit slot change by default               Continue               else               let Obj := (Act.GetEquippedObject tempa)               if (IsArmor Obj == 0)                    let probevalue[tempa] := 500000     ;can only override with multislotted clothing                    Continue                    else                    if (CompareName "Arena" Obj) || (IsQuestItem Obj) || (GetObjectHealth Obj <= 0) || ArmorCounter == 6 || ((ArmorCounter == 0) && (GetBipedSlotMask Obj > 0))                         let probevalue[tempa] := 999999          ;prohibit slot change by default                         Continue                         else                         let ReEquip := 1                         let probevalue[tempa] := 0          ;open slot since armor was broken                         Act.UnequipItemNS Obj                         endif                    endif               endif          loop     if ReEquip == 1          let ArmorCounter := 11          While ArmorCounter > 0               ;this loop sets flags on additional slots               let ArmorCounter := ArmorCounter - 1               let tempa := probevalue[ArmorSlot[ArmorCounter]]               if tempa >= 500000 && ArmorCounter <= 1                    let probevalue[1 - ArmorCounter] := tempa               ;if helm or hood is prohibited then both should be                    elseif tempa == 0                                                       ;open slot                    if ArmorCounter == 3 && eval (probevalue[2] < 999999)                         let probevalue[18] := 0                                   ;cuirass and greaves open, 18 should be too                         if eval (probevalue[5] < 999999)                              let probevalue[19] := 0                              ;feet open, 19 should be too                              if eval (probevalue[4] < 999999)                                   let probevalue[20] := 0                         ;hands open, 20 should be too                                   endif                              endif                         endif                    if ArmorCounter >= 8                         let probevalue[2] := 0                         let probevalue[3] := 0                         if ArmorCounter >= 9                              let probevalue[5] := 0                              let probevalue[18] := 0                              if ArmorCounter >= 10                                   let probevalue[4] := 0                                   let probevalue[19] := 0                                   endif                              endif                         endif                    endif               loop          let clothing := Act.GetItems 22          ForEach item <- clothing               let Obj := item["Value"]               let ArmorCounter := GetEquipmentSlot Obj               if ArmorCounter > 0 || GetBipedSlotMask Obj == 0          ;if ArmorCounter = 0 & GetBiped > 0, unrecognized type                    let tempa := probevalue[ArmorCounter]                    if tempa <= (GetFullGoldValue Obj) && (IsPlayable Obj)                         let probevalue[ArmorCounter] := GetFullGoldValue Obj                         let final[ArmorCounter] := Obj                         endif                    endif               loop          let ArmorCounter := -1          While ArmorCounter < 10               let ArmorCounter := ArmorCounter + 1               let Obj := final[ArmorSlot[ArmorCounter]]               if Obj > 0                    Act.EquipItem2NS Obj                    endif               loop          endif     let origeffectnumused := ar_construct StringMap     let numbereffects := Act.GetActiveEffectCount     let tempa := -1     While tempa < numbereffects - 1          let tempa := tempa + 1          set Obj to Act.GetNthActiveEffectEnchantObject tempa          if (IsArmor Obj) == 0               Continue               else               let ArmorCounter := Act.GetEquipmentSlot Obj               let ObjCurHP := Act.GetEquippedCurrentHealth ArmorCounter               let ObjTtlHP := (GetObjectHealth Obj) + 0.00001               let Percentage := ObjCurHP / ObjTtlHP               let tempb := 0               let tempb := originitialized[$Act+$Obj]               if tempb != 1                    let originitialized[$Act+$Obj] := 1                    let origeffectnum[$Act+$Obj] := 1                    let origmagn[$Act+$Obj+$1] := Act.GetNthActiveEffectMagnitude tempa                    let tempc := tempa                    While tempc < numbereffects - 1                         let tempc := tempc + 1                         set probe to Act.GetNthActiveEffectEnchantObject tempc                         if Obj != probe                              Continue                              else                              let origeffectnum[$Act+$Obj] := origeffectnum[$Act+$Obj] + 1                              let origmagn[$Act+$Obj+$origeffectnum[$Act+$Obj]] := Act.GetNthActiveEffectMagnitude tempc                              endif                         loop                    endif               let tempc := 1               let tempc := origeffectnumused[$Act+$Obj] + 1               let origeffectnumused[$Act+$Obj] := tempc               let tempb := (Percentage * 0.8 * origmagn[$Act+$Obj+$tempc]) + (0.2 * origmagn[$Act+$Obj+$tempc]) + 0.5               Act.SetNthActiveEffectMagnitude tempb tempa               endif          loop     if Act == Player          set Act to GetFirstRef 35 2          else          set Act to GetNextRef          endif     loopend

User avatar
NAkeshIa BENNETT
 
Posts: 3519
Joined: Fri Jun 16, 2006 12:23 pm

Post » Mon Mar 14, 2011 4:50 pm

I have attached a copy of the worst offender as a "spoiler" below. (It's difficult to read as formatted below so I can provide a better copy if needed.) This particular script unequips armor if it's broken, replaces that armor with the highest value clothing (of the right type) in inventory, and also scales the enchantments on any magic armor according to the condition (health) of that armor. All armor types are supported, and it does this for the player and all NPCs. Thanks in advance!

Better copy (add code tags):
Spoiler
;Script written by BFG July, 2010;You may modify this script without notifying me if this heading is not removed, and I am credited in your work!scriptName BFGEnchantedArmor00short fQuestDelayTimeshort ArmorCountershort numbereffectsshort ReEquipshort ObjCurHPfloat ObjTtlHPfloat Percentagefloat tempafloat tempbfloat tempcref Actref Objref probearray_var ArmorSlotarray_var clothingarray_var itemarray_var probevaluearray_var finalarray_var origmagnarray_var origeffectnumarray_var origeffectnumusedarray_var originitializedbegin GameModeset fQuestDelayTime to 1if GetGameLoaded     if GetOBSEVersion < 18          MessageBox "BFG's Enhanced Armory requires Oblivion Script Extender (OBSE) v.18 or higher to run!", "OK"          StopQuest BFGEA00          endif     let ArmorSlot := ar_Construct Array     let tempa := -1     While tempa < 5     let tempa := tempa + 1     let ArmorSlot[tempa] := tempa     loop     let ArmorSlot[6] := 13     let ArmorSlot[7] := 15     let ArmorSlot[8] := 18     let ArmorSlot[9] := 19     let ArmorSlot[10] := 20     let probevalue := ar_construct Map     let final := ar_construct Map     let origmagn := ar_construct StringMap     let origeffectnum := ar_construct StringMap     let originitialized := ar_construct StringMap     endifset Act to PlayerWhile Act     let ReEquip := 0     let ArmorCounter := -1     While ArmorCounter < 10          let ArmorCounter := ArmorCounter + 1          let tempa := ArmorSlot[ArmorCounter]          let final[tempa] := 0          let ObjCurHP := Act.GetEquippedCurrentHealth tempa          if ObjCurHP > 0               let probevalue[tempa] := 999999          ;prohibit slot change by default               Continue               else               let Obj := (Act.GetEquippedObject tempa)               if (IsArmor Obj == 0)                    let probevalue[tempa] := 500000     ;can only override with multislotted clothing                    Continue                    else                    if (CompareName "Arena" Obj) || (IsQuestItem Obj) || (GetObjectHealth Obj <= 0) || ArmorCounter == 6 || ((ArmorCounter == 0) && (GetBipedSlotMask Obj > 0))                         let probevalue[tempa] := 999999          ;prohibit slot change by default                         Continue                         else                         let ReEquip := 1                         let probevalue[tempa] := 0          ;open slot since armor was broken                         Act.UnequipItemNS Obj                         endif                    endif               endif          loop     if ReEquip == 1          let ArmorCounter := 11          While ArmorCounter > 0               ;this loop sets flags on additional slots               let ArmorCounter := ArmorCounter - 1               let tempa := probevalue[ArmorSlot[ArmorCounter]]               if tempa >= 500000 && ArmorCounter <= 1                    let probevalue[1 - ArmorCounter] := tempa               ;if helm or hood is prohibited then both should be                    elseif tempa == 0                                                       ;open slot                    if ArmorCounter == 3 && eval (probevalue[2] < 999999)                         let probevalue[18] := 0                                   ;cuirass and greaves open, 18 should be too                         if eval (probevalue[5] < 999999)                              let probevalue[19] := 0                              ;feet open, 19 should be too                              if eval (probevalue[4] < 999999)                                   let probevalue[20] := 0                         ;hands open, 20 should be too                                   endif                              endif                         endif                    if ArmorCounter >= 8                         let probevalue[2] := 0                         let probevalue[3] := 0                         if ArmorCounter >= 9                              let probevalue[5] := 0                              let probevalue[18] := 0                              if ArmorCounter >= 10                                   let probevalue[4] := 0                                   let probevalue[19] := 0                                   endif                              endif                         endif                    endif               loop          let clothing := Act.GetItems 22          ForEach item <- clothing               let Obj := item["Value"]               let ArmorCounter := GetEquipmentSlot Obj               if ArmorCounter > 0 || GetBipedSlotMask Obj == 0          ;if ArmorCounter = 0 & GetBiped > 0, unrecognized type                    let tempa := probevalue[ArmorCounter]                    if tempa <= (GetFullGoldValue Obj) && (IsPlayable Obj)                         let probevalue[ArmorCounter] := GetFullGoldValue Obj                         let final[ArmorCounter] := Obj                         endif                    endif               loop          let ArmorCounter := -1          While ArmorCounter < 10               let ArmorCounter := ArmorCounter + 1               let Obj := final[ArmorSlot[ArmorCounter]]               if Obj > 0                    Act.EquipItem2NS Obj                    endif               loop          endif     let origeffectnumused := ar_construct StringMap     let numbereffects := Act.GetActiveEffectCount     let tempa := -1     While tempa < numbereffects - 1          let tempa := tempa + 1          set Obj to Act.GetNthActiveEffectEnchantObject tempa          if (IsArmor Obj) == 0               Continue               else               let ArmorCounter := Act.GetEquipmentSlot Obj               let ObjCurHP := Act.GetEquippedCurrentHealth ArmorCounter               let ObjTtlHP := (GetObjectHealth Obj) + 0.00001               let Percentage := ObjCurHP / ObjTtlHP               let tempb := 0               let tempb := originitialized[$Act+$Obj]               if tempb != 1                    let originitialized[$Act+$Obj] := 1                    let origeffectnum[$Act+$Obj] := 1                    let origmagn[$Act+$Obj+$1] := Act.GetNthActiveEffectMagnitude tempa                    let tempc := tempa                    While tempc < numbereffects - 1                         let tempc := tempc + 1                         set probe to Act.GetNthActiveEffectEnchantObject tempc                         if Obj != probe                              Continue                              else                              let origeffectnum[$Act+$Obj] := origeffectnum[$Act+$Obj] + 1                              let origmagn[$Act+$Obj+$origeffectnum[$Act+$Obj]] := Act.GetNthActiveEffectMagnitude tempc                              endif                         loop                    endif               let tempc := 1               let tempc := origeffectnumused[$Act+$Obj] + 1               let origeffectnumused[$Act+$Obj] := tempc               let tempb := (Percentage * 0.8 * origmagn[$Act+$Obj+$tempc]) + (0.2 * origmagn[$Act+$Obj+$tempc]) + 0.5               Act.SetNthActiveEffectMagnitude tempb tempa               endif          loop     if Act == Player          set Act to GetFirstRef 35 2          else          set Act to GetNextRef          endif     loopend

This :
Spoiler
    if GetOBSEVersion < 18          MessageBox "BFG's Enhanced Armory requires Oblivion Script Extender (OBSE) v.18 or higher to run!", "OK"          StopQuest BFGEA00          endif
should definitely be :
Spoiler
    if GetOBSEVersion < 18          MessageBox "BFG's Enhanced Armory requires Oblivion Script Extender (OBSE) v.18 or higher to run!", "OK"          StopQuest BFGEA00          RETURN          endif

Stoping the quest does not stop the script
I don't have time now to read further :)
User avatar
Nikki Hype
 
Posts: 3429
Joined: Mon Jan 01, 2007 12:38 pm

Post » Mon Mar 14, 2011 1:42 pm

Hey, thanks! Obviously I didn't even know there WAS a script tag, I'll be sure and use that in the future.

It's unfortunate that StopQuest doesn't end processing of the script, would there be any way for me to do so? I'll be sure and add the Return command in the meantime.
User avatar
Amy Masters
 
Posts: 3277
Joined: Thu Jun 22, 2006 10:26 am

Post » Tue Mar 15, 2011 3:44 am

StopQuest doesn't stop the script from finishing its execution for the current frame. The script will not run on subsequent frames until the quest is restarted. Example:
scn thingshort varbegin gamemode  if var > 5    stopquest questThing    ; return !    let var += 1  endifend

var gets up to 6, stopquest is called, the statements following stopquest are executed, var becomes 7, the script reaches 'end' and does not run again. Uncomment the return if you want the script to stop processing immediately.
User avatar
Je suis
 
Posts: 3350
Joined: Sat Mar 17, 2007 7:44 pm

Post » Tue Mar 15, 2011 1:04 am

Thanks for the suggestion! I have removed the "GetGameLoaded" section entirely and moved it to a master script, which kicks off this "child" script and 3 others if the proper version of OBSE is found installed.
Here's the updated script. Any further suggestions on optimization are appreciated - I'll be more than happy to give you credit for the assistance. I also have 2 other scripts that need looked at, but this is the worst one.

Spoiler
;Script written by BFG July, 2010;You may modify this script without notifying me if this heading is not removed, and I am credited in your work!scriptName BFGEnchantedArmorScaleshort doonceshort ArmorCountershort numbereffectsshort ReEquipshort ObjCurHPfloat fQuestDelayTimefloat ObjTtlHPfloat Percentagefloat tempafloat tempbfloat tempcstring_var itembrokenref Actref Objref probearray_var ArmorSlotarray_var clothingarray_var itemarray_var probevaluearray_var finalarray_var origmagnarray_var origeffectnumarray_var origeffectnumusedarray_var originitializedbegin GameModeset fQuestDelayTime to 1if GetGameLoaded	let probevalue := ar_construct Map	let final := ar_construct Map	set itembroken to ( GetStringGameSetting sCantEquipBrokenItem )	if doonce == 0		let ArmorSlot := ar_Construct Array		let tempa := -1		While tempa < 10		let tempa := tempa + 1		if tempa < 8			let ArmorSlot[tempa] := tempa			else			let ArmorSlot[tempa] := tempa + 10			endif		loop		let ArmorSlot[6] := 13		let ArmorSlot[7] := 15		let origmagn := ar_construct StringMap		let origeffectnum := ar_construct StringMap		let originitialized := ar_construct StringMap		endif	endifset Act to PlayerWhile Act	let ReEquip := 0	let ArmorCounter := -1	While ArmorCounter < 10		let ArmorCounter := ArmorCounter + 1		let tempa := ArmorSlot[ArmorCounter]		let ObjCurHP := Act.GetEquippedCurrentHealth tempa		if ObjCurHP > 0			let probevalue[tempa] := 999999		;prohibit slot change			Continue			else			let Obj := (Act.GetEquippedObject tempa)			if (IsArmor Obj == 0)				let probevalue[tempa] := 500000	;slot unequipped or is clothing.  can only override with a robe etc.				Continue				else				if (CompareName "Arena" Obj) || (IsQuestItem Obj) || (GetObjectHealth Obj <= 0) || ArmorCounter == 6 || ((ArmorCounter == 0) && (GetBipedSlotMask Obj > 0))					let probevalue[tempa] := 999999		;prohibit slot change					Continue					else					let ReEquip := 1					let probevalue[tempa] := 0		;open slot since armor was broken					Act.UnequipItemNS Obj					endif				endif			endif		loop	if ReEquip == 1		let ArmorCounter := 11		While ArmorCounter > 0			;this loop sets flags on additional slots			let final[tempa] := 0			let ArmorCounter := ArmorCounter - 1			let tempa := probevalue[ArmorSlot[ArmorCounter]]			if tempa != 500000 && ArmorCounter <= 1				let probevalue[1 - ArmorCounter] := tempa			;if helm or hood is open/prohibited then both should be				elseif tempa == 0											;open slot				if ArmorCounter >= 8					let probevalue[2] := 0					let probevalue[3] := 0					if ArmorCounter >= 9						let probevalue[5] := 0						let probevalue[18] := 0						if ArmorCounter >= 10							let probevalue[4] := 0							let probevalue[19] := 0							endif						endif					endif				endif			loop		let tempa := probevalue[ArmorSlot[3]]		if tempa == 0 && eval (probevalue[2] < 999999)			let probevalue[18] := 0							;cuirass and greaves open, 18 should be too			if eval (probevalue[5] < 999999)				let probevalue[19] := 0						;feet open, 19 should be too				if eval (probevalue[4] < 999999)					let probevalue[20] := 0					;hands open, 20 should be too					endif				endif			endif		let clothing := Act.GetItems 22		ForEach item <- clothing			let Obj := item["Value"]			let ArmorCounter := GetEquipmentSlot Obj			if ArmorCounter > 0 || GetBipedSlotMask Obj == 0		;if ArmorCounter = 0 & GetBiped > 0, unrecognized type				let tempa := probevalue[ArmorCounter]				if tempa <= (GetFullGoldValue Obj) && (IsPlayable Obj)					let probevalue[ArmorCounter] := GetFullGoldValue Obj					let final[ArmorCounter] := Obj					endif				endif			loop		let ArmorCounter := -1		While ArmorCounter < 10			let ArmorCounter := ArmorCounter + 1			let Obj := final[ArmorSlot[ArmorCounter]]			if Obj > 0				Act.EquipItem2NS Obj				endif			loop		endif	let origeffectnumused := ar_construct StringMap	let numbereffects := Act.GetActiveEffectCount	let tempa := -1	While tempa < numbereffects - 1		let tempa := tempa + 1		set Obj to Act.GetNthActiveEffectEnchantObject tempa		if (IsArmor Obj) == 0			Continue			else			let ArmorCounter := Act.GetEquipmentSlot Obj			let ObjCurHP := Act.GetEquippedCurrentHealth ArmorCounter			let ObjTtlHP := (GetObjectHealth Obj) + 0.00001			let Percentage := ObjCurHP / ObjTtlHP			let tempb := 0			let tempb := originitialized[$Act+$Obj]			if tempb != 1				let originitialized[$Act+$Obj] := 1				let origeffectnum[$Act+$Obj] := 1				let origmagn[$Act+$Obj+$1] := Act.GetNthActiveEffectMagnitude tempa				let tempc := tempa				While tempc < numbereffects - 1					let tempc := tempc + 1					set probe to Act.GetNthActiveEffectEnchantObject tempc					if Obj != probe						Continue						else						let origeffectnum[$Act+$Obj] := origeffectnum[$Act+$Obj] + 1						let origmagn[$Act+$Obj+$origeffectnum[$Act+$Obj]] := Act.GetNthActiveEffectMagnitude tempc						endif					loop				endif			let tempc := 1			let tempc := origeffectnumused[$Act+$Obj] + 1			let origeffectnumused[$Act+$Obj] := tempc			let tempb := (Percentage * 0.8 * origmagn[$Act+$Obj+$tempc]) + (0.2 * origmagn[$Act+$Obj+$tempc]) + 0.5			Act.SetNthActiveEffectMagnitude tempb tempa			endif		loop	if Act == Player		set Act to GetFirstRef 35 2		else		set Act to GetNextRef		endif	looplet doonce := 1endbegin Menumode 1002set fQuestDelayTime to 0.01set ArmorCounter to -1while ArmorCounter < 10	let ArmorCounter := ArmorCounter + 1	let tempa := ArmorSlot[ArmorCounter]	if player.GetEquippedCurrentHealth tempa <= 0		set Obj to player.GetEquippedObject tempa		if IsArmor Obj			if (CompareName "Arena" Obj) || (IsQuestItem Obj) || (GetObjectHealth Obj <= 0) || ArmorCounter == 6 || ((ArmorCounter == 0) && (GetBipedSlotMask Obj > 0))				Continue				else				player.UnequipItemNS Obj				MessageEX "%z" itembroken				endif			endif		endif	loopend

User avatar
Ysabelle
 
Posts: 3413
Joined: Sat Jul 08, 2006 5:58 pm


Return to IV - Oblivion