pepperman35 Posted November 21, 2020 Author Share Posted November 21, 2020 Good copy on the assignMultiResource. I had formed an incorrect conclusion on its use based on an examination of the actors at Abernathy farm. HOW ARE YOU SPAWNING OR INSTANTIATING THE ACTORS ? Are you calling script function like ObjectReference ThisActor = PlaceActorAtMe(blah blah), or something else? The six NPCs are placed in the greenhouse in the CK. Each NPC is hooked to an EnableMarker (SIIR_RecruitBSController) via the EnableParent tab. The SIIR_RecruitBSController (EnableMarker) is set for Initially Disabled. The six NPCs are enabled via a terminal. This is accomplished via the following fragment: SIIR_RecruitBSBTGlobal.SetValueInt(1) SIIR_RecruitBSController.enable() IS THERE ANYTHING UNIQUE ABOUT THE OBJECTS ? Do you apply a keyword or actor value you can use to identify them as yours or the ones you are interested in? At present no, they are strictly vanilla assets; however, I could easily make them unique. Not sure how relevant it is but I noticed in my testing that when I tried to manually assign these six NPCs to the planters it was not successful, which seemed very odd to me. Link to comment Share on other sites More sharing options...
SKKmods Posted November 21, 2020 Share Posted November 21, 2020 Job #1 is to figure out how to get ObjectReferences for your actors. Without them you can not call the workshop script functions to assign them to a workshop or workshop objects. The reason you can not assign the actors manually is probably becuase the Actors and Objects script WorkshopID is still at the default -1 because you have not called any workshop scripts to register them. Yes despite having WorkshopItemLink. Script WorkshopID assignment is the MASSIVE and FUNDAMENTAL difference between having an isolated non reource producing workshop and a WorkshopParentScript registered resource producting workshop. No WorkshopID ... no resource scripting. Aside: and thats excatly what mod authors tend to f*** up and break when messing about with the Workshops array. Fixing that in script is easy once you have the ObjectReferences for your actors and resurces. Fixing that without script is not possible beacuse WorkshopIDs are dynamic, a workshop can have a different WorkshopID in each game. No, this is not the ObjectReference it is a dynamic script variable exposed as a property; (WorkshopREF as WorkshopScript).WorkshopID (ActorREF as WorkshopNPCScript).WorkshopID (ResourceObjectREF as WorkshopObjectScript).WorkshopID Solution #A Apply a unique keyword to my actors and another unique keyword to my resources. Have a start game enabled quest script run FindAllReferencesWithKeyword() on the keywords and run the workshop registration and resource assignment scripts on the results. Easy-as. Except that it may only work when the player is present and objects are loaded due to Object Persistence. Solution #B Attach scripts direct to the Actors and Resources that fire Event OnLoad() to run the workshop registration and resource assignment scripts on themselves. Downside is if the resources are not unique to you and are base game forms, your modifying shared assets which will affect every instance in the game which can be a disaster. Have to make them unique for this to work. Solution #C something else, getting bored now ... Link to comment Share on other sites More sharing options...
pepperman35 Posted November 21, 2020 Author Share Posted November 21, 2020 Well, nothing in this game is quite as easy as it appears. Both proposed solutions require the requires the NPCs and resources to be unique; therefore, it appears solution B more desirable from a layman's viewpoint. Therefore, I will assume the first step is to make the NPCs and planters unique by creating two unique keywords and adding them. BTW, thanks for your willingness to help. It is greatly appreciated. Link to comment Share on other sites More sharing options...
SKKmods Posted November 21, 2020 Share Posted November 21, 2020 The alternative is to script the spawn rather than hand place actors and resources, then everything becomes simple. (a) Create copies of say an xmarker myActorXmarker myPlantXmarker and place them in the game. Then run a start game enabled quest which finds the markers by a quest fill of GetIsID or FindAllreferencesOfType, spawns actors and plants at them and then runs the workshop registration scripts. OR; (b) Create copies of say default activator myActorActivator myPlantActivator and attach Event Onload Scripts to them which spawns the actor/plant and then runs the workshop registration scripts and then disables themselves. Trick is to tie therm all together. Can be done in script, but if you want specific actor working a specific plant you will need to create static linkedref associations; ActorMarker --- myActorPlantKeyword ---> PlantMarker | |myWorkshopKeyword myWorkshopKeyword |---------------> Workshop < ------------| Whilst I generally prefer to run central scripts on quests as they are easier to maintain and manage, in this instance (b) looks better as your not having to wait and detect when the markers are loaded as they are self referencing. The ONLY challenge I can envisage is the actor detecting "my plant is ready for me" ... but thats also doable. Link to comment Share on other sites More sharing options...
pepperman35 Posted November 21, 2020 Author Share Posted November 21, 2020 Two questions come to mind: 1) Can the script spawn be fired from a terminal after player takes possession of the island's workshop? 2) With respect to the tie in, would a linkedref chain work where the NPC could farm say three specific planters? Link to comment Share on other sites More sharing options...
SKKmods Posted November 21, 2020 Share Posted November 21, 2020 Yes sure spawning/activation can be started from a terminal no problem. Unfortunately the workshop script AssignActorToObject function can only specifiy the first object, for MultiResources it then automatically looks for similar unassigned resources using TryToAssignResourceType Link to comment Share on other sites More sharing options...
pepperman35 Posted November 21, 2020 Author Share Posted November 21, 2020 (edited) Update: The 20 vanilla GreenHsPlanter01Mutfruit planters are now identified as 00_GreenHsPlanter01Mutfruit with the unique keyword ObjectGreenHsPlanterMutfruit. The six NPCs now have the unique keyword ActorInstBotanist. ==================As a quick and dirty test, I did the xmarker thing for 1 of the NPC. Used the terminal to spawn them it, coupled with the code you provided earlier for auto assign. I was quite surprised to find out it worked (e.g., the workshop showed 6 food production). I wonder since myActorXMarker and myNPCActor will be incremented by 1 upto 6 if this could be done via arrays and a for I = 1 to 6 setup. It’s late so that might be gibberish. SIIR_RecruitBSBTGlobal.SetValueInt(1)Actor Spawned = myActorXMarker01.PlaceActorAtMe(myNPCActor01 ,1)Spawned.Disable()Spawned.SetLinkedref(myWorkshop,myWorkshopItemKeyword)Spawned.Enable()Spawned.SetValue(pWorkshopGuardPreference, 0.0) ; not guard so farm(pWorkshopParent as WorkshopParentScript).TryToAutoAssignActor((myWorkshop as WorkshopScript), (Spawned as WorkshopNPCScript)) Edited November 22, 2020 by pepperman35 Link to comment Share on other sites More sharing options...
pepperman35 Posted November 22, 2020 Author Share Posted November 22, 2020 Based on the success from yesterday, I took your advice and pressed forward with the scripted spawn vice hand placing the actors. Thus, I created the xMarkers myActorXMarker01 through myActorXMarker06. As the workshop assign actors script you provided, seemed to work via testing I opted to not spawn in the resources. I still wanted to spawn these NPCs via a terminal (e.g, Recruit botanists to the team) so I adapted what you provided. The following script fragment serves to spawn in the six NPC botanists, link them to the workshop, and allow the workshop to auto-assign them to farming. In addition, additional non-producing bioscientists are enabled for cosmetic purposes. While the code is not elegant it seems to work okay (e.g., tested multiple times today via new game). However, I am aware of my short comings WRT programing and its implications and would welcome your insight regarding implementation. Once again, thank you for your help! SIIR_RecruitBSBTGlobal.SetValueInt(1);; Spawn in the 1st NPC (Botantist), link them to the workshop and allow workshop to auto assign to farming;Actor Spawned = myActorXMarker01.PlaceActorAtMe(myNPCActor01 ,1)Spawned.Disable()Spawned.SetLinkedref(myWorkshop,myWorkshopItemKeyword)Spawned.Enable()Spawned.SetValue(pWorkshopGuardPreference, 0.0) ; not guard so farm(pWorkshopParent as WorkshopParentScript).TryToAutoAssignActor((myWorkshop as WorkshopScript), (Spawned as WorkshopNPCScript));; Repeat the process for the 2nd NPC;Actor Spawned2 = myActorXMarker02.PlaceActorAtMe(myNPCActor02 ,1)Spawned2.Disable()Spawned2.SetLinkedref(myWorkshop,myWorkshopItemKeyword)Spawned2.Enable()Spawned2.SetValue(pWorkshopGuardPreference, 0.0) ; not guard so farm(pWorkshopParent as WorkshopParentScript).TryToAutoAssignActor((myWorkshop as WorkshopScript), (Spawned2 as WorkshopNPCScript));; Repeat the process for the 3rd NPC;Actor Spawned3 = myActorXMarker03.PlaceActorAtMe(myNPCActor03 ,1)Spawned3.Disable()Spawned3.SetLinkedref(myWorkshop,myWorkshopItemKeyword)Spawned3.Enable()Spawned3.SetValue(pWorkshopGuardPreference, 0.0) ; not guard so farm(pWorkshopParent as WorkshopParentScript).TryToAutoAssignActor((myWorkshop as WorkshopScript), (Spawned3 as WorkshopNPCScript));; Repeat the process for the 4th NPC;Actor Spawned4 = myActorXMarker04.PlaceActorAtMe(myNPCActor04 ,1)Spawned4.Disable()Spawned4.SetLinkedref(myWorkshop,myWorkshopItemKeyword)Spawned4.Enable()Spawned4.SetValue(pWorkshopGuardPreference, 0.0) ; not guard so farm(pWorkshopParent as WorkshopParentScript).TryToAutoAssignActor((myWorkshop as WorkshopScript), (Spawned4 as WorkshopNPCScript));; Repeat the process for the 5th NPC;Actor Spawned5 = myActorXMarker05.PlaceActorAtMe(myNPCActor05 ,1)Spawned5.Disable()Spawned5.SetLinkedref(myWorkshop,myWorkshopItemKeyword)Spawned5.Enable()Spawned5.SetValue(pWorkshopGuardPreference, 0.0) ; not guard so farm(pWorkshopParent as WorkshopParentScript).TryToAutoAssignActor((myWorkshop as WorkshopScript), (Spawned5 as WorkshopNPCScript));; Repeat the process for the 6th NPC;Actor Spawned6 = myActorXMarker06.PlaceActorAtMe(myNPCActor06 ,1)Spawned6.Disable()Spawned6.SetLinkedref(myWorkshop,myWorkshopItemKeyword)Spawned6.Enable()Spawned6.SetValue(pWorkshopGuardPreference, 0.0) ; not guard so farm(pWorkshopParent as WorkshopParentScript).TryToAutoAssignActor((myWorkshop as WorkshopScript), (Spawned6 as WorkshopNPCScript));; Spawn in additional NPCs for cosmetic purposes;SIIR_RecruitBSController.enable() Link to comment Share on other sites More sharing options...
SKKmods Posted November 22, 2020 Share Posted November 22, 2020 Here is a working model I cobbeld from existing libraries which has multiple methods to do the plant:actor:workshop thing. Build a SKK_testTerminalSpawn at any workshop (Resources/Misc) If the terminal is associated with a workshop, the terminal menu SPAWN option will either: Detect all SKK_testTerminalPlantMarker xmarkers and place a GreenHsPlanter01Mutfruit at it and register them with the workshop.Detect all SKK_testTerminalPlantKeyword plants enable and register them with the workshop.Detect all GreenHsPlanter01Mutfruit if they are unassigned register them with the workshop.Detect all SKK_testTerminalActorMarker xmarkers and place a SKK_testTerminallWorkshopBotanist at it and register them with the workshop.Detect all SKK_testTerminalActorKeyword actors enable and register them with the workshop.If no ActorMarkers or ActorKeywords it will just spawn a pSKK_testTerminallWorkshopBotanist at each activated plant and register them with the workshop.If There are activated plants and actors, assign them to work and produce. Note: there is no way to FORCE continued actor/work object association or affinity. Any time a ResetWorkshop() is triggered they could be reassigned. That would need a ResetWorkshop detector and reassigner to constantly run which is nasty. As a quick test with no CK placed objects, [ player.placeatme 00100cab ] then build a terminal and run the spawn option. Terminal attached script source, bit longer than necessary with each variable explicity declared and lots of debug output to help follow the assignments: Scriptname SKK_testTerminalScript extends ObjectReference Const Group BaseGame Quest Property pWorkshopParent Auto Const Mandatory Flora Property pGreenHsPlanter01Mutfruit Auto Const Mandatory Keyword Property pWorkshopItemKeyword Auto Const Mandatory ActorValue Property pWorkshopRatingPopulation Auto Const Mandatory ActorValue Property pWorkshopGuardPreference Auto Const Mandatory EndGroup Group SKK ActorBase Property pSKK_testTerminallWorkshopBotanist Auto Const Mandatory Static Property pSKK_testTerminalPlantMarker Auto Const Mandatory Static Property pSKK_testTerminalActorMarker Auto Const Mandatory Keyword Property pSKK_testTerminalPlantKeyword Auto Const Mandatory Keyword Property pSKK_testTerminalActorKeyword Auto Const Mandatory Message Property pSKK_testTerminalNoWorkshop Auto Const Mandatory Message Property pSKK_testTerminalNoPlants Auto Const Mandatory Message Property pSKK_testAssignmentError Auto Const Mandatory GlobalVariable Property pSKK_testTerminalSpawnState Auto Const Mandatory ;Switches terminal display EndGroup ;********************************************************************************************************************** Function ActivatePlants() ; called by terminal script fragment using (akTerminalRef as SKK_testTerminalScript).ActivatePlants() If (pSKK_testTerminalSpawnState.GetValue() == 0) ; has not yet spawned ObjectReference ThisWorkshop = Self.GetLinkedRef(pWorkshopItemKeyword) If (ThisWorkshop == None) Debug.Trace("SKK_testTerminalScript.ActivatePlants ERROR NoWorkshop") pSKK_testTerminalNoWorkshop.Show() ; I am not linked to a Workshop. Else ObjectReference[] PlantMarkers = Self.FindAllReferencesOfType(pSKK_testTerminalPlantMarker, afRadius = 10240) ObjectReference[] PlantKeywords = Self.FindAllReferencesWithKeyword(pSKK_testTerminalPlantKeyword, afRadius = 10240) ObjectReference[] ActivatedPlants = New ObjectReference[0] If (PlantMarkers.Length == 0) && (PlantKeywords.Length == 0) Debug.Trace("SKK_testTerminalScript.ActivatePlants no markers or keywords looking for plants") ObjectReference[] PlantsFound = Self.FindAllReferencesOfType(pGreenHsPlanter01Mutfruit, afRadius = 10240) Int iPlantsFoundIndex = 0 While (iPlantsFoundIndex < PlantsFound.Length) ObjectReference ThisPlant = PlantsFound[iPlantsFoundIndex] If (ThisPlant.IsDeleted() == False) && (ThisPlant is WorkshopObjectScript) && ((ThisPlant as WorkshopObjectScript).IsActorAssigned() == FALSE) ActivatedPlants.Add(ThisPlant) Endif iPlantsFoundIndex +=1 EndWhile Endif Debug.Trace("SKK_testTerminalScript.ActivatePlants PlantMarkers " + PlantMarkers.Length) Debug.Trace("SKK_testTerminalScript.ActivatePlants PlantKeywords " + PlantKeywords.Length) Debug.Trace("SKK_testTerminalScript.ActivatePlants ActivatedPlants " + ActivatedPlants.Length) If (PlantMarkers.Length == 0) && (PlantKeywords.Length == 0) && (ActivatedPlants.Length == 0) Debug.Trace("SKK_testTerminalScript.ActivatePlants ERROR NoPlantMarkers NoPlantkeywords Noplants") pSKK_testTerminalNoPlants.Show() Else Int iPlantMarkersIndex = 0 While (iPlantMarkersIndex < PlantMarkers.Length) ObjectReference ThisMarker = PlantMarkers[iPlantMarkersIndex] ObjectReference ThisPlant = ThisMarker.PlaceAtMe(pGreenHsPlanter01Mutfruit, 1,abForcePersist = false, abInitiallyDisabled = false, abDeleteWhenAble = false) ActivatedPlants.Add(ThisPlant) iPlantMarkersIndex +=1 EndWhile Int iPlantKeywordsIndex = 0 While (iPlantKeywordsIndex < PlantKeywords.Length) ObjectReference ThisPlant = PlantKeywords[iPlantKeywordsIndex] ActivatedPlants.Add(ThisPlant) iPlantKeywordsIndex +=1 EndWhile If (ActivatedPlants.Length == 0) pSKK_testTerminalNoPlants.Show() Else ActivateActors(ActivatedPlants, ThisWorkshop) EndIf EndIf EndIf EndIf EndFunction ;********************************************************************************************************************** Function ActivateActors(ObjectReference[] ActivatedPlants, ObjectReference ThisWorkshop) If (ActivatedPlants == None) || (ActivatedPlants.Length == 0) ; all functions validate conditions incase thay are called direct pSKK_testTerminalNoPlants.Show() ElseIf (ThisWorkshop == None) pSKK_testTerminalNoWorkshop.Show() ; I am not linked to a Workshop. Else ObjectReference[] ActorMarkers = Self.FindAllReferencesOfType(pSKK_testTerminalActorMarker, afRadius = 10240) ObjectReference[] ActorKeywords = Self.FindAllReferencesWithKeyword(pSKK_testTerminalActorKeyword, afRadius = 10240) ObjectReference[] ActivatedActors = New ObjectReference[0] Int iWorkshopID = (ThisWorkshop as WorkshopScript).GetWorkshopID() If (ActorMarkers.Length > 0) Int iActorMarkersIndex = 0 While (iActorMarkersIndex < ActorMarkers.Length) ObjectReference ThisActorMarker = ActorMarkers[iActorMarkersIndex] ObjectReference ThisActor = ThisActorMarker.PlaceActorAtMe(pSKK_testTerminallWorkshopBotanist, aiLevelMod = 4, akZone = None) ActivatedActors.Add(ThisActor) iActorMarkersIndex +=1 EndWhile EndIf If (ActorKeywords.Length > 0) Int iActorKeywordsIndex = 0 While (iActorKeywordsIndex < ActorKeywords.Length) ObjectReference ThisActor = ActorKeywords[iActorKeywordsIndex] If (ThisActor as Actor).IsDead() == False && (ThisActor is WorkshopNPCScript) && ((ThisActor as WorkshopNPCScript).bIsWorker == FALSE) ;is not currently assigned to an object ActivatedActors.Add(ThisActor) EndIf iActorKeywordsIndex +=1 EndWhile EndIf If (ActivatedActors.Length == 0) ; No Markers or keywords so create actors Int iActivatedPlantsIndex = 0 While (iActivatedPlantsIndex < ActivatedPlants.Length) ObjectReference ThisPlant = ActivatedPlants[iActivatedPlantsIndex] ObjectReference ThisActor = ThisPlant.PlaceActorAtMe(pSKK_testTerminallWorkshopBotanist, aiLevelMod = 4, akZone = None) ThisActor.MoveTo(ThisPlant, 64.0, 64.0, 0.0) ActivatedActors.Add(ThisActor) iActivatedPlantsIndex +=1 EndWhile EndIf Debug.Trace("SKK_testTerminalScript.ActivateActors ActorMarkers " + ActorMarkers.Length) Debug.Trace("SKK_testTerminalScript.ActivateActors ActorKeywords " + ActorKeywords.Length) Debug.Trace("SKK_testTerminalScript.ActivateActors ActivatedActors " + ActivatedActors.Length) Debug.Trace("SKK_testTerminalScript.ActivateActors ActivatedPlants " + ActivatedPlants.Length) If (ActivatedActors.Length > 0) && (ActivatedActors.Length == ActivatedPlants.Length) ; have plants, have actors Int iActivatedIndex = 0 While (iActivatedIndex < ActivatedActors.Length) ObjectReference ThisActor = ActivatedActors[iActivatedIndex] ObjectReference ThisPlant = ActivatedPlants[iActivatedIndex] ThisPlant.Enable() If ((ThisPlant as WorkshopObjectScript).WorkshopID != iWorkshopID) (pWorkshopParent as WorkshopParentScript).BuildObjectPUBLIC((ThisPlant as ObjectReference), (ThisWorkshop as WorkshopScript)) Debug.Trace("SKK_testTerminalScript.ActivateActors ThisPlant.WorkshopID " + ThisPlant + " " + (ThisPlant as WorkshopObjectScript).WorkshopID ) EndIf ThisActor.Enable() ThisActor.SetValue(pWorkshopRatingPopulation, 1) ThisActor.SetValue(pWorkshopGuardPreference, 0) (ThisActor as WorkshopNPCScript).SetCommandable(TRUE) (ThisActor as WorkshopNPCScript).SetAllowCaravan(FALSE) (ThisActor as WorkshopNPCScript).SetAllowMove(FALSE) If ((ThisActor as WorkshopNPCScript).GetWorkshopID() != iWorkshopID) (pWorkshopParent as WorkshopParentScript).AddActorToWorkshopPUBLIC((ThisActor as WorkshopNPCScript), (ThisWorkshop as WorkshopScript), bResetMode = false) Debug.Trace("SKK_testTerminalScript.ActivateActors ThisActor.WorkshopID " + ThisActor + " " + (ThisActor as WorkshopNPCScript).GetWorkshopID() ) EndIf (pWorkshopParent as WorkshopParentScript).AssignActorToObjectPUBLIC((ThisActor as WorkshopNPCScript), (ThisPlant as WorkshopObjectScript), bResetMode = false) Debug.Trace("SKK_testTerminalScript.ActivateActors " + iActivatedIndex + " Assigned Actor " + ThisActor + " To Plant " + ThisPlant) iActivatedIndex +=1 EndWhile If (iActivatedIndex > 0) pSKK_testTerminalSpawnState.SetValue(1) ; lock terminal spawn option Else pSKK_testAssignmentError.Show(ActivatedActors.Length,ActivatedPlants.Length) ; Spawn can not be completed. | Errors assigning %.0f actors to %.0f plants. EndIf Else pSKK_testAssignmentError.Show(ActivatedActors.Length,ActivatedPlants.Length) ; Spawn can not be completed. | Errors assigning %.0f actors to %.0f plants. EndIf EndIf EndFunction ;********************************************************************************************************************** Link to comment Share on other sites More sharing options...
pepperman35 Posted November 23, 2020 Author Share Posted November 23, 2020 Thanks mate, much appreciated. Link to comment Share on other sites More sharing options...
Recommended Posts