Jump to content

Infirmary, sick people and beds


pepperman35

Recommended Posts

I have an infirmary set up in my mod which as five beds. When the player enters the cell I’d like to have between 1-4 npcs spawn in and randomly occupy the available beds, giving the appearance that NPCs are being treated. No player interaction with the “sick” NPCs is required.

 

First: Is the doable?

Second: Is anything like this implemented in the game that I could examine?

Third: is there a way to make the NPCs lie flat on their backs vice assuming a sleep position.

Lastly: Suggestions on implementation are welcomed and appreciated, assuming it is doable.

 

Conceptually I could envision:
1. Creating a pool of sick people (approximately 10 “sick” NPCs)
2. Randomly spawn between 1 – 4 NPCs from the pool of sick people, ensuring that no sick NPC is selected twice.
3. Randomly assign the sick NPCs to the available beds, ensuring that multiple NPCs aren’t assigned to the same bed

 

 

Link to comment
Share on other sites

#1, Yes I think it is doable

#2, Yes, sort of anyway. The kid in Vault 81, I think it's 81, the vault where you recruit Curie

#3, Yes, SnapIntoInteraction(akBed) i.e. SleepPartner02.SnapIntoInteraction(akBed). They are not flat on their back, just a sleeping position.

Link to comment
Share on other sites

I don't think the vanilla games uses SnapIntoInteraction on a bed anywhere. They make heavy use of it in vertibirds. I've included the entire script that I have attached to a custom bed in a companion mod that I'm about ready to release.

 

You can see it working at: https://youtu.be/rlnXoJ3nk58

Scriptname CompJennyBedScript extends ObjectReference

Armor Property SkinNaked Auto Const
Armor Property JennysSkinNaked Auto Const
Armor Property SkinNaked_AO Auto Const
Armor Property JennysSkinNaked_AO Auto Const
Bool Property bPlayerSleeping Auto
Bool Property bUndressCompleteSP1 Auto
Bool Property bUndressCompleteSP2 Auto
Bool Property bSP1NotRomantic Auto
Bool Property bSP2NotRomantic Auto
Bool Property bBedAssignedToSP1 Auto
Actor Property SleepPartner01 Auto
Actor Property SleepPartner02 Auto
Actor Property Jenny Auto

CompJennyStartupQScript Property CJStartUpScript Auto

Keyword Property CompJenny_SleepingWithPC Auto Const
Keyword Property playerCanStimpak Auto Const
Message Property CompJennyReplaceSleepCompMsg Auto Const
Message Property CompJennySleepCompNotRomantic Auto Const
Message Property CompJennyBedMessage_BothAlreadyAssigned Auto Const
ActorValue Property CA_IsRomantic Auto Const
GlobalVariable Property CompJennyF4SEVersion Auto Const
Int Property nTimerPC Auto Const
Int Property nSP1UndressComplete Auto Const
Int Property nSP2UndressComplete Auto Const
Int Property nTimerSP1 Auto Const
Int Property nTimerSP2 Auto Const
Int Property nTimerWorker Auto Const
ActorBase Property baSupplyLineWorker Auto Const
Actor[] RomanceableAry
Form[] WornSP1
Form[] WornSP2
int nTempCountArmorSP1 = 0
Int nTmpCountUEFiredSP1 = 0
int nTempCountArmorSP2 = 0
Int nTmpCountUEFiredSP2 = 0

Armor NudeSuitSP1 = None
Armor NudeSuitSP2 = None
int nTmpCurSlot = 0

Form Function FindActor(Actor akActor)
	ActorBase CurActor = (akActor.GetBaseObject() as ActorBase)

EndFunction


Event OnWorkshopObjectPlaced(ObjectReference akReference)
	;Debug.MessageBox("OnWorkshopObjectPlaced Fired")
	RegisterForPlayerSleep()
	FillRomanceableAry()
	;Alias_BedPC.Clear()
	;Alias_BedPC.ForceRefTo(Self)	
	StartTimer(2.0, nTimerWorker)
	Debug.Trace("[CompJenny Bed OnWorkshopObjectPlaced]You have " + RomanceableAry.Length + " romanceable companions.")	
EndEvent

Event OnWorkshopObjectDestroyed(ObjectReference akActionRef)
	UnregisterForPlayerSleep()
	UnregisterForRemoteEvent(SleepPartner01, "OnItemUnequipped")	;Player could enter workshop mode after sleep and before it's unregistered
	UnregisterForRemoteEvent(SleepPartner02, "OnItemUnequipped")	
	Debug.Trace("[CompJenny Bed Destroyed]" + akActionRef + " a reference destroyed and added back into workshop.")
EndEvent

Event OnActivate(ObjectReference akActionRef)
	If akActionRef == Game.GetPlayer()
		If RomanceableAry.Length == 0
			FillRomanceableAry()
			If RomanceableAry.Length == 0
				Return
			EndIf
		EndIf
		SetNotRomantic() ;Clears CA_IsRomantic on all but SleepPartner01 and 02
	EndIf

EndEvent

Event OnExitFurniture(ObjectReference akActionRef)
	int nResult = 0
	bool bNotRomantic = False
	if akActionRef == Game.GetPlayer()
		SetAllRomantic()	;Set CA_IsRomantic on all in the array
		Return
	EndIf
	
	If bPlayerSleeping
		If (akActionRef as Actor) == SleepPartner01
			SleepPartner01.RemoveKeyword(CompJenny_SleepingWithPC)
		ElseIf (akActionRef as Actor) == SleepPartner02
			SleepPartner02.RemoveKeyword(CompJenny_SleepingWithPC)
		EndIf
		Return
	EndIf
		FillRomanceableAry()
		If RomanceableAry.Length <= 0
			Debug.Trace("[CompJenny Bed OnExitFurniture]RomanceableAry is empty.")
		EndIf	
	  
	bNotRomantic = False
	Actor ThisActor = (akActionRef as Actor)
	;Keyword chk added to prevent messagebox when NPC hangs in bed too long.
	If ThisActor.HasKeyword(CompJenny_SleepingWithPC)
		ThisActor.RemoveKeyword(CompJenny_SleepingWithPC)
		Return
	EndIf

	If (ThisActor == SleepPartner01 || ThisActor == SleepPartner02)
		If ThisActor == SleepPartner01
			CJStartUpScript.ShowSP1AssignedMsg(SleepPartner01)
		Else
			CJStartUpScript.ShowSP2AssignedMsg(SleepPartner02)
		EndIf
		Return
	EndIf
	If !IsActorInRomanticArray(akActionRef)
		;This person is not romantic, do you want to assign them to this bed anyway? 0 = Yes, 1 = No
		if CompJennySleepCompNotRomantic.Show() == 1
			Return
		EndIf
		bNotRomantic = True
	EndIf
	If SleepPartner01 == None
		SleepPartner01 = ThisActor
		If !bNotRomantic
			SleepPartner01.SetValue(CA_IsRomantic, 1)
			Debug.Trace("[CompJenny Bed ExitFurniture] SleepPartner01 CA_IsRomantic = True")
		Else
			bSP1NotRomantic = True
			Debug.Trace("[CompJenny Bed ExitFurniture] SleepPartner01 CA_IsRomantic = False")
		EndIf
		bBedAssignedToSP1 = False
		;CJStartUpScript.SetSleepPartner1(SleepPartner01)
		If CJStartUpScript.AssingBedToSp1(SleepPartner01, Self)
			bBedAssignedToSP1 = True
		EndIf

	ElseIf SleepPartner02 == None
		SleepPartner02 = ThisActor
		
		If !bNotRomantic
			SleepPartner02.SetValue(CA_IsRomantic, 1)
			Debug.Trace("[CompJenny Bed ExitFurniture] SleepPartner02 CA_IsRomantic Set")
		Else
			bSP2NotRomantic = True
			Debug.Trace("[CompJenny Bed ExitFurniture] SleepPartner02 CA_IsRomantic = False")
		EndIf
		CJStartUpScript.SetSleepPartner2(SleepPartner02)
		If !bBedAssignedToSP1
			CJStartUpScript.SetBedSP2(Self)
		EndIf

	ElseIf SleepPartner01 != None && SleepPartner02 != None
		CompJennyBedMessage_BothAlreadyAssigned.Show()
		Return

	EndIf
	bPlayerSleeping = false
	int nIdx = 0
	Actor ACur = None
	if !RomanceableAry.Length
		Debug.Trace("[CompJenny Bed ExitFurniture] RomanceableAry is empty")
	Else
		Debug.Trace("[CompJenny Bed ExitFurniture] RomanceableAry.Length = " + RomanceableAry.Length as string)
	EndIf
	While nIdx < RomanceableAry.Length
		If RomanceableAry[nIdx] != SleepPartner01 && RomanceableAry[nIdx] != SleepPartner02
			ACur = RomanceableAry[nIdx]
			ACur.SetValue(CA_IsRomantic, 0)
		EndIf
		nIdx += 1
	EndWhile
	
EndEvent

Event OnPlayerSleepStart(float afSleepStartTime, float afDesiredSleepEndTime, ObjectReference akBed)
	if akBed == Self
		Debug.Trace("[CompJenny Bed OnPlayerSleepStart] OnPlayerSleepStart Fired")

		bPlayerSleeping = True
		bUndressCompleteSP1 = False
		bUndressCompleteSP2 = False		
	
		If SleepPartner01 != None
			nTempCountArmorSP1 = 0
			nTmpCountUEFiredSP1 = 0
			WornSP1 = New Form[0]
			SleepPartner01.AddKeyword(CompJenny_SleepingWithPC)
			RegisterForRemoteEvent(SleepPartner01, "OnItemUnequipped")
			If bSP1NotRomantic
				NudeSuitSP1 = SkinNaked_AO
			Else
				NudeSuitSP1 = SkinNaked
			EndIf
			If SleepPartner01 == Jenny
				if bSP1NotRomantic
					NudeSuitSP1 = JennysSkinNaked_AO
				Else
					NudeSuitSP1 = JennysSkinNaked
				EndIf
			EndIf
			SleepPartner01.EquipItem(NudeSuitSP1 as Form, True, False)
			Utility.Wait(0.01)
			SleepPartner01.Unequipitem(NudeSuitSP1 as Form, False, False)
;			Utility.Wait(0.01)
;			SleepPartner01.SnapIntoInteraction(akBed)
		Else
			Debug.Trace("[CompJenny Bed PCSleepStart] SleepPartner01 = None")
		EndIf
		If SleepPartner02 != None
			nTempCountArmorSP2 = 0
			nTmpCountUEFiredSP2 = 0
			WornSP2 = New Form[0]
			SleepPartner02.AddKeyword(CompJenny_SleepingWithPC)
			RegisterForRemoteEvent(SleepPartner02, "OnItemUnequipped")
			If bSP2NotRomantic
				NudeSuitSP2 = SkinNaked_AO
			Else
				NudeSuitSP2 = SkinNaked
			EndIf
			If SleepPartner02 == Jenny
				if bSP2NotRomantic
					NudeSuitSP2 = JennysSkinNaked_AO
				Else
					NudeSuitSP2 = JennysSkinNaked
				EndIf
			EndIf
			SleepPartner02.EquipItem(NudeSuitSP2 as Form, True, False)
			Utility.Wait(0.01)
			SleepPartner02.Unequipitem(NudeSuitSP2 as Form, False, False)
;			Utility.Wait(0.01)
;			SleepPartner02.SnapIntoInteraction(akBed)
		Else
			Debug.Trace("[CompJenny Bed PCSleepStart] SleepPartner02 = None")
		EndIf		
		
		
		
	EndIf
endEvent

Event Actor.OnItemUnequipped(Actor akSender, Form akBaseObject, ObjectReference akReference)
	If !(akBaseObject as Armor)
		Return
	EndIf
	IF akSender == SleepPartner01
		nTmpCountUEFiredSP1 += 1
	ElseIf akSender == SleepPartner02
		nTmpCountUEFiredSP2 += 1
	EndIf
	if bPlayerSleeping && akSender == SleepPartner01
		nTempCountArmorSP1 += 1
		If akReference != None
			Debug.Trace("[CompJenny Bed Unequip] Ref Item Added to WornSP1")
			WornSP1.Add(akReference)
		Else
			Debug.Trace("[CompJenny Bed Unequip] BaseObject Item Added to WornSP1")
			WornSP1.Add(akBaseObject)
		EndIf

		StartTimer(0.05, nSP1UndressComplete)
	ElseIf bPlayerSleeping && akSender == SleepPartner02
		nTempCountArmorSP2 += 1
		If akReference != None
			Debug.Trace("[CompJenny Bed Unequip] Ref Item Added to WornSP2")
			WornSP2.Add(akReference)
		Else
			Debug.Trace("[CompJenny Bed Unequip] BaseObject Item Added to WornSP2")
			WornSP2.Add(akBaseObject)
		EndIf
		StartTimer(0.05, nSP2UndressComplete)	
	EndIf
EndEvent

Event OnPlayerSleepStop(bool abInterrupted, ObjectReference akBed)
	if akBed == Self

;		UnregisterForPlayerSleep()
		If SleepPartner01 != None
			SleepPartner01.SnapIntoInteraction(akBed)
			Utility.Wait(0.01)
			if SleepPartner01.GetItemCount(NudeSuitSP1) > 0
				SleepPartner01.RemoveItem(NudeSuitSP1, 1)
			EndIf
			If WornSP1.Length > 0
				StartTimer(Utility.RandomInt(3, 6), nTimerSP1)
			EndIf
		Else
			Debug.Trace("[CompJenny Bed SleepStop] SleepPartner01 = None")
		EndIf
		If SleepPartner02 != None
			SleepPartner02.SnapIntoInteraction(akBed)
			Utility.Wait(0.01)
			if SleepPartner02.GetItemCount(NudeSuitSP2) > 0
				SleepPartner02.RemoveItem(NudeSuitSP2, 1)
			EndIf
			If WornSP2.Length > 0
				StartTimer(Utility.RandomInt(3, 6), nTimerSP2)
			EndIf
		Else
			Debug.Trace("[CompJenny Bed SleepStop] SleepPartner02 = None")
		EndIf		
	
		SetAllRomantic()
		RomanceableAry.Clear()
		StartTimer(5, nTimerPC)
	EndIf
endEvent

Event OnTimer(int aiTimerID)		
	If aiTimerID == nTimerPC
		bPlayerSleeping = False	
	ElseIf aiTimerID == nSP1UndressComplete
		UnregisterForRemoteEvent(SleepPartner01, "OnItemUnequipped")
		bUndressCompleteSP1 = True
	ElseIf aiTimerID == nSP2UndressComplete
		UnregisterForRemoteEvent(SleepPartner02, "OnItemUnequipped")
		bUndressCompleteSP2 = True
	ElseIf aiTimerID == nTimerSP1
		If SleepPartner01 != None && WornSP1.Length > 0
			Int nIdx = 0
		
			While nIdx < WornSP1.Length
				if WornSP1[nIdx] != NudeSuitSP1
					SleepPartner01.Equipitem(WornSP1[nIdx] as Form, False, True)
				EndIf
				Utility.Wait(0.10)
				nIdx += 1
			EndWhile
			Debug.Trace("[CompJenny Bed Wakeup] SP1 Armor Count = " + (nTempCountArmorSP1 as string) + ", OnUnequip fired count =  " + (nTmpCountUEFiredSP1 as string) + ", SP1 Array Length = " + (WornSP1.Length as string), 0)
			WornSP1.Clear()
		EndIf		
	ElseIf aiTimerID == nTimerSP2
		If SleepPartner02 != None && WornSP2.Length > 0
			Int nIdx = 0
		
			While nIdx < WornSP2.Length
				if WornSP2[nIdx] != NudeSuitSP2
					SleepPartner02.Equipitem(WornSP2[nIdx] as Form, False, True)
				EndIf
				Utility.Wait(0.10)
				nIdx += 1
			EndWhile
			Debug.Trace("[CompJenny Bed Wakeup] SP2 Armor Count = " + (nTempCountArmorSP2 as string) + ", OnUnequip fired count =  " + (nTmpCountUEFiredSP2 as string) + ", SP2 Array Length = " + (WornSP2.Length as string), 0)
			WornSP2.Clear()
		EndIf
	ElseIf aiTimerID == nTimerWorker
		If Self.GetActorOwner() == baSupplyLineWorker
			Self.SetActorOwner(NONE) ;Remove synth supply line worker as owner
		EndIf
	EndIf
EndEvent


Function SetThisNotRomantic(Actor akNotRomantic)
	If akNotRomantic == SleepPartner01
		SleepPartner01 = SleepPartner02
		SleepPartner02 = None
	ElseIf akNotRomantic == SleepPartner02
		SleepPartner02 = None
	EndIf
	int nIdx = 0
	While nIdx < RomanceableAry.Length
		If  RomanceableAry[nIdx] == akNotRomantic
			RomanceableAry[nIdx].SetValue(CA_IsRomantic, 0)
		EndIf
		nIdx += 1
	  EndWhile		

EndFunction

Function FillRomanceableAry()
	;Builds RomanceableAry and fills it will all companions that have CA_IsRomantic set
	if RomanceableAry.Length > 0
		SetAllRomantic()
		RomanceableAry.Clear()
	EndIf
	RomanceableAry = new Actor[0]
    ObjectReference[] CompAry = Game.GetPlayer().FindAllReferencesWithKeyword(playerCanStimpak, 5000.0)  
	int nIdx = 0
	Actor ACur = None
	While nIdx < CompAry.Length	;Get list of all Romantic companions
		ACur = (CompAry[nIdx] as Actor)
		If ACur.GetValue(CA_IsRomantic)	> 0	
			RomanceableAry.Add(ACur)
		EndIf
		nIdx += 1
	  EndWhile	

EndFunction

Function SetAllRomantic()
	;Restores CA_IsRomantic on all NPCs in RomanceableAry
	if RomanceableAry.Length
		int nIdx = 0
		While nIdx < RomanceableAry.Length
			RomanceableAry[nIdx].SetValue(CA_IsRomantic, 1)
			nIdx += 1
		EndWhile

	EndIf
EndFunction

Function SetNotRomantic()
	;Clears CA_IsRomantic on all but SleepPartner01 and 02
	int nIdx = 0
	Actor ACur = None
	if !RomanceableAry.Length
		Debug.MessageBox("RomanceableAry is empty")
	EndIf
	While nIdx < RomanceableAry.Length
		If RomanceableAry[nIdx] != SleepPartner01 && RomanceableAry[nIdx] != SleepPartner02
			ACur = RomanceableAry[nIdx]
			ACur.SetValue(CA_IsRomantic, 0)
		EndIf
		nIdx += 1
	EndWhile

EndFunction

bool Function IsActorInRomanticArray(ObjectReference akActorRef)	;If actor is in RomanceableAry, returns True, else returns False

	int nIdx = 0
	If !RomanceableAry.Length
		Return false
	EndIf
	While nIdx < RomanceableAry.Length
		if RomanceableAry[nIdx] == (akActorRef as Actor)
			Return true
		EndIf
		nIdx += 1	
	EndWhile
	Return false

EndFunction

 

Link to comment
Share on other sites

Okay for a quick test I used NPCBedHospitalNoPlayer as the bed, made an NPC, and assigned the NPC to the bed via a standard sit package. No scripting at this point. The NPC lays in the bed sideways. Anyone ever seen such wierdness and know how to fix it?

 

40023-1606571366-1992131176.png

Edited by pepperman35
Link to comment
Share on other sites

I haven't looked at how they force old Shawn into that bed but it's not designed for animated entry. Before doing the following I suggest making a copy of the bed and using it, I don' t like to make changes to vanilla assets if I can help it.

 

Open your copy of the bed in the CK, Find Active Markers section (mid left). Select Interact Point 0 then under Markers Position/Orientation set Rot to 90. This should get the npc laying in the proper direction. If the npc sinks to deep into the bed you can adjust the Z position. You can adj. the pos. from head to foot of bed via the Y pos. Of course side to side is adjusted with X pos.

Link to comment
Share on other sites

  • Recently Browsing   0 members

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