Jump to content

Establishing a Workbench Alias to Allow Scripts to Be Attached


Recommended Posts

I am wanting to create a workbench alias so that I can attach a script to each of the workbenches that you find throughout the game world.

 

Attaching a script to each of the workbenches allows me to make use of the OnWorkshop... event variants at each of the settlements.

 

I have attached a previous incarnation of the script directly to the workbench forms, and the script's worked fine. However, I'd rather not edit vanilla forms, so I thought creating an alias would be the go.

 

My issue is that I can't see the script running at all (which I can tell from notifications that are displayed at certain events), so I'm assuming that I haven't set the alias up correctly. I have only done quite limited experimenting with aliases in the past, so that's very likely the case.

 

As shown below, I have attempted to alias the various workbenches that I've put in a couple form lists. I'll note that I am using the same form lists to add an activator to the workshop workbenches (which is working fine), so there's nothing wrong with the form lists themselves (to my knowledge). I've only added the base game workbenches to the form lists to ensure that there are no DLC requirements. However, I've added any DLC workbenches to those form lists via script if those .esm files are loaded, so there shouldn't be any issues there.

 

To put things simply, I need help creating an alias so that I can attach scripts to the various workshop workbenches in the game.

 

http://i.imgur.com/yZs27Uy.png

 

The mod in its current state can be found in the following dropbox link. It's in a relatively complete state, as there's really only bug testing left to do (this being just one of them). For some context, it's version 2 of my Workbench Control Panel mod.

 

Any help would be appreciated.

Link to comment
Share on other sites

When are you starting your quest? That's when the alias is filled. If it's start game enabled and workbench isn't in loaded area, it will be none.

 

You can do ref collection alias with only one condition: GetIsID WorkShopWorkBench. Then do SQV your quest in console and you see all workbenches in your alias(should be 28 in vanilla game?). If something is missing, you might need additional aliases/conditions for some workbenches. Or you can just use those form lists you made.

 

You can put max initial count high as you want, it will fill up to that point. You can put 50 and the game finds 28, it will not fail because of that. Just don't do Allow Reuse in quest or you can get same workbench several times.

 

I actually just tested it, and with only GetIsID WorkSHopWorkBench, max initial count 50, nothing ticked in settings, and it lists 28 ref aliases in the collection.

Link to comment
Share on other sites

Hey, thanks for the response. The save-game did actually start right next to the Sanctuary workbench, so the In Loaded Area flag didn't cause any issues. I originally didn't have that box ticked, but I ended up messing around with a few things because I was running out of ideas. The quest itself starts enabled with the game.

 

I have only ever messed around with reference aliases, and never with reference collection aliases. Am I correct in assuming that the only real advantage to creating a reference collection alias over a reference alias is that you don't need to create a new reference alias for each reference that you want to keep track of? That is, I don't need to create 28 reference aliases for each of the WorkshopWorkbenches in the vanilla game (Workbench0, Workbench1, ..., Workbench27)?

 

Using the SQV 07000F9C console command (0x000F9C being the quest FormID) reveals that both the reference alias and the reference collection alias have correctly registered each of the workshop references (that are linked to the WorkshopWorkbench containers). That is, it returns the FormID's of SanctuaryWorkshopREF (010250FE), RedRocketWorkshopREF (01054BAE), etc.

 

However, I've had no luck whatsoever getting any feedback from the script that I've attached to either the reference alias or the reference collection aliases. I've added Debug.Notifications to each of the various OnWorkshop... events that I'm using, and I even added the OnActivate() event to the script, to see if I could trigger anything by activating the workbench. I haven't been able to trigger any of the notifications that I've embedded in the script, so there's still something wrong somewhere.

 

The OnWorkshop... events are apparently sent to the workshop reference. Considering the reference collection alias is keeping track of each of the workshop references, the events should be triggered, but aren't.

 

Another issue I'm having with the reference collection alias is the use of the Self.GetReference() function. I can't see any equivalent function on this page. I'm sure that there's some way that I can achieve the same functionality in the script that I've attached to the reference collection alias, but I haven't been able to find it so far. At the moment I've just got that section of the script commented out, because the script functions fine without it. However, I will need to resolve this issue before I release the mod.

Link to comment
Share on other sites

Hmmh, I have only used ref collection with actors. I have a script where I need to do something when actor from collection dies.. and this is how I "identify" which one is it:

Event OnDying(ObjectReference AkSenderRef, Actor akKiller)

int index = Self.Find(akSenderRef)

Actor tempActor = Self.GetAt(index) as Actor

;do stuff to tempActor
endEvent

Self <- means the whole alias collection in this case so it finds the akSenderRef from the collection. So yes, you are correct that the only reason to use ref collection is to make it easier if you have lot of aliases.

 

But maybe it's not good in this case.. but reading https://www.creationkit.com/fallout4/index.php?title=RefCollectionAlias_Script , I can see it should work same way with OnActivate. I guess there might be something wrong with your script? Maybe you could post just the script in code tag? I don't have experience with workshops, so I can't propably help more than this.. but maybe someone else can.

Edited by vkz89q
Link to comment
Share on other sites

Oh, I wasn't aware that the reference collection alias functioned as an array. Thanks, that solves that issue.

 

Here's what the script currently looks like. It compiles fine, but I don't get any notifications when I trigger those events in-game. I'll have a look at making those edits to the Self.GetReference() sections of the script shortly. I haven't made them prior to making this post as solving this issue won't fix whatever's wrong with how I've created these aliases.

 

I've provided the mod as a whole in a dropbox link in the first post, as it was when I first made this thread.

 

 

 

[code=auto:0]ScriptName WCP_QUST_Workbench_RefCollAlias Extends RefCollectionAlias

; ==========
; Properties
; ==========

; --------------------
; Auto Const Mandatory
; --------------------

Actor Property PlayerRef Auto Const Mandatory

ActorValue Property Food 	Auto Const Mandatory
ActorValue Property Safety 	Auto Const Mandatory
ActorValue Property Water 	Auto Const Mandatory

GlobalVariable Property WCP_GLOB_DisplayNotifications Auto Const Mandatory

Keyword Property WorkshopLinkCenter 	Auto Const Mandatory
Keyword Property WorkshopLinkContainer 	Auto Const Mandatory
Keyword Property WorkshopLinkSandbox 	Auto Const Mandatory
Keyword Property WorkshopLinkSpawn 		Auto Const Mandatory

WCP_QUST_Housekeeping_Script Property WCP_QUST_Housekeeping Auto Const Mandatory

WorkshopParentScript Property WorkshopParent Auto Const Mandatory

; ======
; Events
; ======

Event OnActivate(ObjectReference akSenderRef, ObjectReference akActionRef)
	If (akActionRef == PlayerRef)
		Debug.Notification(asNotificationText = "Hello World!")
	EndIf
	
	Debug.Notification(asNotificationText = "Derp")
EndEvent

Auto State Disabled
	; Do nothing
EndState

State Busy
	; Do nothing
EndState

State Enabled
	; Build Mode Entered or Exited
	Event OnWorkshopMode(ObjectReference akSenderRef, Bool aStart)
		; ---------
		; Variables
		; ---------
		
		Bool BuildMode
		Bool Repaired
		
		; ----------
		; Operations
		; ----------
		
		Debug.Notification(asNotificationText = "OnWorkshopMode")
		
		GoToState("Busy")
		
		BuildMode = True
		Repaired = False
		
		ConditionalSettlementAttacks(BuildMode, Repaired, None)
		
		GoToState("Enabled")
	EndEvent

	; Workshop Object Scrapped or Stored
	Event OnWorkshopObjectDestroyed(ObjectReference akSenderRef, ObjectReference akActionRef)
		; ---------
		; Variables
		; ---------
		
		Bool BuildMode
		Bool Repaired
		
		; ----------
		; Operations
		; ----------
		
		Debug.Notification(asNotificationText = "OnWorkshopObjectDestroyed")
		
		GoToState("Busy")
		
		BuildMode = False
		Repaired = False
		
		ConditionalSettlementAttacks(BuildMode, Repaired, akActionRef)
		
		GoToState("Enabled")
	EndEvent

	; Workshop Object Constructed
	Event OnWorkshopObjectPlaced(ObjectReference akSenderRef, ObjectReference akReference)
		; ---------
		; Variables
		; ---------
		
		Bool BuildMode
		Bool Repaired
		
		; ----------
		; Operations
		; ----------
		
		Debug.Notification(asNotificationText = "OnWorkshopObjectPlaced")
		
		GoToState("Busy")
		
		BuildMode = False
		Repaired = False
		
		ConditionalSettlementAttacks(BuildMode, Repaired, akReference)
		
		GoToState("Enabled")
	EndEvent

	; Workshop Object Repaired
	Event OnWorkshopObjectRepaired(ObjectReference akSenderRef, ObjectReference akReference)
		; ---------
		; Variables
		; ---------
		
		Bool BuildMode
		Bool Repaired
		
		; ----------
		; Operations
		; ----------
		
		Debug.Notification(asNotificationText = "OnWorkshopObjectRepaired")
		
		GoToState("Busy")
		
		BuildMode = False
		Repaired = True
		
		ConditionalSettlementAttacks(BuildMode, Repaired, akReference)
		
		GoToState("Enabled")
	EndEvent
EndState

; =========
; Functions
; =========

Bool Function IsWorkshopSafe(Bool BuildMode, Bool DisplayNotifications, Bool Repaired, Int Index, ObjectReference ConstructableObject)
	; ---------
	; Variables
	; ---------
	
	Int FoodCount
	Int RequiredSafetyCount
	Int SafetyCount
	Int WaterCount
	
	; ----------
	; Operations
	; ----------
	
	FoodCount = WorkshopParent.Workshops[Index].GetValue(akAV = Food) As Int
	SafetyCount = WorkshopParent.Workshops[Index].GetValue(akAV = Safety) As Int
	WaterCount = WorkshopParent.Workshops[Index].GetValue(akAV = Water) As Int
	
	; As the repaired event does not include the attributes of the repaired constructable object in the sum
	If (Repaired == True)
		FoodCount += ConstructableObject.GetValue(akAV = Food) As Int
		WaterCount += ConstructableObject.GetValue(akAV = Water) As Int
		SafetyCount += ConstructableObject.GetValue(akAV = Safety) As Int
	EndIf
	
	RequiredSafetyCount = WCP_QUST_Housekeeping.FoodMultiplier*FoodCount+WCP_QUST_Housekeeping.WaterMultiplier*WaterCount
	
	If (SafetyCount >= RequiredSafetyCount)
		; The workshop has sufficient defense to scare off raiders
		
		If (WorkshopParent.Workshops[Index].AllowAttacks == True)
			WorkshopParent.Workshops[Index].AllowAttacks = False
			
			Return True
		EndIf
	ElseIf (SafetyCount < RequiredSafetyCount)
		; The workshop has insufficient defense to scare off raiders
		
		If (DisplayNotifications == True)
			If (BuildMode == False)
				If (ConstructableObject.GetValue(akAV = Food) > 0 || ConstructableObject.GetValue(akAV = Safety) > 0 || ConstructableObject.GetValue(akAV = Water) > 0)
					Debug.Notification(asNotificationText = "Required Defense = " + RequiredSafetyCount + "\nDefense Deficit = " + (RequiredSafetyCount-SafetyCount))
				EndIf
			EndIf
		EndIf
		
		If (WorkshopParent.Workshops[Index].AllowAttacks == False)
			WorkshopParent.Workshops[Index].AllowAttacks = True
			
			Return True
		EndIf
	EndIf
EndFunction

Function ConditionalSettlementAttacks(Bool BuildMode, Bool Repaired, ObjectReference ConstructableObject)
	; ---------
	; Variables
	; ---------
	
	Bool StateChanged
	Bool DisplayNotifications
	
	Int Index
	
	; ----------
	; Operations
	; ----------
	
	Index = GetCurrentWorkshopIndex()
	
	DisplayNotifications = WCP_GLOB_DisplayNotifications.GetValue() As Bool
	
	If (WCP_QUST_Housekeeping.DefaultConditionalSettlementAttacksState[Index] == True)
		StateChanged = IsWorkshopSafe(BuildMode, DisplayNotifications, Repaired, Index, ConstructableObject)
	ElseIf (WCP_QUST_Housekeeping.DefaultConditionalSettlementAttacksState[Index] == False)
		If (WorkshopParent.Workshops[Index].AllowAttacks == True)
			WCP_QUST_Housekeeping.DefaultConditionalSettlementAttacksState[Index] = True
			
			StateChanged = IsWorkshopSafe(BuildMode, DisplayNotifications, Repaired, Index, ConstructableObject)
		EndIf
	EndIf
	
	If (DisplayNotifications == True)
		If (BuildMode == False)
			If (StateChanged == True)
				If (WorkshopParent.Workshops[Index].AllowAttacks == True)
					Debug.Notification(asNotificationText = "WCP: This settlement is now prone to attack")
				ElseIf (WorkshopParent.Workshops[Index].AllowAttacks == False)
					Debug.Notification(asNotificationText = "WCP: This settlement is no longer under attack")
				EndIf
			EndIf
		EndIf
	EndIf
EndFunction

Int Function GetCurrentWorkshopIndex()
	; ---------
	; Variables
	; ---------
	
	Int CenterIndex
	Int ContainerIndex
	Int PlayerIndex
	Int SandboxIndex
	Int SpawnIndex
	Int WorkbenchIndex
	
	; ----------
	; Operations
	; ----------
	
	PlayerIndex = WorkshopParent.WorkshopLocations.Find(akElement = PlayerRef.GetCurrentLocation(), aiStartIndex = 0)
	
	If (PlayerIndex >= 0)
		Return PlayerIndex
	EndIf
	
;	WorkbenchIndex = WorkshopParent.WorkshopLocations.Find(akElement = Self.GetReference().GetCurrentLocation(), aiStartIndex = 0)
;	
;	If (WorkbenchIndex >= 0)
;		Return WorkbenchIndex
;	EndIf
;	
;	SandboxIndex = WorkshopParent.WorkshopLocations.Find(akElement = Self.GetReference().GetLinkedRef(apKeyword = WorkshopLinkSandbox).GetCurrentLocation(), aiStartIndex = 0)
;	
;	If (SandboxIndex >= 0)
;		Return SandboxIndex
;	EndIf
;	
;	ContainerIndex = WorkshopParent.WorkshopLocations.Find(akElement = Self.GetReference().GetLinkedRef(apKeyword = WorkshopLinkContainer).GetCurrentLocation(), aiStartIndex = 0)
;	
;	If (ContainerIndex >= 0)
;		Return ContainerIndex
;	EndIf
;	
;	CenterIndex = WorkshopParent.WorkshopLocations.Find(akElement = Self.GetReference().GetLinkedRef(apKeyword = WorkshopLinkCenter).GetCurrentLocation(), aiStartIndex = 0)
;	
;	If (CenterIndex >= 0)
;		Return CenterIndex
;	EndIf
;	
;	SpawnIndex = WorkshopParent.WorkshopLocations.Find(akElement = Self.GetReference().GetLinkedRef(apKeyword = WorkshopLinkSpawn).GetCurrentLocation(), aiStartIndex = 0)
;	
;	If (SpawnIndex >= 0)
;		Return SpawnIndex
;	EndIf
;	
;	If (PlayerIndex < 0 && WorkbenchIndex < 0 && SandboxIndex < 0 && ContainerIndex < 0 && CenterIndex < 0 && SpawnIndex < 0)
;		WCP_QUST_Housekeeping.ErrorWarning(301)
;		
;		; Stop the script running
;	EndIf
EndFunction
[/code]

 

 

 

Edit: I just noticed that the Enabled state wasn't set to Auto, so that could explain those issues (I'll have a look at fixing it now). However, that doesn't explain why the OnActivate event wasn't giving me any feedback.

 

Edit 2: Or rather, I forgot to change the state of this script from Disabled to Enabled in the perk script when this feature is enabled.

 

Edit 3: Yeah... after remotely changing the state of the script in the spoiler to Enabled, the script appears to function as intended. I guess I'm an idiot. Still, you've helped me understand reference collection aliases, so this hasn't been a waste. Thanks for your help mate.

Edited by KernalsEgg
Link to comment
Share on other sites

I've been slowly working on these scripts over the last couple of months. I lost what I had originally been working on when I reformatted my computer (again, I'm an idiot), which I did after being out of country for over a month. What ended up happening was me trying to work myself back to where I was purely in Notepad++ (that is, just the scripts themselves), as I only recently attempted to compile the scripts in the CK and create the .esp itself. Given that I hadn't worked on the mod for over a month, though, it took a while to re-familiarise myself with my previous work. These sort of bugs that result from discontinuities in design choices are a result of this.

 

Luckily I had the source files that I have uploaded on the file page to work with. However, if you care to contrast what I've released on the mod page and what I uploaded to dropbox this morning, you'll see that I pretty much rebuilt the mod from scratch.

 

Again, thanks for the help mate :)

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...