Safe way to use CreateFullActorCopy

Post » Fri Nov 18, 2011 4:59 pm

Like a responsible modder (:P), I've been reading up on CreateFullActorCopy, and it looks like there's a problem with all the inventory items being duplicated along with the Actor, but they remain as references even after executing DeleteFullActorCopy.

What I'm trying is this ....

Cast spell on dead actor ...
Dead actor is copied (along with inventory) as a ghost ...
Then actor is deleted.

But does anyone know of a safe anti-bloat-friendly way to get rid of all the copied inventory items?
User avatar
Emilie Joseph
 
Posts: 3387
Joined: Thu Mar 15, 2007 6:28 am

Post » Fri Nov 18, 2011 4:10 pm

The problem with CreateFullActorCopy is that if there are scripted items in its inventory, the engine creates a new Base Forms, which cannot be removed from the game, bloating the savegame.

A safer approach might be using PlaceAtMe to create the new actor and multiple AddItem's to provide him with the same inventory as the dead one.
User avatar
I’m my own
 
Posts: 3344
Joined: Tue Oct 10, 2006 2:55 am

Post » Fri Nov 18, 2011 4:06 pm

The problem with CreateFullActorCopy is that if there are scripted items in its inventory, the engine creates a new Base Forms, which cannot be removed from the game, bloating the savegame.

A safer approach might be using PlaceAtMe to create the new actor and multiple AddItem's to provide him with the same inventory as the dead one.


Thanks! So how about this ...

ScriptName MakeGhostAppearScriptRef SelfRef GhostCopyRef EquippedObject00Ref EquippedObject01...etc.Begin ScriptEffectStart    Set Self to GetSelf    Set EquippedObject00 to Self.GetEquippedObject 0    Set EquippedObject01 to Self.GetEquippedObject 1    ...etc.	    Set GhostCopy to ( Self.PlaceAtMe Self 5, 5, 0 )	    Resurrect GhostCopy    GhostCopy.ResetHealth    GhostCopy.SetGhost 1    GhostCopy.AddItem EquippedObject00 1    GhostCopy.AddItem EquippedObject01 1    GhostCopy.AddItem EquippedObject02 1    ...etc.EndBegin ScriptEffectFinish    GhostCopy.Disable    GhostCopy.DeleteReferenceEnd


I'm wondering about the line "Self.PlaceAtMe Self." What if "Self" is a leveled Actor? Will it generate another random Actor or will it dutifully copy the target reference (race, hair, etc.)? And would it also give it it's own leveled equipment?

Edit: Uh oh. According to the http://cs.elderscrolls.com/constwiki/index.php/DeleteReference on the Construction Wiki, this command will only work if the reference is NOT an actor.
User avatar
Spaceman
 
Posts: 3429
Joined: Wed May 23, 2007 10:09 am

Post » Fri Nov 18, 2011 8:34 am

Should work, but better set Self to GetBaseObject, as I am not sure PaceAtMe will accept a reference FormID. I am not familiar with leveled lists, but I guess that, once spawned, the actor becomes a reference as any other.

Not deleting actors is not that much of a problem as the engine will get rid of them during the clean up process (Cell reset).

Also you should create a ForEach loop to cycle thru the NPC inventory, as you don't know in advance how many items will be there.
User avatar
Ezekiel Macallister
 
Posts: 3493
Joined: Fri Jun 22, 2007 12:08 pm

Post » Fri Nov 18, 2011 9:28 am

Should work, but better set Self to GetBaseObject, as I am not sure PaceAtMe will accept a reference FormID. I am not familiar with leveled lists, but I guess that, once spawned, the actor becomes a reference as any other.

Not deleting actors is not that much of a problem as the engine will get rid of them during the clean up process (Cell reset).

Also you should create a ForEach loop to cycle thru the NPC inventory, as you don't know in advance how many items will be there.


I had to look up "ForEach loop" :D Definitely new and complicated for me. Would that look like this?

ScriptName MakeGhostAppearScriptRef SelfRef GhostCopyRef ItemRef ContainerBegin ScriptEffectStart    Set Self to GetBaseObject    Set GhostCopy to ( Self.PlaceAtMe Self 5, 5, 0 )    Let Container := Self            Resurrect GhostCopy    GhostCopy.ResetHealth    GhostCopy.SetGhost 1    ForEach Item <- Container	        ;Only interested in equipped items        If Item.IsEquipped            Print Item.GetName + " is equipped by " + Container.GetName            Item.CopyIR GhostCopy        Endif    LoopEnd


Does the ForEach Loop automatically stop itself when it finds an item it already found before?

Also, because you can't add an item to an NPC and force them to equip it in the same frame, I'm wondering if the ForEach Loop would work for me in this application. Because with each pass of the loop, it seems like I only get one chance to do something with the inventory reference before ForEach moves on to the next reference in the container.

About resetting the cell, I know that cells aren't supposed to actually reset until the Player re-enters them, so I guess that would mean that these PlaceAtMe references would still stick around unless the Player loads the area where they eventually ended up.
User avatar
Stacy Hope
 
Posts: 3391
Joined: Thu Jun 22, 2006 6:23 am

Post » Fri Nov 18, 2011 8:09 am

ForEach requires a reference, so it should be: "Let Container := GetSelf"


Does the ForEach Loop automatically stop itself when it finds an item it already found before?

ForEach will walk the inventory one group of identical items at a time (check " Inventory References" in OBSE docs for details)


Also, because you can't add an item to an NPC and force them to equip it in the same frame, I'm wondering if the ForEach Loop would work for me in this application. Because with each pass of the loop, it seems like I only get one chance to do something with the inventory reference before ForEach moves on to the next reference in the container.

The loop looks fine. Just add the following lines after "Item.CopyIR GhostCopy" to equip the item (basItem being a new ref var):
let basItem := Item.GetBaseObject
GhostCopy.equipitem basItem
Adding and Equipping an item in the same frame always works for me. Don't know why it does not work for others.



About resetting the cell, I know that cells aren't supposed to actually reset until the Player re-enters them, so I guess that would mean that these PlaceAtMe references would still stick around unless the Player loads the area where they eventually ended up.

Last week I re-ran an old test of mine and confirmed that PlaceAtMe'd actors do get purged from the savegame after 72 hours, even if the player does not return to the cell. I will run it again, moving the actors to a dummy cell and see what happens. I will let you know.
User avatar
Maya Maya
 
Posts: 3511
Joined: Wed Jul 05, 2006 7:35 pm

Post » Fri Nov 18, 2011 5:37 pm

Last week I re-ran an old test of mine and confirmed that PlaceAtMe'd actors do get purged from the savegame after 72 hours, even if the player does not return to the cell. I will run it again, moving the actors to a dummy cell and see what happens. I will let you know.


Thanks a ton, QQuix. I have a working script for a spell to cast on a dead actor, release their ghost (who is identical to them), and then have the ghost vanish. That ForEach Loop works beautifully. If you test the auto-removal of PlaceAtMe references again, I'd love to know the result. That remains my only concern, but it's definitely promising!

Scriptname ReleaseGhostScriptRef SelfRef GhostCopyRef ContainerRef ItemRef BaseItemBegin ScriptEffectStart    Set Self to GetSelf    ;Must be dead    If ( Self.GetDead ) && ( Self.IsActor )        ;Continue    Else        PlaySound MagicFailureSoundDestruction        Dispel ReleaseGhost        Return    Endif    Set Self to GetBaseObject    Set GhostCopy to ( Player.PlaceAtMe Self 1, 15, 0 )    Let Container := GetSelf    PlaySound SPLRestorationHit    ForEach Item <- Container        ;Only interested in equipped items        If Item.IsEquipped            Print Item.GetName + " is equipped by " + Container.GetName            Item.CopyIR GhostCopy            Let BaseItem := Item.GetBaseObject            GhostCopy.EquipItem BaseItem        Endif    Loop    aaPaladinGhostCasterRef.MoveTo GhostCopy 10 10 10    aaPaladinGhostCasterRef.Cast GoAwayGhost GhostCopy    GhostCopy.ModActorValue2 Aggression -100    GhostCopy.StopCombat    GhostCopy.AddSpell AbGhostNPC    GhostCopy.SetGhost 1End


And the following makes the ghost go away after a delay ...

ScriptName GoAwayGhostScriptRef SelfBegin ScriptEffectStart    Set Self to GetSelfEndBegin ScriptEffectFinish    Self.RemoveAllItems    Self.Disable       Self.PositionCell 0, 0, 0, 0, aaMyDummyCell    Self.KillEnd

User avatar
Joe Bonney
 
Posts: 3466
Joined: Tue Jul 17, 2007 12:00 pm


Return to IV - Oblivion