Jump to content

MCGUFIN

  • entries
    8
  • comments
    0
  • views
    142

Fork Pregnancy


Monoman1

53 views

Pregnancy Fork is an interoperability adapter layer that presents a single unified surface for modders to use. 
Single surface interface to 2/3 backend pregnancy mods. Modders don't need to know anything about the underlying pregnancy mod a user has installed. 

 

Another great feature of this approach is that expanding the system to include another pregnancy mod simply involves authoring a new backend interface. Once that backend interface is in place then any mod accessing pregnancy functions via MGF is automatically compatible with the new pregnancy mod without any changes on their end!

 

Highlights:

  • Unified pregnancy events - _MGF_Preg_Conceived, _MGF_Preg_LaborStarted, _MGF_Preg_Birthed, _MGF_Preg_Aborted. 
  • Query functions - IsPregnant(), GetFathers(), GetFatherRaces(), GetPregnancyPercent(), GetTrimester(), GetCyclePhase(). 
  • 'Action' functions - Impregnate(), ForceLabor(), Abort(). 
  • Faction Data:
    • MGF_PregStatusFact. Rank -1/0 - Not pregnant. 1 -> First trimester. 2 -> Second trimester. 3 -> Third trimester. 
    • _MGF_PregActiveWithPcFact - This Npc is the Father of the player's current pregnancy. 
    • _MGF_PregConceivedWithPcFact - This Npc has conceived with a female player <FactionRank> times. 
    • _MGF_PregBirthedWithPcFact - This Npc has Fathered <FactionRank> babies with a female player. 

 

Mods: 
Fertility Mode v3 Fixes and Tweaks - Built, tested. 
Beeing Female NG - Built, requires testing currently. 
Fertility Mode Reloaded - In process. 
Fertility Mode (base) and Beeing Female (base) - Unsupported. 

_MGF_ForkPregnancy:

Spoiler
Scriptname _MGF_ForkPregnancy extends Quest  

; Fork script for when you don't give a damn which pregnancy mod is installed
; and just want to ask common, conceptual questions about an actor.

; Currently covers:
; 1 - Beeing Female NG
; 2 - Fertility Mode v3 Fixes and Tweaks
; 3 - Fertility Mode Reloaded (not compatible with base Fertility Mode alone,
;     or with the Fixes and Tweaks patch - pick one FM variant per game)

; Pregnancy mod you want not here? Write the interface script. Test it. Send it to me.

; NOTE: this Fork only carries the surface all three mods can answer. There will not always be overlap. 

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

; Unified conceptual-level events, fired regardless of which backend mod is active. 

;	RegisterForModEvent("_MGF_Preg_Conceived", "OnConceived")
;	Event OnConceived(Form Mother, Form Father, Int NumBabies)
;		Actor TheMother = Mother as Actor
;		Actor TheFather = Father as Actor ; may be None - not every pregnancy has one on record
;	EndEvent
;
;	_MGF_Preg_Conceived		- she just conceived				-> (Form Mother, Form Father, Int NumBabies)
;	_MGF_Preg_LaborStarted	- labor has begun					-> (Form Mother, Form Father, Int NumBabies)
;	_MGF_Preg_Birthed		- she has now given birth			-> (Form Mother, Form Father, Int NumBabies, Form Baby)
;	_MGF_Preg_Aborted		- pregnancy ended without a birth	-> (Form Mother, Form Father)

;	_MGF_Preg_TriCycle_Complete	- The trimester and menstrual cycle update has completed. 

; IMPORTANT: BF has the concept of multiple Fathers - One pregnancy, multiple babies, different Fathers. 
; The event only sends Fathers[0]. You'll need to call GetFathers(Mother) if you want all of them. 
; FM = Single Father. 

; Note: BF clears Father data on Abort/Birth so if you need them better get them on conception. 

; Baby, on Birthed.
; BF - Some form. Need to investigate what this form is. 
; FM - Nothing spawned until much later (baby grows up). Might be expandable. Also needs investigation. 

; =======================================================================================
; Queryable Data ========================================================================
; =======================================================================================

; Globals - _MGF_Globs ==================================================================
;	_MGF_PcPreg_CurrentBabyCount 	- The number of babies the player is currently pregnant with. 
;	_MGF_PcPreg_CyclePhase			- The player's current menstrual cycle phase. 

; Factions - _MGF_Factions ==============================================================
;	General:
;		_MGF_PregStatusFact	-	Any actor (including the player). Rank 1-3 (trimester) while pregnant, removed on birth/abort. 

;	Npcs impregnated by the player:
;		_MGF_PregConceivedByPcFact	; Rank = Number of times this actor has been conceived by the player, capped at 127. 
;		_MGF_PregBirthedByPcFact	; Rank = Number of times this actor has given birth by the player, capped at 127. 
;		_MGF_PregActiveByPcFact		; This Npc is currently pregnant by the player. 

;	Npcs that got the player pregnant:
;		_MGF_PregActiveWithPcFact ; Player is currently carrying a pregnancy by this actor. There can be multiple Fathers with BF. (multiple babies, different Fathers)
;		_MGF_PregConceivedWithPcFact ; Rank = Number of times this actor has conceived a pregnancy with the player, capped at 127. 
;		_MGF_PregBirthedWithPcFact ; Rank = Number of times this actor has fathered a birth with the player, capped at 127. 

; Aliases ===============================================================================
;	Impregnated player:
;		0 - Current father of the player's ongoing pregnancy. 
;		1 - Father of the player's most recently CONCLUDED pregnancy (birth or abort). 
;		2 - Father of the player's most recent actual BIRTH specifically. 

;	Impregnated by the player: 
;		3 - 5 - The three most recent NPCs the player has conceived with (index 3 = latest)
;		6 - 8 - The three most recent NPCs the player has fathered a birth with (index 6 = latest)

; Rolling 100 element conception/birthed logs for the player. [0] = Newest. (Array.Length - 1) = Oldest. 
;	Impregnated player: 
;		GetConceivedWithPcLog()
;		GetFatheredWithPcLog()

;	Player impregnated:
;		GetConceivedByPcLog()
;		GetFatheredByPcLog()

; =======================================================================================
; Plumbing ==============================================================================
; =======================================================================================

Import _MGF_ArrayCreate
Import _MGF_ArrayEdit
Import _MGF_ArrayQuery

Event OnInit()
	Mods = New String[3]
	Mods[0] = "BeeingFemaleNG.esp"
	Mods[1] = "Fertility Mode 3 Fixes and Updates.esp" ; gating on the Fixes and Tweaks patch specifically - base Fertility Mode alone is no longer supported
	Mods[2] = "Fertility Mode.esm" ; informational only (see GetActiveMod() under State Fmr) - FMR itself is NOT gated on this, see CornerstoneScript below
	
	SetCyclePhaseNames()
	
	DecideState()
	RegisterForModEvent("_MGF_LoadOrderChanged", "On_MGF_LoadOrderChanged")

	; For Status-board wiring
	RegisterForModEvent("_MGF_Preg_Conceived", "OnPregConceived")
	RegisterForModEvent("_MGF_Preg_Birthed", "OnPregBirthed")
	RegisterForModEvent("_MGF_Preg_Aborted", "OnPregAborted")

	ConceivedWithLog = ArrayActorCreate(0)
	BirthedWithLog = ArrayActorCreate(0)
	ConceivedWithMeLog = ArrayActorCreate(0)
	BirthedWithMeLog = ArrayActorCreate(0)
	CurrentlyPregnantByPc = ArrayActorCreate(0)
	AllCurrentlyPregnant = ArrayActorCreate(0)

	If GameTimeUpdatesAllowed()
		RegisterForSingleUpdateGameTime(PollIntervalHours)
	Else
		RegisterForModEvent("_MGF_MQ101_Stage240", "On_MGF_MQ101_Stage240")
	EndIf
EndEvent

Bool Function GameTimeUpdatesAllowed()
	Return (Game.GetFormFromFile(0x03372B, "Skyrim.esm") as Quest).GetStage() >= 240 ; MQ101
EndFunction

Event On_MGF_MQ101_Stage240(String EventName, String StrArg, Float NumArg, Form Sender)
	UnRegisterForModEvent("_MGF_MQ101_Stage240")
	RegisterForSingleUpdateGameTime(PollIntervalHours)
EndEvent

Function SetCyclePhaseNames()
	CyclePhaseNames = ArrayStringCreate(4, "Follicular")
	CyclePhaseNames[1] = "Ovulation"
	CyclePhaseNames[2] = "Luteal"
	CyclePhaseNames[3] = "Menstruation"
EndFunction

Function IncrementFactionRankCapped(Actor Target, Faction Fact) Global
	; Clamp faction rank increases to avoid wrap around. GetFactionRank returns
	; -1 for an actor who isn't a member of Fact at all (not "rank -1"), so the
	; first-ever occurrence needs to land on rank 1, not 0 - SetFactionRank(0)
	; would otherwise silently add them to the faction at 0, one event short.
	If Target && Fact
		Int Rank = Target.GetFactionRank(Fact)
		If Rank == -1
			Target.SetFactionRank(Fact, 1)
		ElseIf Rank < 127
			Target.SetFactionRank(Fact, Rank + 1)
		EndIf
	EndIf
EndFunction

Function DecideState()
	If Game.GetModByName(Mods[0]) != 255 ; Beeing Female NG
		GoToState("Bf")
	ElseIf Game.GetModByName(Mods[1]) != 255 ; Fertility Mode (Fixes and Tweaks)
		GoToState("Fm")
	ElseIf _MGF_File.FileExists(CornerstoneScript) ; Fertility Mode Reloaded - no distinct plugin of its own, see _MGF_InterfaceFmr for why this checks a script file instead
		GoToState("Fmr")
	Else
		GoToState("")
	EndIf
EndFunction

Event On_MGF_LoadOrderChanged(Bool OrderChanged, Bool ModsAdded, Bool ModsRemoved, Bool ModsModified)
	; Because FMR 'overwrites' FertilityMode.esm (and we don't support base FM) we can't 
	; gate on mod name here. Need to do a 'CornerstoneScript' check
	If ModsAdded || ModsRemoved
		DecideState()
	EndIf
EndEvent

; Status board - event handlers ==============================================

Event OnPregConceived(Form Mother, Form Father, Int NumBabies)
	Actor TheMother = Mother as Actor
	If !TheMother
		Return
	EndIf
	Actor TheFather = Father as Actor

	; Any actor, any father.
	TheMother.SetFactionRank(Factions._MGF_PregStatusFact, 1) ; conception is always trimester 1
	AllCurrentlyPregnant = ArrayActorAppend(AllCurrentlyPregnant, TheMother)

	; She's the player.
	If TheMother == PlayerRef
		Globs._MGF_PcPreg_CurrentBabyCount.SetValue(NumBabies as Float)
		SetAliasTarget(AliasCurrentFather, TheFather as Form)

		; BF's multi-father: BF records one entry per BABY. Deduplicate.
		CurrentFathersOfPc = ArrayActorUnique(GetFathers(PlayerRef))
		Int i = 0
		While i < CurrentFathersOfPc.Length
			Actor WithFather = CurrentFathersOfPc[i]
			IncrementFactionRankCapped(WithFather, Factions._MGF_PregConceivedWithPcFact)
			WithFather.SetFactionRank(Factions._MGF_PregActiveWithPcFact, 1)
			ConceivedWithMeLog = PushForwardActor(ConceivedWithMeLog, WithFather, DropOff = ConceivedWithMeLog.Length >= LogSize)
			i += 1
		EndWhile
	EndIf

	If (ArrayActorFind(GetFathers(TheMother), PlayerRef) > -1)
		; The player fathered this - checked against the full father list (BF's multi-father). 
		IncrementFactionRankCapped(TheMother, Factions._MGF_PregConceivedByPcFact)
		TheMother.SetFactionRank(Factions._MGF_PregActiveByPcFact, 1)
		CurrentlyPregnantByPc = ArrayActorAppend(CurrentlyPregnantByPc, TheMother)
		ConceivedWithLog = PushForwardActor(ConceivedWithLog, TheMother, DropOff = ConceivedWithLog.Length >= LogSize)
		RefreshConceivedAliases()
	EndIf
EndEvent

Event OnPregBirthed(Form Mother, Form Father, Int NumBabies, Form Baby)
	Actor TheMother = Mother as Actor
	If !TheMother
		Return
	EndIf
	Actor TheFather = Father as Actor

	; Any actor, any father.
	TheMother.RemoveFromFaction(Factions._MGF_PregStatusFact)
	AllCurrentlyPregnant = ArrayActorRemove(AllCurrentlyPregnant, TheMother)

	; She's the player.
	If TheMother == PlayerRef
		Globs._MGF_PcPreg_CurrentBabyCount.SetValue(0.0)
		; Read the CURRENT alias rather than trusting the event's own Father
		; parameter - keeps one source of truth for what "current father" meant
		; a moment ago, rather than two that could theoretically disagree.
		Actor ConcludedFather = (GetAlias(AliasCurrentFather) as ReferenceAlias).GetReference() as Actor
		SetAliasTarget(AliasPrevConcludedFather, ConcludedFather as Form)
		SetAliasTarget(AliasPrevBirthFather, ConcludedFather as Form)
		(GetAlias(AliasCurrentFather) as ReferenceAlias).Clear()

		; Consuming the cache from conception, not re-querying GetFathers() -
		; BF has already cleared its own father record for this pregnancy by
		; now, so that call would return nothing. See CurrentFathersOfPc's
		; declaration for why.
		Int i = 0
		While i < CurrentFathersOfPc.Length
			Actor WithFather = CurrentFathersOfPc[i]
			If WithFather
				IncrementFactionRankCapped(WithFather, Factions._MGF_PregBirthedWithPcFact)
				WithFather.RemoveFromFaction(Factions._MGF_PregActiveWithPcFact)
				BirthedWithMeLog = PushForwardActor(BirthedWithMeLog, WithFather, DropOff = BirthedWithMeLog.Length >= LogSize)
			EndIf
			i += 1
		EndWhile
		CurrentFathersOfPc = ArrayActorCreate(0)
	EndIf

	; The player fathered this - checked via faction membership, not
	; GetFathers(). By the time this fires, BF has already cleared its own
	; father record for a concluded pregnancy, so re-querying here would
	; silently return nothing. _MGF_PregActiveByPcFact was set at conception
	; and lives on the actor independently of BF's own storage, so it survives
	; that cleanup - read it BEFORE removing her from it.
	If TheMother.IsInFaction(Factions._MGF_PregActiveByPcFact)
		IncrementFactionRankCapped(TheMother, Factions._MGF_PregBirthedByPcFact)
		TheMother.RemoveFromFaction(Factions._MGF_PregActiveByPcFact)
		CurrentlyPregnantByPc = ArrayActorRemove(CurrentlyPregnantByPc, TheMother)
		BirthedWithLog = PushForwardActor(BirthedWithLog, TheMother, DropOff = BirthedWithLog.Length >= LogSize)
		RefreshBirthedAliases()
	EndIf
EndEvent

Event OnPregAborted(Form Mother, Form Father)
	Actor TheMother = Mother as Actor
	If !TheMother
		Return
	EndIf
	Actor TheFather = Father as Actor

	; Any actor, any father.
	TheMother.RemoveFromFaction(Factions._MGF_PregStatusFact)
	AllCurrentlyPregnant = ArrayActorRemove(AllCurrentlyPregnant, TheMother)

	; She's the player.
	If TheMother == PlayerRef
		Globs._MGF_PcPreg_CurrentBabyCount.SetValue(0.0)
		; Only the "concluded" slot moves - an abortion isn't a birth, so
		; AliasPrevBirthFather is deliberately left untouched here.
		Actor ConcludedFather = (GetAlias(AliasCurrentFather) as ReferenceAlias).GetReference() as Actor
		SetAliasTarget(AliasPrevConcludedFather, ConcludedFather as Form)
		(GetAlias(AliasCurrentFather) as ReferenceAlias).Clear()

		; Same cache consumption as OnPregBirthed, minus any counter increment -
		; an abortion isn't a birth, and conception already got its credit.
		Int WI = 0
		While WI < CurrentFathersOfPc.Length
			Actor WithFather = CurrentFathersOfPc[WI]
			If WithFather
				WithFather.RemoveFromFaction(Factions._MGF_PregActiveWithPcFact)
			EndIf
			WI += 1
		EndWhile
		CurrentFathersOfPc = ArrayActorCreate(0)
	EndIf

	; The player fathered this - same reorder as OnPregBirthed, see its
	; comment. No conceived/birthed counter change - she was already counted
	; at conception, and an abortion isn't a birth.
	If TheMother.IsInFaction(Factions._MGF_PregActiveByPcFact)
		TheMother.RemoveFromFaction(Factions._MGF_PregActiveByPcFact)
		CurrentlyPregnantByPc = ArrayActorRemove(CurrentlyPregnantByPc, TheMother)
	EndIf
EndEvent

Function SetAliasTarget(Int AliasIndex, Form Target)
	; ForceRefTo(None) is NOT how you clear an alias - Clear() is the actual
	; function for that, and calling ForceRefTo with a None target doesn't
	; reliably do the same thing. Centralized here because every write site
	; below can legitimately receive a None (no father on record, a log slot
	; that hasn't been filled yet, or a father who's since become
	; unresolvable), and every one of them needs the same branch.
	ReferenceAlias TargetAlias = GetAlias(AliasIndex) as ReferenceAlias
	If !TargetAlias
		Return
	EndIf
	If Target
		TargetAlias.ForceRefTo(Target as ObjectReference)
	Else
		TargetAlias.Clear()
	EndIf
EndFunction

Function RefreshConceivedAliases()
	; Index 0 is always the most recent - see PushForwardActor's semantics
	; (inserts at index 0, shifts the rest back). Length can be under 3 early
	; in a playthrough now that the log grows from empty rather than being
	; pre-filled - bounds-checked so this never indexes past what actually
	; exists yet.
	If ConceivedWithLog.Length > 0
		SetAliasTarget(AliasConceived0, ConceivedWithLog[0])
	EndIf
	If ConceivedWithLog.Length > 1
		SetAliasTarget(AliasConceived1, ConceivedWithLog[1])
	EndIf
	If ConceivedWithLog.Length > 2
		SetAliasTarget(AliasConceived2, ConceivedWithLog[2])
	EndIf
EndFunction

Function RefreshBirthedAliases()
	; Same bounds-checking as RefreshConceivedAliases, same reason.
	If BirthedWithLog.Length > 0
		SetAliasTarget(AliasBirthed0, BirthedWithLog[0])
	EndIf
	If BirthedWithLog.Length > 1
		SetAliasTarget(AliasBirthed1, BirthedWithLog[1])
	EndIf
	If BirthedWithLog.Length > 2
		SetAliasTarget(AliasBirthed2, BirthedWithLog[2])
	EndIf
EndFunction

; Status board ===============================================================

Event OnUpdateGameTime()
	RunPregPoll()
	RegisterForSingleUpdateGameTime(PollIntervalHours)
EndEvent

Function RunPregPoll()
	; Trimester/CyclePhase have no source event on any backend. 
	; Plain recurring poll - gives a single, simple accuracy guarantee. 
	; Trimester/Phase data can be 'stale' up to PollIntervalHours game hours. 
	
	PollPlayerCycleState()
	PollAllPregnantTrimesters()
	SendModEvent("_MGF_Preg_TriCycle_Complete", strArg = "", numArg = 0.0)
EndFunction

Function PollPlayerCycleState()
	Globs._MGF_PcPreg_CyclePhase.SetValue(GetCyclePhase(PlayerRef) as Float)
EndFunction

Function PollAllPregnantTrimesters()
	; Bounded by how many pregnancies are active right now, not by the size of
	; either backend's full tracked-actor history. 
	
	; Filter None/dead actors. 
	AllCurrentlyPregnant = ArrayActorSanitize(AllCurrentlyPregnant, FilterDisabled = false, FilterDead = true)
	Int i = 0
	While i < AllCurrentlyPregnant.Length
		Int CurrentTrimester = GetTrimester(AllCurrentlyPregnant[i])
		If CurrentTrimester > 0
			AllCurrentlyPregnant[i].SetFactionRank(Factions._MGF_PregStatusFact, CurrentTrimester)
		Else
			; Shouldn't normally happen but just in case. 
			AllCurrentlyPregnant[i].RemoveFromFaction(Factions._MGF_PregStatusFact)
		EndIf
		i += 1
	EndWhile
EndFunction

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

Function RelayConceived(Actor Mother, Actor Father, Int NumBabies) Global
	If Mother
		Int Handle = ModEvent.Create("_MGF_Preg_Conceived")
		If Handle
			ModEvent.PushForm(Handle, Mother)
			ModEvent.PushForm(Handle, Father)
			ModEvent.PushInt(Handle, NumBabies)
			ModEvent.Send(Handle)
		EndIf
	EndIf
EndFunction

Function RelayLaborStarted(Actor Mother, Actor Father, Int NumBabies) Global
	If Mother
		Int Handle = ModEvent.Create("_MGF_Preg_LaborStarted")
		If Handle
			ModEvent.PushForm(Handle, Mother)
			ModEvent.PushForm(Handle, Father)
			ModEvent.PushInt(Handle, NumBabies)
			ModEvent.Send(Handle)
		EndIf
	EndIf
EndFunction

Function RelayBirthed(Actor Mother, Actor Father, Int NumBabies, Form Baby) Global
	If Mother
		Int Handle = ModEvent.Create("_MGF_Preg_Birthed")
		If Handle
			ModEvent.PushForm(Handle, Mother)
			ModEvent.PushForm(Handle, Father)
			ModEvent.PushInt(Handle, NumBabies)
			ModEvent.PushForm(Handle, Baby)
			ModEvent.Send(Handle)
		EndIf
	EndIf
EndFunction

Function RelayAborted(Actor Mother, Actor Father) Global
	If Mother
		Int Handle = ModEvent.Create("_MGF_Preg_Aborted")
		If Handle
			ModEvent.PushForm(Handle, Mother)
			ModEvent.PushForm(Handle, Father)
			ModEvent.Send(Handle)
		EndIf
	EndIf
EndFunction

; =======================================================================================
; Rolling Logs ==========================================================================
; =======================================================================================

; Rolling 100 element logs of pregnancy events based around the player.

; Player got these actors pregnant ======================================================
Actor[] Function GetConceivedByPcLog(Bool FilterDisabled = true)
	; NPCs the player has impregnated. 
	Return ArrayActorSanitize(ConceivedWithLog, FilterDisabled, FilterDead = true)
EndFunction

Actor[] Function GetFatheredByPcLog(Bool FilterDisabled = true)
	; NPCs the player has fathered a birth with. 
	Return ArrayActorSanitize(BirthedWithLog, FilterDisabled, FilterDead = true)
EndFunction

; Player got impregnated by these actors ================================================
Actor[] Function GetConceivedWithPcLog(Bool FilterDisabled = true)
	; 'Men' who've conceived a pregnancy WITH the player
	Return ArrayActorSanitize(ConceivedWithMeLog, FilterDisabled, FilterDead = true)
EndFunction

Actor[] Function GetFatheredWithPcLog(Bool FilterDisabled = true)
	; 'Men' who've fathered a birth WITH the player.
	Return ArrayActorSanitize(BirthedWithMeLog, FilterDisabled, FilterDead = true)
EndFunction

Actor[] Function GetCurrentlyPregnantByPc(Bool FilterDisabled = true)
	Return ArrayActorSanitize(CurrentlyPregnantByPc, FilterDisabled, FilterDead = true)
EndFunction

Actor[] Function GetAllCurrentlyPregnant(Bool FilterDisabled = true)
	Return ArrayActorSanitize(AllCurrentlyPregnant, FilterDisabled, FilterDead = true)
EndFunction

; Fork state

String Function GetActiveState()
	Return GetState()
EndFunction

String Function GetActiveMod()
	Return ""
EndFunction

; =======================================================================================
; User Functions ========================================================================
; =======================================================================================

String Function GetCyclePhaseName(Actor Woman)
	; Human-readable label for GetCyclePhase()'s numeric result.
	; Not State dispatched - FM and BF use identical phase numbering.
	If IsPregnant(Woman)
		Return "Pregnant"
	EndIf
	; Postpartum recovery is neither pregnant nor cycling. 
	If IsInRecovery(Woman)
		Return "Recovering"
	EndIf
	Int Phase = GetCyclePhase(Woman)
	If Phase > -1
		Return CyclePhaseNames[Phase]
	EndIf
	Return "Unknown"
EndFunction

State Bf
	String Function GetActiveMod()
		; This backend's plugin filename.
		Return Mods[0]
	EndFunction

	Bool Function IsPregnant(Actor Woman)
		; True if currently pregnant.
		Return Bf.IsPregnant(Woman)
	EndFunction

	Int Function GetNumBabies(Actor Woman)
		; Babies in the current pregnancy.
		Return Bf.GetNumBabies(Woman)
	EndFunction

	Actor Function GetFather(Actor Woman)
		; First recorded father.
		Return Bf.GetFather(Woman)
	EndFunction

	Actor[] Function GetFathers(Actor Woman)
		; All recorded fathers - (BF's multi-Father mechanism)
		Return Bf.GetFathers(Woman)
	EndFunction

	Race Function GetFatherRace(Actor Woman)
		; First recorded father's race.
		Return Bf.GetFatherRace(Woman)
	EndFunction

	Race[] Function GetFatherRaces(Actor Woman)
		; Per-baby father races, index-aligned with GetFathers().
		Return Bf.GetFatherRaces(Woman)
	EndFunction

	Float Function GetPregnancyDay(Actor Woman)
		; Days since conception.
		Return Bf.GetPregnancyDay(Woman)
	EndFunction

	Float Function GetPregnancyDuration()
		; Configured full-term length, in days.
		Return Bf.GetPregnancyDuration()
	EndFunction

	Float Function GetPregnancyPercent(Actor Woman)
		; Progress through the pregnancy, 0-100.
		; Value is not clamped at the upper end - Can return values > 100.0
		; Eg: 110.0 = Woman is '10%' overdue. 
		Return Bf.GetPregnancyPercent(Woman)
	EndFunction

	Int Function GetTrimester(Actor Woman)
		; 1/2/3, or 0 if not pregnant.
		Return Bf.GetTrimester(Woman)
	EndFunction

	Int Function GetCyclePhase(Actor Woman)
		; 0-3, or -1 if pregnant/not tracked.
		Return Bf.GetCyclePhase(Woman)
	EndFunction

	Bool Function IsInRecovery(Actor Woman)
		; True during the postpartum window after a birth, before cycling resumes.
		Return Bf.IsInRecovery(Woman)
	EndFunction

	Int Function GetCycleDuration(Actor Woman)
		; BF's duration is actor/race scaled - 
		; A different Woman here can give a different answer (FM's version is the same for all).
		; 0 if Woman isn't currently tracked/cycling.
		Return Bf.GetCycleDuration(Woman)
	EndFunction

	Float Function GetCyclePercent(Actor Woman)
		; Progress through the current phase, 0 - 100.
		Return Bf.GetCyclePercent(Woman)
	EndFunction

	Float Function GetBabyHealthPercent(Actor Woman)
		; Unborn baby's health, 0 - 100.
		Return Bf.GetBabyHealthPercent(Woman)
	EndFunction

	Int Function GetNumBirths(Actor Woman)
		; Lifetime birth count.
		Return Bf.GetNumBirths(Woman)
	EndFunction

	Function Impregnate(Actor Mother, Actor Father, Int NumBabies = 1)
		; NumBabies is honored here - unlike FM/FMR below.
		Bf.Impregnate(Mother, Father, NumBabies)
	EndFunction
	
	Function ForceLabor(Actor Woman)
		; Skips straight to labor instead of waiting for term.
		Bf.ForceLabor(Woman)
	EndFunction

	Bool Function Abort(Actor Mother)
		; Abort a pregnancy
		Return Bf.Abort(Mother)
	EndFunction
EndState

State Fm
	String Function GetActiveMod()
		; This backend's plugin filename.
		Return Mods[1]
	EndFunction

	Bool Function IsPregnant(Actor Woman)
		; True if currently pregnant.
		Return Fm.IsPregnant(Woman)
	EndFunction

	Int Function GetNumBabies(Actor Woman)
		; Always 0 or 1 - FM only ever supports one baby per pregnancy.
		Return Fm.GetNumBabies(Woman)
	EndFunction

	Actor Function GetFather(Actor Woman)
		; The recorded father.
		Return Fm.GetFather(Woman)
	EndFunction

	Actor[] Function GetFathers(Actor Woman)
		; Always 0 or 1 entries - FM only ever has one father, wrapped in an array purely for parity with BF.
		Return Fm.GetFathers(Woman)
	EndFunction

	Race Function GetFatherRace(Actor Woman)
		; The recorded father's race.
		Return Fm.GetFatherRace(Woman)
	EndFunction

	Race[] Function GetFatherRaces(Actor Woman)
		; Always 0 or 1 entries - see GetFathers() above.
		Return Fm.GetFatherRaces(Woman)
	EndFunction

	Float Function GetPregnancyDay(Actor Woman)
		; Days since conception.
		Return Fm.GetPregnancyDay(Woman)
	EndFunction

	Float Function GetPregnancyDuration()
		; Configured full-term length, in days.
		Return Fm.GetPregnancyDuration()
	EndFunction

	Float Function GetPregnancyPercent(Actor Woman)
		; Progress through the pregnancy, 0-100. 
		; Not clamped at the upper end. Values > 100.0 are possible. 
		; Eg: 110.0 = Mother is '10%' overdue
		Return Fm.GetPregnancyPercent(Woman)
	EndFunction

	Int Function GetTrimester(Actor Woman)
		; 1/2/3, or 0 if not pregnant.
		Return Fm.GetTrimester(Woman)
	EndFunction

	Int Function GetCyclePhase(Actor Woman)
		; 0-3, or -1 if pregnant/not tracked.
		Return Fm.GetCyclePhase(Woman)
	EndFunction

	Bool Function IsInRecovery(Actor Woman)
		; True during the postpartum window after a birth, before cycling resumes.
		Return Fm.IsInRecovery(Woman)
	EndFunction

	Int Function GetCycleDuration(Actor Woman)
		; FM's cycle duration is a flat value. BF's is not. (See BF's version)
		; Parameter 'Woman' is here for function signature parity only. 
		Return Fm.GetCycleDuration()
	EndFunction

	Float Function GetCyclePercent(Actor Woman)
		; Progress through the whole cycle, 0-100.
		Return Fm.GetCyclePercent(Woman)
	EndFunction

	Float Function GetBabyHealthPercent(Actor Woman)
		; Unborn baby's health, 0-100 - only ever tracked for the player.
		Return Fm.GetBabyHealthPercent(Woman)
	EndFunction

	Int Function GetNumBirths(Actor Woman)
		; Lifetime birth count.
		Return Fm.GetNumBirths(Woman)
	EndFunction

	Function Impregnate(Actor Mother, Actor Father, Int NumBabies = 1)
		; NumBabies is silently ignored here - FM only ever supports one baby per pregnancy. 
		Fm.Impregnate(Mother, Father)
	EndFunction
	
	Function ForceLabor(Actor Woman)
		; Skips straight to labor instead of waiting for term.
		Fm.ForceLabor(Woman)
	EndFunction

	Bool Function Abort(Actor Mother)
		; Abort a pregnancy
		Return Fm.Abort(Mother)
	EndFunction
EndState

State Fmr
	String Function GetActiveMod()
		; Informational only - not what gates this State. See CornerstoneScript
		; below for the real detection.
		Return Mods[2]
	EndFunction

	Bool Function IsPregnant(Actor Woman)
		; True if currently pregnant.
		Return Fmr.IsPregnant(Woman)
	EndFunction

	Int Function GetNumBabies(Actor Woman)
		; Always 0 or 1 - FMR only ever supports one baby per pregnancy.
		Return Fmr.GetNumBabies(Woman)
	EndFunction

	Actor Function GetFather(Actor Woman)
		; The recorded father.
		Return Fmr.GetFather(Woman)
	EndFunction

	Actor[] Function GetFathers(Actor Woman)
		; Always 0 or 1 entries - same reason as FM's version above.
		Return Fmr.GetFathers(Woman)
	EndFunction

	Race Function GetFatherRace(Actor Woman)
		; None, always - FMR never got this built (see _MGF_InterfaceFmr, which
		; has no equivalent - sidelined along with the rest of FMR's newer
		; work). Not a claim that FMR lacks the underlying data.
		Return None
	EndFunction

	Race[] Function GetFatherRaces(Actor Woman)
		; Empty, always - see GetFatherRace() above.
		Return ArrayRaceCreate(0)
	EndFunction

	Float Function GetPregnancyDay(Actor Woman)
		; Days since conception.
		Return Fmr.GetPregnancyDay(Woman)
	EndFunction

	Float Function GetPregnancyDuration()
		; Configured full-term length, in days.
		Return Fmr.GetPregnancyDuration()
	EndFunction

	Float Function GetPregnancyPercent(Actor Woman)
		; Progress through the pregnancy, 0-100.
		Return Fmr.GetPregnancyPercent(Woman)
	EndFunction

	Int Function GetTrimester(Actor Woman)
		; 1/2/3, or 0 if not pregnant.
		Return Fmr.GetTrimester(Woman)
	EndFunction

	Int Function GetCyclePhase(Actor Woman)
		; -1, always - FMR has no cycle-phase concept implemented on our side
		; (see _MGF_InterfaceFmr, which never got this - sidelined along with
		; the rest of FMR's labor/cycle work). Not the same claim as "FMR has
		; no menstrual cycle" - we simply haven't built this for it yet.
		Return -1
	EndFunction

	Bool Function IsInRecovery(Actor Woman)
		; False, always - not built for FMR, same as GetCyclePhase() above.
		Return False
	EndFunction

	Int Function GetCycleDuration(Actor Woman)
		; 0, always - see GetCyclePhase() above.
		Return 0
	EndFunction

	Float Function GetCyclePercent(Actor Woman)
		; -1.0, always - see GetCyclePhase() above.
		Return -1.0
	EndFunction

	Float Function GetBabyHealthPercent(Actor Woman)
		; Unborn baby's health, 0-100 - only ever tracked for the player.
		Return Fmr.GetBabyHealthPercent(Woman)
	EndFunction

	Int Function GetNumBirths(Actor Woman)
		; -1, always - FMR doesn't track lifetime birth count at all, as far
		; as we've been able to find (see _MGF_IntFmr.GetNumBirths). Different
		; from BF/FM, where this is a real count.
		Return Fmr.GetNumBirths(Woman)
	EndFunction

	Function Impregnate(Actor Mother, Actor Father, Int NumBabies = 1)
		; NumBabies is silently ignored here - same limitation as State Fm.
		Fmr.Impregnate(Mother, Father)
	EndFunction
	
	Function ForceLabor(Actor Woman)
		; No-op, always - not built for FMR (see _MGF_InterfaceFmr, which has
		; no equivalent - sidelined along with the rest of FMR's labor work,
		; same as GetCyclePhase() above).
	EndFunction

	Bool Function Abort(Actor Mother)
		; Abort a pregnancy
		Return Fmr.Abort(Mother)
	EndFunction
EndState

; Empty state Functions =================================================

Bool Function IsPregnant(Actor Woman)
	Return false
EndFunction

Int Function GetNumBabies(Actor Woman)
	Return 0
EndFunction

Actor Function GetFather(Actor Woman)
	Return None
EndFunction

Actor[] Function GetFathers(Actor Woman)
	Return ArrayActorCreate(0)
EndFunction

Race Function GetFatherRace(Actor Woman)
	Return None
EndFunction

Race[] Function GetFatherRaces(Actor Woman)
	Return ArrayRaceCreate(0)
EndFunction

Float Function GetPregnancyDay(Actor Woman)
	Return -1.0
EndFunction

Float Function GetPregnancyDuration()
	Return 0.0
EndFunction

Float Function GetPregnancyPercent(Actor Woman)
	Return 0.0
EndFunction

Int Function GetTrimester(Actor Woman)
	Return 0
EndFunction

Int Function GetCyclePhase(Actor Woman)
	Return -1
EndFunction

Bool Function IsInRecovery(Actor Woman)
	Return False
EndFunction

Int Function GetCycleDuration(Actor Woman)
	Return 0
EndFunction

Float Function GetCyclePercent(Actor Woman)
	Return -1.0
EndFunction

Float Function GetBabyHealthPercent(Actor Woman)
	Return -1.0
EndFunction

Int Function GetNumBirths(Actor Woman)
	Return 0
EndFunction

Function Impregnate(Actor Mother, Actor Father, Int NumBabies = 1)
	; No-op - neither mod is installed/active.
EndFunction

; Ends a pregnancy without a birth. True only if there was one to end.
Bool Function Abort(Actor Mother)
	Return False
EndFunction

Function ForceLabor(Actor Woman)
	; No-op - neither mod is installed/active.
EndFunction

; Debug =================================================================================

Function Test(Actor Woman)
	Debug.Trace("_MGF_ForkPregnancy: Test Begin")
	Debug.Trace("_MGF_ForkPregnancy: Active Mod: " + GetActiveMod())
	Debug.Trace("_MGF_ForkPregnancy: Target: " + Woman)
	Debug.Trace("_MGF_ForkPregnancy: IsPregnant(): " + IsPregnant(Woman))
	Debug.Trace("_MGF_ForkPregnancy: GetNumBabies(): " + GetNumBabies(Woman))
	Debug.Trace("_MGF_ForkPregnancy: GetFather(): " + GetFather(Woman))
	Debug.Trace("_MGF_ForkPregnancy: GetPregnancyDay(): " + GetPregnancyDay(Woman))
	Debug.Trace("_MGF_ForkPregnancy: GetPregnancyDuration(): " + GetPregnancyDuration())
	Debug.Trace("_MGF_ForkPregnancy: GetPregnancyPercent(): " + GetPregnancyPercent(Woman))
	Debug.Trace("_MGF_ForkPregnancy: GetTrimester(): " + GetTrimester(Woman))
	Debug.Trace("_MGF_ForkPregnancy: GetBabyHealthPercent(): " + GetBabyHealthPercent(Woman))
	Debug.Trace("_MGF_ForkPregnancy: GetNumBirths(): " + GetNumBirths(Woman))
	Debug.Trace("_MGF_ForkPregnancy: Test End")
EndFunction

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

String[] Mods

; FMR needs file-existence gating instead of a plugin-name check because it uses the same FertilityMode.esm as the base mod. 
String Property CornerstoneScript = "Data/Scripts/_JSW_BB_DetectFertilityLoader.pex" AutoReadOnly Hidden

_MGF_InterfaceBf Property Bf Auto
_MGF_InterfaceFm Property Fm Auto
_MGF_InterfaceFmr Property Fmr Auto

Actor Property PlayerRef Auto

; Status board ===============================================================

_MGF_Globs Property Globs Auto
_MGF_Factions Property Factions Auto

; Alias indices
Int Property AliasCurrentFather = 0 AutoReadOnly Hidden
Int Property AliasPrevConcludedFather = 1 AutoReadOnly Hidden
Int Property AliasPrevBirthFather = 2 AutoReadOnly Hidden
Int Property AliasConceived0 = 3 AutoReadOnly Hidden
Int Property AliasConceived1 = 4 AutoReadOnly Hidden
Int Property AliasConceived2 = 5 AutoReadOnly Hidden
Int Property AliasBirthed0 = 6 AutoReadOnly Hidden
Int Property AliasBirthed1 = 7 AutoReadOnly Hidden
Int Property AliasBirthed2 = 8 AutoReadOnly Hidden

; Target window size for the four rolling logs. 
Int Property LogSize = 100 AutoReadOnly Hidden

; How often Trimester/CyclePhase/_MGF_PregStatusFact get re-checked. 
; The system is accurate to within this window. 
Float Property PollIntervalHours = 1.0 AutoReadOnly Hidden

; Display names for menstrual cycle phases. 
String[] Property CyclePhaseNames Auto Hidden

; Log arrays: 
Actor[] ConceivedWithLog ; Player-fathered
Actor[] BirthedWithLog ; Player-fathered
Actor[] ConceivedWithMeLog ; 'Men' who conceived with the player
Actor[] BirthedWithMeLog ; 'Men' who fathered a birth with the player
Actor[] CurrentlyPregnantByPc ; live, player-fathered only
Actor[] AllCurrentlyPregnant ; live, any father - drives _MGF_PregStatusFact's poll

; Exists specifically because BF clears its own father record before our 
; poll-based Birthed detection ever fires, so re-querying GetFathers() at that point 
; would return nothing. 
Actor[] CurrentFathersOfPc

 

 

Edited by Monoman1

0 Comments


Recommended Comments

There are no comments to display.

×
×
  • Create New...