gooboo Posted April 4, 2017 Share Posted April 4, 2017 I have a question regarding the raiders/gunners you can capture with the Wasteland Workshop mod and why the npcs disappear when I go into cities or interior cells after making them followers. I've been using the Wasteland Workshop mod to capture raiders and gunners and, after a last-man-standing type of battle, recruiting the victorious npc into my own "gang" using mods and the console command. This method of turning npcs into followers has worked just fine with the regular raiders you come across in dungeons or outdoors. Those npcs follow me around everywhere, don't disappear when loading new cells, etc. No problems at all. Something is different with the raider and gunner npcs that spawn from the cages in the WW dlc, but I don't know what exactly it is. Whenever I walk into a city like Goodneighbor, or any interior in general, the npc disappears (or de-spawns). I tried moveto player and player.moveto, but it doesn't work. Nothing moves over to me, and when I use the move.to function I just move to where the npc was last standing before I went inside to another cell, and the npc is gone. As I mentioned previously this doesn't happen with any of my other raider/gunner followers, so I know this can work. I figure there's something in the dlc that makes these npcs de-spawn, I just don't know what it is or where to find it. I have little talent with scripting, so I don't really know where to look. I looked up the "npc" that spawns the raiders/gunners in the CK but I didn't find anything that would make them de-spawn when loading new cells. Is this something that's typically controlled with scripts? Is there some other function that I'm not aware of? I hope someone with more knowledge of the CK can help me out here. Thanks! Link to comment Share on other sites More sharing options...
Greslin Posted April 5, 2017 Share Posted April 5, 2017 I don't have a concrete answer for you, but I do have rampant speculation. Something to think about, anyway. If the "Can't Open Doors" flag is set in an NPC's race record, problems happen with them trying to cross cells or enter interiors. I ran afoul of this in my "Realistic Cats" mod, and the "No Doors for Dogmeat" mod author did as well. This was the first thing that crossed my mind after reading your post - if somehow that flag is being set, or the NPC's race is changed to one with the flag set, that probably could do it. I looked through the DLC race records and did a text search through all the base scripts, but I didn't find anything like that. But it could still be there and I just didn't see it. Like I said, speculation. Link to comment Share on other sites More sharing options...
gooboo Posted April 5, 2017 Author Share Posted April 5, 2017 I tried removing the DLC02TamedActorScript from the raider npc, (DLC02LvlRaiderMixed) and that didn't help. If it's scripted, it's not that particular script. Link to comment Share on other sites More sharing options...
gooboo Posted April 9, 2017 Author Share Posted April 9, 2017 I was looking through more scripts today, and I thought I would try and see what the script for the actual workshop cages looks like. Without knowing much about scripting, it looks more promising- Scriptname DLC02:WorkshopCageScript extends workshopobjectscriptgroup cagePropertiesActorBase property myCapturedActorBase auto const{ actor or leveled list to use for captured actor }FormList property myCapturedActorFormList auto const{ OPTIONAL - use this instead of myCapturedActorBase - will pick randomly from the form list }ActorBase property myCapturedActorBaseSpecial auto const{ OPTIONAL - special actor or leveled list to use if myCapturedActorSpecialChance is rolled }float property myCapturedActorSpecialChance = 0.05 auto const{ chance of capturing myCapturedActorBaseSpecial }ActorValue property myCapturedActorResource auto const{ actor value - resource - to add to cage when capture actor is in it }string property myNode = "CreatureNode01" auto constbool property HasCapturedActor auto hidden conditional{ TRUE after an actor is inside the cage - ready to be released }DLC02:DLC02WorkshopAttackStarterScript property DLC02WorkshopAttackStarter auto const mandatoryendGroupfloat captureTimeStart = 0.0 ; set to GameDaysPassed when built, used to roll for capturefloat maxCaptureTime = 5.0 const ; used for capture roll - at maxCaptureTime (game days), 100% chance to capturefloat lastCaptureCheck = 0.0 ; timestamp of last time we checked for capturefloat minCaptureCheckInterval = 0.25 const ; at least this many gamedays must pass before we check againbool bIsPlayerSleeping = false ; currently the only way to tell if player is sleeping is to roll our ownfunction CheckForCapture()if IsDestroyed() == false && IsPowered()debug.trace(self + "CheckForCapture: captureTimeStart=" + captureTimeStart)float currentTime = Utility.GetCurrentGameTime(); how long has passed since capture start?float captureTime = currentTime - captureTimeStart; has enough time passed since last check?float lastCheckTimePassed = currentTime - lastCaptureCheckif lastCaptureCheck == 0.0; never checked means just built - set last capture check to now but don't actually roll for capturedebug.trace(self + " CheckForCapture: cage just built - initialize lastCaptureCheck")lastCaptureCheck = currentTimeelseif lastCheckTimePassed >= minCaptureCheckInterval; capture chance:float captureChance = captureTime/maxCaptureTimefloat captureRoll = Utility.RandomFloat(0.0, 1.0)debug.trace(self + "CheckForCapture: captureTime=" + captureTime + ", captureChance=" + captureChance + ", captureRoll=" + captureRoll)if captureRoll <= captureChanceCaptureActor()endif; update lastCaptureChecklastCaptureCheck = currentTimeelsedebug.trace(self + " CheckForCapture: last check was " + lastCheckTimePassed + " days ago, don't check again until " + minCaptureCheckInterval + " days have passed")endifendifendFunction; override parent function for special handlingbool function ModifyResourceDamage(ActorValue akActorValue, float aiDamageMod); ModifyResourceDamage is only called in 2 places:; WorkshopParent.ResetWorkshop - we definitely want to ignore that (to not release the creature during the reset process); WorkshopScript.RepairDamageToResource - auto repairing, which we also don't want to dofloat baseValue = GetBaseValue(akActorValue)bool returnVal = falseif baseValue > 0if aiDamageMod > 0; positive damage - clear captured actorif HasCapturedActorreturnVal = true ; actually damagedCaptureActor(false)endifendifendifreturn returnValendFunctionfunction HandleCreation(bool bNewlyBuilt = true)Parent.HandleCreation(bNewlyBuilt)if bNewlyBuiltCaptureActor(false)endifRegisterForPlayerSleep()endFunctionEvent OnDestructionStageChanged(int aiOldStage, int aiCurrentStage)Parent.OnDestructionStageChanged(aiOldStage, aiCurrentStage)if aiCurrentStage == 0; I've been repaired - ready to capture actorCaptureActor(false)endifEndEventevent OnLoad()debug.trace(self + " OnLoad")Parent.OnLoad(); if captured actor, make sure cage is in right stateif HasCapturedActorCheckCageState()else; otherwise, roll for captureCheckForCapture()endif; register for sleep on loadRegisterForPlayerSleep()EndEventevent OnUnload()debug.trace(self + " OnUnload")Parent.OnUnload()CheckForCapture(); unregister on unload so I don't persistUnregisterForPlayerSleep()EndEventEvent OnWorkshopObjectDestroyed(ObjectReference akActionRef); when stored or scrapped, make sure to clear capture actor valueCaptureActor(false)UnregisterForPlayerSleep()EndEventEvent OnPlayerSleepStart(float afSleepStartTime, float afDesiredSleepEndTime, ObjectReference akBed)debug.trace(self + " OnPlayerSleepStart")bIsPlayerSleeping = trueCheckForCapture()EndEventEvent OnPlayerSleepStop(bool abInterrupted, ObjectReference akBed)bIsPlayerSleeping = falsedebug.trace(self + " OnPlayerSleepStop: HasCapturedActor=" + HasCapturedActor); wait for capture lock to clear (if sleep is interrupted while capturing an actor)int failsafeCount = 0while captureBusy && failsafeCount < 10debug.trace(self + "OnPlayerSleepStop: ... waiting for lock to clear... " + failsafeCount)utility.wait(1.0)failsafeCount += 1endWhileCheckCageState()EndEventbool captureBusy = false ; thread lockfunction CaptureActor(bool bIsCaptured = true)debug.trace(self + " CaptureActor " + bIsCaptured)int failsafeCount = 0while captureBusy && failsafeCount < 10debug.trace(self + " ... waiting for lock to clear... " + failsafeCount)utility.wait(1.0)failsafeCount += 1endWhile; lockcaptureBusy = truebool wasAlreadyCaptured = HasCapturedActorif bIsCapturedif IsDestroyed() == falseif myCapturedActorResourceSetValue(myCapturedActorResource, 1.0)endifif wasAlreadyCaptured == false; state changeWorkshopScript workshopRef = WorkshopParent.GetWorkshop(workshopID)debug.trace(self + " workshopRef=" + workshopRef + ", workshopID=" + workshopID)if workshopRef && myCapturedActorResource; attack values are Variable type not Resource type, so have to modify them directlyWorkshopParent.ModifyResourceData(myCapturedActorResource, workshopRef, 1.0)endif; set player ownership so enemies will attack the cageSetFactionOwner(WorkshopParent.PlayerFaction)endifHasCapturedActor = trueCheckCageState()endifelsecaptureTimeStart = Utility.GetCurrentGameTime()if myCapturedActorResourceSetValue(myCapturedActorResource, 0)endifif wasAlreadyCaptured == true; state changeWorkshopScript workshopRef = WorkshopParent.GetWorkshop(workshopID)debug.trace(self + " workshopRef=" + workshopRef + ", workshopID=" + workshopID)if myCapturedActorResource; attack values are Variable type not Resource type, so have to modify them directlyWorkshopParent.ModifyResourceData(myCapturedActorResource, workshopRef, -1.0)endifendifHasCapturedActor = falseendif; clear lockcaptureBusy = falseendFunctionfunction HandleDestruction()OpenCage()Parent.HandleDestruction()endFunctionfunction HandlePowerStateChange(bool bPowerOn = true)if bPowerOn == false && HasCapturedActorSetDestroyed(true)DamageObject(9999.0)endifParent.HandlePowerStateChange(bPowerOn)endFunctionfunction OpenCage()debug.trace(self + " OpenCage: HasCapturedActor=" + HasCapturedActor)if HasCapturedActorWorkshopScript workshopRef = WorkshopParent.GetWorkshop(workshopID); for now very simple - create actorActorBase actorBaseToCreateFormList formListToCreate = myCapturedActorFormListActorBase actorBaseToUse = myCapturedActorBase; roll for specialif myCapturedActorBaseSpecialif Utility.RandomFloat(0.0, 1.0) <= myCapturedActorSpecialChanceactorBaseToUse = myCapturedActorBaseSpecialformListToCreate = NONEendifendifif formListToCreate; pick randomly from form listint randomPick = Utility.RandomInt(0, formListToCreate.GetSize()-1)actorBaseToCreate = formListToCreate.GetAt(randomPick) as ActorBaseelseactorBaseToCreate = actorBaseToUseendif; clear ownership so actor is allowed to sit in cageSetFactionOwner(NONE); create non-temp actor (will call Delete() on untamed/non-domestic animal actors); place at holding marker in cell with special encounter zone so LVL uses player's level, not encounter zone levelActor capturedActor = DLC02WorkshopAttackStarter.DLC02CageSpawnMarker.PlaceActorAtMe(actorBaseToCreate, 4, DLC02WorkshopAttackStarter.DLC02PlayerLevelZone) as ActorcapturedActor.Disable(); move to cage nodecapturedActor.MoveToNode(self, myNode); link to cage for initial sit packagecapturedActor.SetLinkedRef(self)capturedActor.Enable()debug.trace(self + " OpenCage: capturedActor=" + capturedActor)CaptureActor(false); wait a bit to do the rest to give actor time to init into furnitureutility.wait(0.5)bool bShouldAddToWorkshop = true ; add creatures to workshop by default; if a tameable actor, see if they are tamed as they come out of cageDLC02TamedActorScript tamedActor = capturedActor as DLC02TamedActorScriptif tamedActorif tamedActor.CheckForTame(workshopRef)tamedActor.StopCombatAlarm()endifelse; normal workshop NPC - just add to workshop (always non-hostile)if capturedActor is WorkshopNPCScriptdebug.trace(self + " OpenCage - workshopNPC - add to workshop")WorkshopParent.AddActorToWorkshopPUBLIC(capturedActor as WorkshopNPCScript, workshopRef, bResetMode = true)endifendif; unlink to cagecapturedActor.SetLinkedRef(NONE)endifendFunctionfunction CheckCageState()debug.trace(self + " CheckCageState: bIsPlayerSleeping=" + bIsPlayerSleeping); make sure cage is in closed anim stateif HasCapturedActorPlayAnimation("TurnOffNoTransition")endifif bIsPlayerSleeping == false ; don't open cage while player sleeping - actor ends up in bad state; if not powered with captured creature, openif HasCapturedActor && IsPowered() == falseHandlePowerStateChange(false)endifendifendFunction In particular, this little bit here caught my eye- ; create non-temp actor (will call Delete() on untamed/non-domestic animal actors); place at holding marker in cell with special encounter zone so LVL uses player's level, not encounter zone levelActor capturedActor = DLC02WorkshopAttackStarter.DLC02CageSpawnMarker.PlaceActorAtMe(actorBaseToCreate, 4, DLC02WorkshopAttackStarter.DLC02PlayerLevelZone) as ActorcapturedActor.Disable() I don't actually know much about scripting, so I hope someone with more knowledge than I can take a look and help me out here, but is this thing saying something about the actors being "deleted" if they're marked as untamed or non-domestic? That could explain why they disappear when loading a new cell or using the coc console command. Link to comment Share on other sites More sharing options...
Recommended Posts