Preventing script-related crash

Post » Sat Nov 17, 2012 3:24 am

A relatively simple follower-outfit changing script causes a somewhat random CTD. According to the papyrus logs, it has something to do with the actor's loaded 3D.

Here's the script:

Spoiler
[/size][size=3]Scriptname PSDefaultFollowerAliasScript extends ReferenceAlias [/size][size=3]Package Property PlayerFollowerPackage Auto [/size][size=3]Package Property PlayerFollowerCombatOverridePackage Auto[/size][size=3]Package Property PlayerFollowerCombatOverridePackageExterior Auto [/size][size=3]Outfit Property DefaultOutfit Auto [/size][size=3]Outfit Property ArmorBladesOutfit Auto [/size][size=3]Outfit Property NullOutfit Auto [/size][size=3]Faction Property BladesFaction Auto[/size][size=3]Faction Property CurrentFollowerFaction Auto[/size][size=3]WEAPON Property FollowerHuntingBow Auto[/size][size=3]WEAPON Property DummyDagger Auto [/size][size=3]Ammo Property FollowerIronArrow Auto[/size][size=3]ObjectReference Property DA07QuestObjectChestREF Auto ;Basically, a persistent container that's not used much, does not respawn, and is empty.[/size][size=3]Function ChangeFollowerOutfit(bool SettingUp = true)[/size][size=3]GetActorRef().RemoveAllItems(DA07QuestObjectChestREF)[/size][size=3]if (SettingUp)[/size][size=3]GetActorRef().SetOutfit(NullOutfit)[/size][size=3]else[/size][size=3]if (GetActorRef().IsInFaction(BladesFaction))[/size][size=3]GetActorRef().SetOutfit(ArmorBladesOutfit)[/size][size=3]else[/size][size=3]GetActorRef().SetOutfit(DefaultOutfit)[/size][size=3]endif[/size][size=3]endif[/size][size=3]GetActorRef().RemoveAllItems()[/size][size=3]Utility.Wait(1)[/size][size=3]DA07QuestObjectChestREF.RemoveAllItems(GetActorRef())[/size][size=3]GetActorRef().AddItem(DummyDagger, 1)[/size][size=3]GetActorRef().EquipItem(DummyDagger)[/size][size=3]GetActorRef().RemoveItem(DummyDagger, 1)[/size][size=3]endFunction[/size][size=3]auto STATE waiting[/size][size=3]Event OnPackageStart (Package akNewPackage)[/size][size=3]if (akNewPackage == PlayerFollowerPackage) && (GetActorRef().IsInFaction(CurrentFollowerFaction))[/size][size=3]int BowCount = (GetActorRef().GetItemCount(FollowerHuntingBow))[/size][size=3]int ArrowCount = (GetActorRef().GetItemCount(FollowerIronArrow))[/size][size=3]GetActorRef().RemoveItem(FollowerHuntingBow, BowCount)[/size][size=3]GetActorRef().RemoveItem(FollowerIronArrow, ArrowCount)[/size][size=3]ChangeFollowerOutfit()[/size][size=3]gotostate("following")[/size][size=3]endif[/size][size=3]endEvent[/size][size=3]endSTATE[/size][size=3]STATE following[/size][size=3]Event OnPackageChange (Package akOldPackage)[/size][size=3]if (akOldPackage == PlayerFollowerPackage) || (akOldPackage == PlayerFollowerCombatOverridePackage) || (akOldPackage == PlayerFollowerCombatOverridePackageExterior)[/size][size=3]if (GetActorRef().GetCurrentPackage() != PlayerFollowerPackage) && (GetActorRef().GetCurrentPackage() != PlayerFollowerCombatOverridePackage) && (GetActorRef().GetCurrentPackage() != PlayerFollowerCombatOverridePackageExterior)[/size][size=3]ChangeFollowerOutfit(false)[/size][size=3]gotostate("waiting")[/size][size=3]endif[/size][size=3]endif[/size][size=3]endEvent[/size][size=3]Event OnDeath(Actor akKiller)[/size][size=3]ChangeFollowerOutfit(false)[/size][size=3]gotostate("waiting")[/size][size=3]endEvent[/size][size=3]endSTATE[/size][size=3]

The concept is simple: remove all of the follower's items to an external container, set their outfit to an empty outfit ("NullOutfit"), remove all their old items back, and force them to equip them (adding and removing the "DummyDagger" item). When they're dismissed, remove all their items to an external container, set their outfit back to their default (or Blades armor), remove their items again (so they aren't carrying multiple copies of their normal outfit), give them their inventory back, and force them to equip it.

It works in theory and mostly in practice, but it occassionally crashes the game, especially in difficualt-to-render areas with low FPS, or after combat and other hardware-intensive situations. It has to do with the double "RemoveAllItems()" call, and trying to render all of it, apparently.

There are also a few miscellaneous issues:

-The follower briefly appears in their undergarments while their inventory flies to Dawnstar and back. A necessary evil, I suppose -- I could move them away and then back, but at least this way they're present.
-If the follower is recruited into the Blades, they immediately change into Blades armor -- any way to check if the alias-attached "BladesChangeOutfit" script is in the "done" state?
-Sometimes the follower equips every weapon in their inventory -- bows, arrows, and weapons in both hands, if able. I don't know if it actually affects their combat prowess.

On the plus side, changes to follower equipment (smithing, enchanting) is retained, and items flagged as being part of an outfit (taken off of dead bodies or pickpocketed off someone) aren't eaten by the "SetOutfit()" call.


...How do I get rid of the demned "[size]" code?
User avatar
Skrapp Stephens
 
Posts: 3350
Joined: Mon Aug 06, 2007 5:04 am

Post » Sat Nov 17, 2012 9:19 am

For starters...
Spoiler
ScriptName PSDefaultFollowerAliasScript Extends ReferenceAliasActor rThisActorAmmo Property FollowerIronArrow AutoFaction Property BladesFaction AutoFaction Property CurrentFollowerFaction AutoObjectReference Property DA07QuestObjectChestREF Auto ; Basically, a persistent container that is not used much, does not respawn, and is empty.Outfit Property DefaultOutfit AutoOutfit Property ArmorBladesOutfit AutoOutfit Property NullOutfit AutoFormList Property PackageFLST Auto ; PlayerFollowerPackage + PlayerFollowerCombatOverridePackage + PlayerFollowerCombatOverridePackageExteriorWeapon Property FollowerHuntingBow AutoWeapon Property DummyDagger AutoEvent OnInit()	rThisActor = GetActorRef()EndEventFunction ChangeFollowerOutfit(Bool SettingUp = True)	rThisActor.RemoveAllItems(DA07QuestObjectChestREF)	If SettingUp		rThisActor.SetOutfit(NullOutfit)	ElseIf rThisActor.IsInFaction(BladesFaction)		rThisActor.SetOutfit(ArmorBladesOutfit)	Else		rThisActor.SetOutfit(DefaultOutfit)	EndIf	rThisActor.RemoveAllItems()	Utility.Wait(1)	DA07QuestObjectChestREF.RemoveAllItems(rThisActor)	rThisActor.AddItem(DummyDagger, 1)	rThisActor.EquipItem(DummyDagger)	rThisActor.RemoveItem(DummyDagger, 1)EndFunctionAuto State Waiting	Event OnPackageStart(Package akNewPackage)		If akNewPackage == PackageFLST.GetAt(1) As Package ; Make sure you use the right index			If rThisActor.IsInFaction(CurrentFollowerFaction)				rThisActor.RemoveItem(FollowerHuntingBow, rThisActor.GetItemCount(FollowerHuntingBow))				rThisActor.RemoveItem(FollowerIronArrow, rThisActor.GetItemCount(FollowerIronArrow))				ChangeFollowerOutfit()				GoToState("Following")			EndIf		EndIf	EndEventEndStateState Following	Event OnPackageChange(Package akOldPackage)		If PackageFLST.HasForm(akOldPackage)			If !PackageFLST.HasForm(rThisActor.GetCurrentPackage())				ChangeFollowerOutfit(False)				GoToState("Waiting")			EndIf		EndIf	EndEvent	Event OnDeath(Actor akKiller)		ChangeFollowerOutfit(False)		GoToState("Waiting")	EndEventEndState
User avatar
Lisha Boo
 
Posts: 3378
Joined: Fri Aug 18, 2006 2:56 pm


Return to V - Skyrim