Jump to content

[FO4 CK] General Help Thread


Recommended Posts

Simplest thing then, is probably to add a package to that alias to eat whenever there's a suitable furniture nearby, and when it's been a while since the last snack. You might have to copy an existing package from the game and give it a higher priority to make sure yours runs and not the default one.

 

If you can do that, you can add script fragments for the start and end of the package, as well as when the package changes for something else. That'll probably give you all the control you need.

Link to comment
17 minutes ago, DocClox said:

Simplest thing then, is probably to add a package to that alias to eat whenever there's a suitable furniture nearby, and when it's been a while since the last snack.

It's a very good idea. And I will add to the package too, the condition (global) PiperIsHungry, and if not furniture near to sit n eat, in wild, then a forcegreet scene bothering player "I'm hungry, do you have something to eat? (The forcegreet scene is currently working, timers...) There is a mod that you can spawn camping gear, and it can spawn chairs, and so on, to play eat furnitures. https://www.nexusmods.com/fallout4/mods/32839

 

Thanks a lot

Link to comment

Does anyone know anything about the garbage collection in the Fo4 Engine?

 

What I want to do is something like this:

 

struct RRS_Props
        int breed_state
        int tattoo_state
        int config_state
        int designation
endstruct

RRS_Props function get_props(objectreference ref)
        RRS_Props prop = new RRS_PROPS
;
;       check the ref against several keyword lists to see which of them it has
;
        prop.breed_state = find_kw(ref, breed_state_keys)
        prop.tattoo_state = find_kw(ref, tattoo_state_keys)
;
;       return the struct with the indicies of found keywords
;
        return prop
endfunction

Thing is, the returned prop is going to get dropped on the floor. Will it get garbage collected? I didn't see any "delete" keyword to go with the "new" so I'm assuming it will...

Link to comment
3 hours ago, DocClox said:

Thing is, the returned prop is going to get dropped on the floor. Will it get garbage collected? I didn't see any "delete" keyword to go with the "new" so I'm assuming it will...

Structs and arrays get garbage collected when there are no more variables pointing to them.  I assume the calling function does something like foo=get_props(ref). When foo goes out of scope, the array allocated in the above function will get garbage collected.

 

Likewise, if you assign a new array or struct to a variable, the old one it was pointing to will be garbage collected (unless another variable also points to it)

RRS_Props foo1 = new RRS_Props
RRS_Props foo2 = foo1           ; at this point foo1 and foo2 point to the same memory

foo1 = new RRS_Props            ; now they point to different memory

foo2 = new RRS_Props            ; now they point to different memory and the first struct we allocated will be gc'd.

 

Link to comment

I have a quesion: Is it possible to make a formlist of strings? 

 

If so do you think it'd be possible to make a function that checks that list to see if an AAF animation from it exists? and then randomly select one of the ones that do?

Link to comment
4 minutes ago, Tentacus said:

I have a quesion: Is it possible to make a formlist of strings? 

 

If so do you think it'd be possible to make a function that checks that list to see if an AAF animation from it exists? and then randomly select one of the ones that do?

Not a formlist.  But you can make a script property that is an array of strings:

 

image.png

 

You can then loop through each one and use the GetPositionData() function to see if any of them are installed.

Link to comment
21 minutes ago, EgoBallistic said:

Not a formlist.  But you can make a script property that is an array of strings:

 

image.png

 

You can then loop through each one and use the GetPositionData() function to see if any of them are installed.

Thanks, duh I should have thought of that as I already use an array like that for tags.

Link to comment
  • 2 weeks later...

Can someone help me with a workshop problem?

 

I'm trying to make some signboards for the RRS (think big posters). I got a model made which I can place through the console, but if I try and make a constructible object, it crashes the game when I go to the workshop category.

 

This is what I'm shooting for:

 

image.png

 

I based the nif on the same vault saftey posters that Kiara did with the  Vault Breeding Posters, so they have attach points. As you see, I can place it, bit I can't move it in the workshop. I had to position that with modpos and modangle.

 

This is what the static looks like.

 

image.png

 

This is the constructible

 

image.png

 

And this is the nif, if it's any help.

 

image.png

 

I've compared it against working posters and I can't see anything I'm missing, apart from maybe a preview transform, but I'm fairly sure I've skipped them before and still had things work.

 

Any thoughts, anyone?

Link to comment

Fixed it. Problem seems to have been that I still had a skinning element in there from when I converted the obj file with outfit studio. I also converted the shapes to BSTriShapes and set bit 19 on the flags, since that was how it was on a working nif.

 

Link to comment

Does anyone know the trick to making glass walls?

 

I tried copying the ones from DDProductions, and the SOE ones, and all is well, but if I edit the texture - instant CTD. I'm using DXT5 for the DSS file, which is what Bethesda glass floors  in the Institute use (and also one of the SOE walls)

 

It's unlikely to be the materials file or the mesh, since the ones I'm using work fine elsewhere. So I figure it has to be the dds file. Or maybe the normalmap, which is the only other thing I've changed.

Link to comment
26 minutes ago, DocClox said:

Does anyone know the trick to making glass walls?

 

I tried copying the ones from DDProductions, and the SOE ones, and all is well, but if I edit the texture - instant CTD. I'm using DXT5 for the DSS file, which is what Bethesda glass floors  in the Institute use (and also one of the SOE walls)

 

It's unlikely to be the materials file or the mesh, since the ones I'm using work fine elsewhere. So I figure it has to be the dds file. Or maybe the normalmap, which is the only other thing I've changed.

I had this issue about a year ago trying to import a helicopter object. I was using gimp the time. I had to set the alpha channel to 127 rather then 128, then import it to  paint.net to export it to Nifskop as gimp was not exporting correctly for some reason. Not sure if this helps.

 

you are using the glass .BGEM file (NOT .BGSM)

Link to comment
16 minutes ago, mashup47 said:

I had this issue about a year ago trying to import a helicopter object. I was using gimp the time. I had to set the alpha channel to 127 rather then 128, then import it to  paint.net to export it to Nifskop as gimp was not exporting correctly for some reason. Not sure if this helps.

 

OK, that sounds plausible. I'll try that. Any reason not to load the .PNG into Paint.Net and export as DDS from there?

 

Quote

you are using the glass .BGEM file (NOT .BGSM)

 

I am. Like I say, copied from working versions :)

 

[edit]

 

NVM - Paint.Net worked just fine! Now I just need to fiddle with the alpha levels a little.

 

Thank you very much!

Link to comment
  • 2 weeks later...

Has anyone tried placing workshop lights with a script? I can place them just fine, but they don't power on. They will if I pick 'em up and put them down again, but I don't want that to be necessary.

 

[edit]

 

I think I sussed it.

 

I was placing the lights relative to an item just placed using the workshop. So in the placed item, I had code like this:


 

Event OnWorkshopObjectPlaced(ObjectReference ref)

;
;       first we place the layout. This is nif file with a tree of nodes
;       that specify position and orientation for the things we're going to attach
;
        objectreference layout = placeatme(rrs_frame_layout)
;
;       give it a second to cool down
;
        utility.wait(1.0)
;
;       attach dummy nodes to the nodes we want to use.
;       the dummy is a nif with a single root level node.
;       it doesn't seem to work when you attach objects directly to a node,
;       so the dummy is an in-between
;
        objectreference dummy_l = layout.placeatnode("light_left", rrs_frame_dummy)
        objectreference dummy_r = layout.placeatnode("light_right", rrs_frame_dummy)
        utility.wait(1.0)
;
;       now: the dummy has the position and orientation we want.
;       we place the light at the dummy, it will inherit those attributes
;
        if light_left
                light_left.enable()
        else
                light_left = PlaceAtMe(rrs_frame_light)
        endif
        light_left.moveto(dummy_l)

;
;       same for the right node
;
        if light_right
                light_right.enable()
        else
                light_right = PlaceAtMe(rrs_frame_light)
        endif
        light_right.moveto(dummy_r)
;
;       by default, both the layout and the dummies are marked "delete when able".
;       let's null out the object refs, just to encourage the process
;
        layout = None
        dummy_l = None
        dummy_r = None

The trick, I think was to link the new lights to the workshop

;
;       we inherit from workshopObjectScript - cast to that
;
        WorkshopObjectScript wos = ((self as objectreference) as WorkshopObjectScript)
;
;       wos has a reference to WorkshopParent. Between that and the workshopID we can get the specific workshop
;       that placed us
;
        WorkshopScript workshop = wos.WorkshopParent.GetWorkshop(wos.workshopID)
;
;       set linked refs from the lights back to the workshop
;
        light_right.SetLinkedRef(workshop, WorkshopItemKeyword)
        light_left.SetLinkedRef(workshop, WorkshopItemKeyword)
;
;       and tell the workshop that it has new items on the power grid
;
        wos.HandlePowerStateChange()

endevent

That seemed to work. I say "seemed" because I've not tested it much, and for unrelated reasons I think I'm going to abandon this approach in favor of making the fittings a static part of the furniture mesh, and placing the light source instead.

Link to comment

Has anyone tried the trick where you block activation and then call activate from the OnActivate event? I used it successfully in Skyrim, but it seems buggy in Fo4.

 

I have some furniture, and I want settlers to be able to use it normally, but to pop up a menu if the player uses so they can make some configuration choices. But when I have a settler use it (a JB slave in fact) she sits and then immediately gets up again.

 

So I block activation when the item is placed...

Event OnWorkshopObjectPlaced(ObjectReference ref)
; stuff...
        BlockActivation()
endevent

Then

 

Event Onactivate(ObjectReference akActionRef)
        debug.trace("rrs: activate")
        actor a = akActionRef as actor
        if a != game.getplayer()
                do_activate(akActionRef)
                return
        endif
        int choice = rrs_stand_menu_main.show()
        ; ... actions based on menu choice ...

The do_activate is a wrapper around activate()

 

function do_activate(ObjectReference ref)
        debug.trace("rrs: do_activate")
        gotostate("sitting")
        activate(ref, abDefaultProcessingOnly = true)
        lights_on()
        utility.wait(1)
        gotostate("")
endfunction

abDefaultProcessingOnly should stop onActivate from firing, but something was going wrong, so I added a state to ignore nested calls. 

 

;
; OnActivate shouldn't get called if abDefaultProcessingOnly is true
; but I'm not sure that's working. So we ignore activation while activating
;
state sitting
        Event Onactivate(ObjectReference akActionRef)
                debug.trace("rrs: sitting state activate")
        EndEvent
endstate

I don#t see the trace message at all, so I don't think it was needed, but it does eliminate one possible problem.

 

Any ideas? I'm a bit stuck here.

 

[edit]

 

Looks like I'm not the only one to run into this

Link to comment
  • 1 month later...
  • 2 weeks later...

I need a bit of help here. I'm working on a sort of integration script to make Advanced Needs 2's Menstrual Cycle expansion play nice with Family Planning Enhanced. It's an uphill battle because to be honest I don't really know what I'm doing haha, but I think I'm onto something with my script, not that I'm remotely close to testing or anything.

 

What I'm trying to achieve right now is a delayed notification system whereby the player finds out she's pregnant by being late for her period. So I want to at the moment of conception, check where the player is along the AN2 menstrual cycle, store that value as an integer, use that integer to evaluate when the player should next have a period, start a game timer with that value as the duration, and then start a process I have in the script to trigger three notifications representing the player realising they're late, wondering if they're pregnant and then confirming they are. I haven't even figured out if I can even access non-global variables from other scripts (like I said noob), but assuming I can it looks like AN2 has three main timers representing the stages of not menstruating, PMS and period, and there are variables for checking which of these stages is active, so I could presumably use those to check which one is running at the moment of conception.

 

But I can't figure out if there's any way to even get the current value of StartTimerGameTime, let alone get it from another script. Is this something that would be possible? Also I have included what I have so far if anyone has the time to look over it and yell at me for any rookie mistakes.

 

Spoiler

Scriptname ANTweaksMensesScript extends Quest

FPFP_Player_Script FPE
;Must make script child of FPE script


int DelayedPregnancyNotification1 = 10
int DelayedPregnancyNotification2 = 20
int DelayedPregnancyNotification3 = 30
Bool ShouldIbeMenstruating = False
Bool DoIKnowImPregnant = False
Bool FirstCheck = True

Bool Function LoadFPE()
	If Game.IsPluginInstalled("FP_FamilyPlanningEnhanced.esp")
		FPE = FPFP_Player_Script.GetAPI()
		Return True
	Else
		Return false
		Debug.Notification("Family Planning Enhanced Not installed! Reinstall and try again")
	EndIf
EndFunction

Bool Function LoadAN2()
	If Game.IsPluginInstalled("AdvancedNeeds2_Expansion_04_MestrualCycle.esp")
		Return True
	Else
		Return false
		Debug.Notification("Advanced Needs 2 Menstrual Cycle Not installed! Reinstall and try again")
	EndIf
EndFunction

Function RegisterForFPEEvents()
	RegisterForCustomEvent(FPE, "FPFP_GetPregnant")
	RegisterForCustomEvent(FPE, "FPFP_GiveBirth")
EndFunction

Function StartTimerGameTime(float afInterval, int aiTimerID = 10) native
EndFunction

Function GetPregnancyNotification()
	StartTimerGameTime(???, 10, ShouldIbeMenstruating)
	StartTimerGameTime(12, 20, DelayedPregnancyNotification1)
	StartTimerGameTime(12, 30, DelayedPregnancyNotification2)
	StartTimerGameTime(12, 40, DelayedPregnancyNotification3)
EndFunction

Function Initialize()
    If LoadFPE() && LoadAN2()
        RegisterForFPEEvents()
    EndIf
EndFunction


Event OnQuestInit()
    RegisterForRemoteEvent(Game.GetPlayer(), "OnPlayerLoadGame")
    Initialize()
EndEvent

Event Actor.OnPlayerLoadGame(Actor akSender)
    Initialize()
EndEvent

Event FPFP_Player_Script.FPFP_GetPregnant(FPFP_Player_Script akSender, Var[] akArgs)
	If ((akArgs[0] as Actor) == PlayerREF)
		DoIKnowImPregnant = False
		;Have to call the value of player's stage in her cycle and store it as an int
			If AN_PeriodStack == 1
					??????????????
			EndIf
			;
		StartTimerGameTime(;the value I call, 40)
		;  disable menstruation
		(AN_MensesScript).Function EndPeriod()
		AN_MenstrualCycle.SetValue(0)
		MensesScript.ResetModState()
		;Purely a debug message
		Debug.Notification("Debug: Menstrual Cycle Disabled")
		; Set a delayed notification timer
		StartTimerGameTime(12, 10)	
EndEvent

Event FPFP_Player_Script.FPFP_GiveBirth(FPFP_Player_Script akSender, Var[] akArgs)
	If (akSender.Ourself == PlayerREF)
		; enable menstruation
		AN_MenstrualCycle.SetValue(1)
		MensesScript.EnableCycle()
		DoIKnowImPregnant == False
EndEvent

Event OnTimerGameTime (bool ShouldIbeMenstruating);Should activate when the next period is due
	If (AN_PeriodStack == 1)
		Self.StartTimerGameTime(10)
	Else
	Self.StartTimerGameTime(20)
EndEvent

Event OnTimerGameTime(int DelayedPregnancyNotification1)
	Debug.Notification("My period's late...")
	Self.CancelTimerGameTime(20)
	StartTimerGameTime(30)	
EndEvent

Event OnTimerGameTime(int DelayedPregnancyNotification2)
	Debug.Notification("I still haven't got my period. Maybe I'm pregnant")
	Self.CancelTimerGameTime(30)
	Self.StartTimerGameTime(40)
EndEvent

Event OnTimerGameTime(int DelayedPregnancyNotification3)
	DoIKnowImPregnant = True; The player knows she's pregnant so the child code for the FPE script triggers notifications and the quest
EndEvent	

Event OnTimerGameTime(int aiTID)
	If MorningAfterPill ; the player has taken the pill during the first month
		GiveBirth(False)
		(AN_MensesScript)MensesScript.EnableCycle()
		(AN_MensesScript).Function GivePeriod()
		Debug.MessageBox("The contraceptive you took forced a period.")
		Return
	EndIf
	;float currentMonth = GetCurrentMonth()
	;If currentMonth > 0 && currentMonth < 9
		;UpdateBody(currentMonth)
		If FirstCheck
			If DoIKnowImPregnant == True
				debug.notification("There's no mistake about it: I'm pregnant!")
				StartFPEPlayerQuests()
				FirstCheck = False
			EndIf
		If DoIKnowImPregnant == True
			debug.notification("It's the "+ GetMonthString(currentMonth) +" month of my pregnancy.")
		EndIf
EndEvent

 

 

Link to comment
5 hours ago, RealBarenziah said:

But I can't figure out if there's any way to even get the current value of StartTimerGameTime, let alone get it from another script. Is this something that would be possible?

 

I don't think you can interrogate a timer directly to find out how long is remaining or expired (that would be a useful feature though!). If that's what you mean. But you could use the built in timestamp functionality to check current time versus timer start time. You'd have to do this manually.


Retrieving values from other scripts is quite straight forward. Papyrus has inbuilt mechanisms to enable this or you can concoct your own methods. To facilitate inter-script value passing I usually cast a reference that has a particular script attached as that script then either access its auto flagged properties directly or use a custom method of data retrieval.

Link to comment
1 hour ago, Carabosse said:

 

I don't think you can interrogate a timer directly to find out how long is remaining or expired (that would be a useful feature though!). If that's what you mean. But you could use the built in timestamp functionality to check current time versus timer start time. You'd have to do this manually.


Retrieving values from other scripts is quite straight forward. Papyrus has inbuilt mechanisms to enable this or you can concoct your own methods. To facilitate inter-script value passing I usually cast a reference that has a particular script attached as that script then either access its auto flagged properties directly or use a custom method of data retrieval.

OK thanks.  I think I've figured out an alternative method involving using a pseudo menstrual cycle that would have the benefit of allowing me to trigger the late notification when the next period actually is late, so that's fine that you can't. Good to know I can get values from other scripts though.

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

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

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. For more information, see our Privacy Policy & Terms of Use