the Sim Settlements forums!

Register a free account today to become a member! Once signed in, you'll be able to participate on this site by adding your own topics and posts, as well as connect with other members through your own private inbox!

Tutorial Multiple Activations / Activation Wheel

Whisper

Well-Known Member
Patreon Supporter
Community Rockstar
Verified Builder
Vault Librarian
Messages
1,320
Basics of the topic, more fleshing out to be done later (particularly with shots from the Creation Kit).

Prior, it has been noted that there can be no more than three activation options on an object. These being:

1/ the default activation on the object (Search for workshops, Craft for workbenches, Talk for settlers, etc)

2/ up to two (2) more activation options are possible

2a/ a hard-coded second option, Transfer for Workshops and Workbenches (defaults)

2b/ the Track option on beds/plants/settlers of Workshop Plus, Whats Your Name from WYN, etc

2c/ the combination of two mods, each adding a single option - so that Tracking and Whats Your Name can both have activations on a settler (the order they appear is determined by load-order and when the perks are given to the player)

3/ adding a 4th activation option causes all to disappear

3a/ the Armor Workbench has 2 options normally, you can add a third:
7AB46321-B2FB-418E-A8BA-41339B13CF6F.png

3b/ adding a fourth causes all to disappear (“Use” appears to be a game-engine default and the equivalent of “Craft”):
2E1B00D5-ED87-4DA1-999B-EEBEBB57F44F.png

4/ adding yet another activation - taking the total to five (5) - causes the game engine to bring up options in the dialogue wheel:
27D1949F-ED11-44FE-A8DF-64DDF0867D0C.png

4a/ a better illustration by numbering the options:
36B25C13-8ECA-4C28-86E5-542E3F5AE042.png

4b/ adding yet more numbered activations demonstrates how they are overridden:
EF43E3F4-C73B-4C32-B5D9-4AD8EDEF493A.png

4c/ this implies that the Use option will always stay at the bottom of the wheel, everything else starts at the top and cycles clockwise, overriding each other in order.

4d/ note that the hard-coded game option “Transfer” has disappeared. If you want that, you’ll have to emulate that with an activation of your own - or have some means of disabling several activations so that the game defaults return.

More testing needed.
 
Last edited:
Multiple Activations / Activation Wheel - while in Workshop mode.

While in Workshop mode all of the normal activation options disappear. This means that you cannot talk to/trade with settlers, ask them their name, etc. Instead other options appear: to assign them to work objects, supply lines, move over there, pick up/scrap/store items, etc.

The regular activation options can be brought back while in Workshop mode by adding more activations to the object (do this upon entering Workshop mode, remove upon exiting Workshop mode). Again these appear in the Activation Wheel. When they appear the default workshop activations seem to remain, though appear to be unusable (TEST MORE) - the wheel also shows:
4CB479C9-9E42-4856-A644-3F6AA835538A.jpeg
Note for PC users: when the Activation Wheel is shown the mouse becomes “sticky” and turning is difficult. This is because the Activation Wheel overrides the turning/direction options in Workshop mode in favor of selecting the Activation options. This issue does not occur on XBox.

TODO: Investigate disabling the mouse for selecting dialogue options on the PC.

TODO: Investigate the interaction of the Activation Wheel with custom dialogue interfaces like Full Dialogue Interface and Extended Dialogue Interface. (With XDI might there be several items - a scrollable list - of activations possible?)

When the Activation Wheel is visible some Workshop mode actions are not possible. For instance, you cannot pick up this plant or bed to move/scrap/store them:
1DEB40B1-0D26-434F-AFEF-5C2C74D3831D.png
4D236505-9A04-47AF-BDEF-D9A2CB8EA490.jpeg
The solution is to include Hide/Disable option/s in the wheel, so that the object can be dealt with normally. If the Activation Wheel is temporarily hidden, when the object is picked up in build-mode the Activation Wheel does not return until the object is placed down once more.

Because the Activation Wheel includes the default option, you can do things in Workshop mode that you couldn’t normally. Like trading with a settler:
98AD8EF6-0892-4828-A31E-FFA13DBF8AE0.jpeg
Or even harvesting crops:
80BF750A-C886-43A1-BDEE-5ACDAE00BFC4.png
7229B5D8-308A-414B-8088-7EA0C69D5B31.png
(Note that once harvested the option is blank, though the Activation Wheel is still there.)
 
Cycling Activation Wheel - non-workshop mode.

High-level pseudocode/general concept. (TODO: Concept mod with cycling options. Pictures from the CK showing how things are set up.)

Parameters:
* the object already has a single default activation
* it requires 4 extra activation options to show the Wheel
* option #2 is not shown (only 1, 3-5, optionally others)
* 8 options are desired (in addition to the Default and Cycle options)

Layout of options:
Code:
         Cycle
           ^
Option B < + > Option A
           v
     Default Option
* Global value to switch alt-activations off/on (Cycle_On, default 0.0)
* Holotape to toggle the above
* Global value to determine which pair of options are currently available (Cycle_Active, default 0.0)

Perk Activation options:
* Invisible
* Cycle
* Option 0A
* Option 0B
* Option 1A
* Option 1B
* Option 2A
* Option 2B
* Option 3A
* Option 3B

Condition functions:
* Global Cycle_On == 1.0 (all the above)
* Global Cycle_Active:
** Option 0A & B - Cycle_Active == 0.0
** Option 1A & B - Cycle_Active == 1.0
** Option 2A & B - Cycle_Active == 2.0
** Option 3A & B - Cycle_Active == 3.0

Code (each time the Cycle option is selected):
Code:
Cycle_Active.SetValue(Cycle_Active.GetValue() + 1.0)
If Cycle_Active.GetValue() > 3.0
  Cycle_Active.SetValue(0.0)
EndIf
Notes:
* If an odd number of activators is desired then the “Option A” or “Option B” for one of the cycles should be blank. Possibly set it to “Disable”, setting Cycle_On to 0.0 and leaving the entire set of cycling options disabled until re-enabled.
* A perk can have multiple Activation entry points.
* A perk for a cycle-group can have a full set of activations for multiple objects. Best to keep them exclusively for a single item (easier to comprehend/maintain).
 
Last edited:
Cycling Activation Wheel - Workshop mode.

This is done in much the same way as the non-Workshop mode, with some differences:

1/ since you only need 4 activation options for the Activation Wheel to appear in Workshop mode, the Invisible option above is not required

2/ due to the “stickiness” of the mouse and the requirement to use Workshop mode options (move, store, scrap, assign to work objects/supply lines) you need a “Hide (10 secs)” option

3/ for situations where you need to do several things and 10 seconds time is too short, you need a “Disable” option

4/ the perk/s should be added to the player upon entering Workshop mode and removed upon exiting Workshop mode

Setting up a Hide option:
Code:
; disable the cycling
Cycle_On.SetValue(0.0)

; use a different timer number for different perks
settimer(10, 5)
Deal with the timer:
Code:
Event OnTimer(int aiTimerID)
  ; make certain it is the correct timer
  If aiTimerID == 5
    ; turn the cycle back on
    Cycle_On.SetValue(1.0)
  EndIf
EndEvent
If you want to permanently disable the cycle, set Cycle_On to 0.0 - the player can toggle it back on in the holotape.
Code:
; disable until re-enabled via holotape
Cycle_On.SetValue(0.0)
If you want the cycle re-enabled upon going into Workshop mode again, set the Cycle_Active to 2000.0 and re-set it to 0.0 when going into workshop mode once more.
Code:
; disable until re-enter workshop mode
Cycle_Active.SetValue(2000.0)
(The number chosen is deliberately ridiculously high in case the modder keeps adding cycle functions and forgets to up the number upon reaching it.)
 
Last edited:
Cycling Activation Wheel with Custom Activator.

With a custom activator object you can use the default option for the cycling effect: “E) Cycle”. This might change to the engine default “E) Use” when in the Activation Wheel state.

If no Hide option is required, then the Activator can have three options per cycle. Alternatively the Hide/Disable options can be available somewhere in the options cycle.

The previously-described 5+ activations for non-workshop mode and 4+ activations for workshop mode apply.
 
Interesting.

1) In that first set of observations you gave, I realized the easiest workaround for the transfer command is to have it repeat as every third command, and thus, it will change positions but never move off the wheel (if redundant commands are possible).
2) Does the wheel always pop-up (vanilla game engine), or is that something created by Workshop Framework?
3) You speak of a timer, and my mind went in that direction as well. Were you thinking in terms of hovering over an object (trader, resource, etc.) and then another set of choices would be given? (Trade/Harvest/whatever)
4) Does this work in the same way as dialogue trees? Would it be possible to just have the four choices, that lead to other choices, or would that become too cumbersome? Because you would really only have three choices again, and a 'back' option.

I was a big user of mods that dynamically add settlements, like C.A.M.P. & Conquest, until I realize what that does to the Workshop Parent most of the time. Heck, More than half the settlement mods on the Nexus do that (and I spend a lot time tinkering with them to fix them properly). But the one good thing that comes out of that experience is you learn a LOT of work-arounds for stuff, and you also get a good feel of how the Workshop system actually works under-the-hood. That being said, Conquest had this weird scripting thing where it took a while to connect to the 'network' of workshops, so even when you had Provisioners set up, there was a delay of a few minutes before it would kick you out of WS mode and then put you right back in, but this time connected to larger network of linked WS's, rather than just the local one. I bring this up because sometimes I would do something real quick, leave that settlement, be fairly far-away from the settlement... and that script would kick-in and pop me into WS mode, in the middle of nowhere, and I would still be able to interact with NPCs, etc. Heck, it happened SO many times while I was using a crafting bench, which made it hard to read the text. So YEAH, timers work, even unintentionally because of lag, and you can wind up with two totally separate sets of interaction boxes on your screen. Also, the normal kick-out would come into play, and I'd only have a few seconds like that, unless I was in a settlement (either the original, at a WB, or even if I ran to another close one). Things get weird at that point.
 
I have a proof-of-concept, will get into working on it soon(tm). Mostly because I need to fix something in an XBox mod of mine that’s been broken since May(!) and I’ve been head-deep in other stuff instead.

It could be set up like a dialogue tree, it depends. I have a list of things that I’d like to try for xBox users - just need the time to test and see how it works.
 
Man, was my commenting here earlier serendipitous...
Okay, so I have another 'must have' mod that is now bumping-heads with Workshop Framework. It too adds a third option to the Workshop & Workbenches. Here's my thought: Can I crack-open that other mod, make a copy of that command-pop-up (essentially duplicating the command the mod already adds), and your discovery here will kick-in, and I will have BOTH commands from both mods available? ('New' option I added was just a dummy to force the wheel to appear)
 
It should be possible to make a "dummy" custom mod that you can include in the mix. What mod is it and what does it do?
 
After some testing, the activations in workshop mode are not as easily worked out as I'd hoped. Here's a sample of what can/cannot be done:
1615208511082.png
A sample mod that I'm working on:
1615208574246.png
A large number of activations in a single perk - note the priority (second column):
1615208620452.png
1615208948715.png
For the above and below (the chair is a .nif that I chose for testing the activator):
  • RRight and RLeft are set to be the first and second perk entry options (right/left arrows) when WSA_Cycle in [1..2]
  • Axis-Z/X/Y is the third perk entry option (top arrow) when WSA_Cycle = 1 and when WSA_AxisView in [1..3]
  • Rot 0.1/1/10/45 is the third perk entry option (top arrow) when WSA_Cycle = 2
  • Disable/Hide are the first and third perk entry options (right/left arrows) when WSA_Cycle = 3
  • (blank) is the third perk entry option (top arrow) when WSA_Cycle = 3 (and has the same functionality as the Cycle option on the activator)
1615209319789.png
1615209384552.png
1615209406693.png
Sample perk entry:
1615208748880.png
And sample papyrus to rotate right (aka clockwise - axis dependent):
Code:
if WSA_AxisView.GetValue() == 1.0
  akTargetRef.SetAngle(akTargetRef.GetAngleX(), akTargetRef.GetAngleY(), akTargetRef.GetAngleZ() + WSA_AxisRotation.GetValue())
endif
if WSA_AxisView.GetValue() == 2.0
  akTargetRef.SetAngle(akTargetRef.GetAngleX() + WSA_AxisRotation.GetValue(), akTargetRef.GetAngleY(), akTargetRef.GetAngleZ())
endif
if WSA_AxisView.GetValue() == 3.0
  akTargetRef.SetAngle(akTargetRef.GetAngleX(), akTargetRef.GetAngleY() + WSA_AxisRotation.GetValue(), akTargetRef.GetAngleZ())
endif
Debug.Notification("Rotate Right")
 
Last edited:
Note: The following is taken from a fully-working mod which is available on BethNet:

XBox Version: https://bethesda.net/en/mods/fallout4/mod-detail/4229446

PC Version: https://bethesda.net/en/mods/fallout4/mod-detail/4229447

Note: The PC version is only supplied on BethNet for the few people who want to download and check the source-code (it's in the ba2 archive). There's no real need for a PC version, PC's have Place Everywhere - which is much easier to use.

More details:

I have found the secret of making any object activateable while in Workshop Mode. It requires the WorkshopWorkObject keyword placed on the item. Here it is placed upon a custom activator which is used in Whisper's Workshop Utilities:

1629755583026.png
The good thing is that this keyword can be added/removed on-the-fly via papyrus, in four workshop events (these must be registered for upon entering workshop mode, and unregistered for upon exiting workshop mode):

Code:
; check for destroyed objects
Event ObjectReference.OnWorkshopObjectDestroyed(ObjectReference akWorkshopRef, ObjectReference akReference)
  ; check if this is the activator
  if akReference == PlacedActivator
    ; set to none
    PlacedActivator = None
   
    ; remove the keywords
    RKeywords()
   
    ; remove the last grabbed also
    LastGrabbed = None
  endif
 
  ; check if this is the last grabbed item
  if LastGrabbed == akReference
    ; set to none
    LastGrabbed = None
  endif
EndEvent

; check for grabbed objects
Event ObjectReference.OnWorkshopObjectGrabbed(ObjectReference akWorkshopRef, ObjectReference akReference)
  ; if the object grabbed is the activator and things are disabled
  if akReference == PlacedActivator && WSA_ObjectDisable.GetValue() != 1.0
    ; enable activations once more
    WSA_ObjectDisable.SetValue(1.0)
  endif
 
  ; if activating and this is not the activator and is not an actor
  if WSA_ObjectDisable.GetValue() == 1.0 && akReference != PlacedActivator && ! (akReference is Actor)
    ; remove the keyword(s) from the prior item
    RKeywords()
   
    ; grab this item
    LastGrabbed = akReference
   
    ; add keyword(s) to this new item
    AKeywords()
  endif
 
  ; if we don't have an activator
  if PlacedActivator == None
    ; place the activator
    PlaceActivator()
  endif
EndEvent

; check for moved objects
Event ObjectReference.OnWorkshopObjectMoved(ObjectReference akWorkshopRef, ObjectReference akReference)
  ; if this is not the activator and is not an actor
  if akReference != PlacedActivator && ! (akReference is Actor)
    ; grab this item
    LastGrabbed = akReference
  endif
 
  ; if we don't have an activator
  if PlacedActivator == None
    ; place the activator
    PlaceActivator()
  endif
EndEvent

; check for created objects
Event ObjectReference.OnWorkshopObjectPlaced(ObjectReference akWorkshopRef, ObjectReference akReference)
  ; if activating and this is not an actor
  if WSA_ObjectDisable.GetValue() == 1.0 && ! (akReference is Actor)
    ; remove the keyword(s) from the prior item
    RKeywords()
   
    ; grab this item
    LastGrabbed = akReference
   
    ; add keyword(s) to this new item
    AKeywords()
  endif
 
  ; if we don't have an activator
  if PlacedActivator == None
    ; place the activator
    PlaceActivator()
  endif
EndEvent

Here are the two functions which remove and add the keywords in the above:

Code:
; add keywords
Function AKeywords()
  ; if the base object doesn't have the keyword
  if ! LastGrabbed.GetBaseObject().HasKeyword(WSA_KYWD_ActivatorTest)
    ; set activator keyword on the object
    LastGrabbed.AddKeyword(WSA_KYWD_ActivatorTest)
  endif
 
  ; if the base object doesn't have the workshopworkobject keyword
  if ! LastGrabbed.GetBaseObject().HasKeyword(WorkshopWorkObject)
    ; wait for 1 second
    Utility.Wait(1.0)
   
    ; add the keyword
    LastGrabbed.AddKeyword(WorkshopWorkObject)
  endif
EndFunction

; remove keywords
Function RKeywords()
  ; if the base object doesn't have the keyword
  if ! LastGrabbed.GetBaseObject().HasKeyword(WSA_KYWD_ActivatorTest)
    ; remove keyword from last grabbed item
    LastGrabbed.RemoveKeyword(WSA_KYWD_ActivatorTest)
  endif
 
  ; if the base object doesn't have the workshopworkobject keyword
  if ! LastGrabbed.GetBaseObject().HasKeyword(WorkshopWorkObject)
    ; remove the keyword
    LastGrabbed.RemoveKeyword(WorkshopWorkObject)
  endif
EndFunction

The above snippets of papyrus code allow static items like walls and rooves, junk items, etc to be manipulated directly in workshop mode. Note that the activator has some extra functionality, directly interfacing with the item is provided for really fine-grained control.

There is a peculiarity, the item appears as if an NPC can be assigned to it:

1629757355990.png

Hint: Don't Do This!

This is an interface artifact of having the WorkshopWorkObject keyword added to the item on the fly - it only applies when the item has the keyword added to it. Once a different item is created/grabbed & released/etc then that keyword is removed from the originally-focused item (via the RKeywords() function) and added to the newly-focused item (via the AKeywords() function).

Note that upon leaving workshop mode the keywords are also removed from the currently-focused item.
 
Last edited:
; check for destroyed objects Event ObjectReference.OnWorkshopObjectDestroyed(ObjectReference akWorkshopRef, ObjectReference akReference) ; check if this is the activator if akReference == PlacedActivator ; set to none PlacedActivator = None ; remove the keywords RKeywords() ; remove the last grabbed also LastGrabbed = None endif ; check if this is the last grabbed item if LastGrabbed == akReference ; set to none LastGrabbed = None endif EndEvent
My OCD dictates that I ask if this Function should be written as:
Code:
; check for destroyed objects
Event ObjectReference.OnWorkshopObjectDestroyed(ObjectReference akWorkshopRef, ObjectReference akReference)
  ; check if this is the activator
  if ( akReference == PlacedActivator )
    ; set to none
    PlacedActivator = None
  
    ; remove the keywords
    RKeywords()
  
    ; remove the last grabbed also
    LastGrabbed = None

  ; check if this is the last grabbed item
  elseif ( akReference == LastGrabbed )
    ; set to none
    LastGrabbed = None
  endif
EndEvent
Otherwise, this has been pretty cool to follow. :)
 
My OCD dictates that I ask if this Function should be written as:
Code:
; check for destroyed objects
Event ObjectReference.OnWorkshopObjectDestroyed(ObjectReference akWorkshopRef, ObjectReference akReference)
  ; check if this is the activator
  if ( akReference == PlacedActivator )
    ; set to none
    PlacedActivator = None
 
    ; remove the keywords
    RKeywords()
 
    ; remove the last grabbed also
    LastGrabbed = None

  ; check if this is the last grabbed item
  elseif ( akReference == LastGrabbed )
    ; set to none
    LastGrabbed = None
  endif
EndEvent
Otherwise, this has been pretty cool to follow. :)
I know what you mean, and I can assure you that an if-else is not appropriate here. :) Here's why -

Scenario - we need to capture three types of destruction:

1/ Destroying the PlacedActivator globe
2/ Destroying the LastGrabbed object (the one which currently has "focus")
3/ Destroying some other non-grabbed object (ie a wall on the other side of the settlement)

If you follow the steps through both sets of code, you'll see why they are two separate if statements in my code up there. :)
 
I know what you mean, and I can assure you that an if-else is not appropriate here. :) Here's why -

Scenario - we need to capture three types of destruction:

1/ Destroying the PlacedActivator globe
2/ Destroying the LastGrabbed object (the one which currently has "focus")
3/ Destroying some other non-grabbed object (ie a wall on the other side of the settlement)

If you follow the steps through both sets of code, you'll see why they are two separate if statements in my code up there. :)
I think they are meaning the () around the statements
 
1/ Destroying the PlacedActivator globe
2/ Destroying the LastGrabbed object (the one which currently has "focus")
3/ Destroying some other non-grabbed object (ie a wall on the other side of the settlement)
I must be suffering reading comprehension fail... facepalm :scratchhead

for 1)
Code:
...
if ( akReference == PlacedActivator )
    ; set to none
    PlacedActivator = None
...
    ; remove the last grabbed also
    LastGrabbed = None
...
if akReference is both the PlacedActivator and LastGrabbed, you already set LastGrabbed to none so, to me, it doesn't need to be checked again. This is my question. Blame it on E for getting code optimization stuck in my head. ;)

for 2)
it is not the PlacedActivator, so the if statement fails then it evaluates the elseif statement.

for 3)
it should be ignored as it is not the PlacedActivator or LastGrabbed.
I think they are meaning the () around the statements
The brackets are just my personal preference and irrelevant to my question.
 
I must be suffering reading comprehension fail... facepalm :scratchhead

for 1)
Code:
...
if ( akReference == PlacedActivator )
    ; set to none
    PlacedActivator = None
...
    ; remove the last grabbed also
    LastGrabbed = None
...
if akReference is both the PlacedActivator and LastGrabbed, you already set LastGrabbed to none so, to me, it doesn't need to be checked again. This is my question. Blame it on E for getting code optimization stuck in my head. ;)

for 2)
it is not the PlacedActivator, so the if statement fails then it evaluates the elseif statement.

for 3)
it should be ignored as it is not the PlacedActivator or LastGrabbed.

The brackets are just my personal preference and irrelevant to my question.
I'll step through the three scenarios - maybe I wrote it wrong lol:

1/ If it's the PlacedActivator, then:
a/ remove the activator
b/ remove the keywords on the LastGrabbed item
c/ null the LastGrabbed item
d/ continue, nothing else applies...

2/ If it's the LastGrabbed item, then:
a/ not the PlacedActivator so does not apply
b/ null the LastGrabbed item (leaving the activator, and deleting the item removes the keywords it had anyway)
c/ continue, nothing else applies...

3/ If it's some other item that's destroyed, then:
a/ not the PlacedActivator so does not apply
b/ not the LastGrabbed item so does not apply
c/ continue, nothing else applies...

Where if we use an if-else, then:

i/ If it's the PlacedActivator, do (1) above
ii/ Else do (2) above - whether LastGrabbed item or some other item entirely

**/ This leaving the original LastGrabbed item with keywords and etc, a coding mess

Make sense?
 
I now see my fail! For some reason I had it stuck in my head that PlacedActivator would always be LastGrabbed... DOH! More coffee. LastGrabbed is the ref PlacedActivator is manipulating. (the whole purpose of this code...) Using elseif would definitely cause a lot of bug reports... and possibly butthurt.

I do find reading other's code to be quite educational. Like now, I learned to step back a little to look at the bigger picture. One year ago I never would have thought I would have a code discussion for a Fallout mod with Whisper! ;)

On another note, should I remove my posts as I'm cluttering this thread up?
 
I now see my fail! For some reason I had it stuck in my head that PlacedActivator would always be LastGrabbed... DOH! More coffee. LastGrabbed is the ref PlacedActivator is manipulating. (the whole purpose of this code...) Using elseif would definitely cause a lot of bug reports... and possibly butthurt.

I do find reading other's code to be quite educational. Like now, I learned to step back a little to look at the bigger picture. One year ago I never would have thought I would have a code discussion for a Fallout mod with Whisper! ;)

On another note, should I remove my posts as I'm cluttering this thread up?
Yup, many bugreports! I've found over the years that it's always best to mentally step through all the scenarios that the code will come into "contact with", as it were.

Code discussions are always good, no matter who it's with. :)

No, leave the posts here. :) It's all educational and all good!
 
Last edited:
Code discussion is very good. I have been playing with dlc05 conveyor scripts. The vanilla scripts are... interesting. If you want a good laugh, look at ObjectReference GetLinkedRefArray. I'm still scratching my head with the use of a loop instead of using the native Function GetLinkedRefChain... :scratchhead

Edit: And I'm NOT a coder......... shrug
 
Top