Jump to content

Recommended Posts

Sex Education

View File

Sex Education

 

 

What does this mod do?

Having sex (through AAF) grants configurable experience points.

 

Why would I want this?

Because your character has a lot of sex and you want to level up faster? At the very least, you want a little compensation for time spent on your knees.

 

Personally I think this mod is best for play styles that are lighter on combat and heavier on sex. At the extreme end, that style might even stem from a prostitution scenario mod like Hardship, where XP is otherwise pretty hard to come by. Furthermore, not only is the bonus XP useful as an indirect source of self esteem for Sex Attributes, but SexEd also now includes the option to directly grant self esteem from consensual sex!

 

Isn't there another mod with a similar effect?

Lucrative Augments includes one augment that grants experience points for sex. Sex Education simply provides a more configurable version of this effect in a stand-alone package.

 

Features and Other Gritty Details

This mod works for any player gender and AAF animation, except for animations tagged hugging, dancing, or pose (kissing tags may be excluded in the MCM). Player can be pitching, catching, licking, spanking, or anything in between; XP will be granted as long as you are an actor in the animation. However, masturbation gives no XP. You only learn with at least one partner!

 

Sex Education includes the following MCM settings:

Spoiler

Mod On/Off: Master switch that will disable sex-based XP entirely.

 

Base XP Per Partner: Amount of baseline experience granted by each partner in an animation. For example, an animation with yourself and three partners will grant three helpings of baseline experience (one per partner) at the end of the animation. Any modifiers from Advanced Mode settings will apply to this value.

 

Sex Ed Mode: Two modes are available. Simple Mode is very straightforward, and grants baseline XP for each partner, every time, with no other modifiers. Advanced Mode will adjust earned XP based on the settings found under Advanced Mode Settings.

 

Allow XP For Kissing Tag: Some sex animations include kissing tag too. Player may choose whether to exclude animations with this tag from granting experience.

 

Advanced Mode Settings

XP Decay For Similar Partner: As long as Advanced Mode is active, Sex Education will dynamically track the number of sexual encounters with each combination of race type and gender (i.e. human male, ghoul female, supermutant male, etc). Each encounter with the same race/gender combination will provide slightly less XP based on this setting. This XP reduction is additive, not multiplicative. For example: using the default setting of 2%, after three encounters with a human male, the XP for the next encounter with a human male would be reduced by 6% (2+2+2).

 

Please note that the decay will eventually reach 100% reduction, granting zero XP unless you use a Minimum XP Per Partner setting greater than zero. Lastly, none of the races are hard coded; Sex Education will properly track every race type separately, including any DLC creatures or custom races used in animations.

 

Group Sex XP Modifier: Is your character the type who would learn more from a foursome than from banging three partners one by one? Or would they be too distracted and maybe learn a little less? With this setting, every simultaneous partner beyond the first will increase (or decrease) the total XP for the sexual encounter by your chosen amount.

 

Aggressive Sex XP%: Animations tagged “aggressive” can have their total XP adjusted here. Default setting is 50% as much XP as you'd earn for a non-aggressive animation. This default assumes you're the unfortunate recipient of aggressive sex, meaning you're less like a participant and more like a half-willing communal repository. However, if your character is the type to initiate aggressive sex on some poor captive, or if you feel your character could stand to “learn their place” in a more literal sense, this setting can be turned all the way up to 200%. Alternatively, this can be set to negative values if you prefer to actually lose experience.

 

Allow XP Loss Below Current Level: This setting can prevent XP falling below the current level minimum. Please note that you will not actually lose levels or perks, nor drop below 1 XP, regardless of settings.

 

Prevent/Allow FO4 XP Restoration: If player experience falls below their current level, FO4's engine will try to restore the difference in XP when you load a save. This MCM option can either allow or prevent that default behavior. The “Prevent” option means SexEd will track and store your experience whenever you open the menu. If it detects a higher experience value upon loading a save, SexEd will restore the last saved value.

 

Fellow Pitchers XP%: Players in the pitcher role (e.g. giver, fucker, penis/strapon donor) will always earn full XP from the catcher (e.g. receiver, fuckee, penis/strapon storage unit). If multiple pitchers are utilizing the same catcher in an animation, what percent of XP do you want to earn from the additional pitchers? I recommend leaving this value at 100% if you are usually the catcher in animations; that way you won't lose XP for edge cases where a group animation has a more ambiguous pitcher/catcher dynamic.

 

Minimum XP Per Partner: With the various Advanced Mode settings above, it's possible to reach a point where an encounter would grant zero XP. This setting ensures that you'll always earn at least some XP per partner, regardless of any other factors.

 

Mod Integration Settings

AAF Spectators XP On/Off: If AAF Spectators is installed, you can gain experience for being watched during sex. Any observers called by AAF Spectators will grant XP. This even works in simple mode or solo animations. Now you can level up by masturbating for a crowd!

 

Base XP Per Observer: Amount of baseline experience granted by each AAF Spectators observer.

 

XP% Reduction Per Extra Observer: Percent to reduce baseline experience earned from each AAF Spectators observer beyond the first. Values are additive.

 

Apply Aggressive Tag XP Modifier: If Advanced Mode is active, experience earned from AAF Spectators observers can be modified by the “Aggressive Sex XP%” setting.

 

Treat Raped/Rapist Flags as Aggressive: Various popular mods (e.g. Violate, SEU, MCG, Sexual Harassment, and others) include community standardized indicators when initiating AAF scenes. Player may choose to treat PlayerRaped and PlayerRapist flagged scenes as aggressive, regardless of animation tags.

 

Treat Consensual Flag as Non-Aggressive: Similar to the previous MCM option, player may choose to treat Consensual flagged scenes as non-aggressive, regardless of animation tags.

 

Self Esteem for Consensual Sex: If you have Sex Attributes installed, SexEd can grant a small amount of self esteem every time you have consensual sex.

 

Hardcore XP Mode

Hardcore XP Mode On/Off: When activated, any XP gained (outside of SexEd itself) can be reduced to nearly zero.

 

Hardcore XP% Earned: Adjusts the percentage of XP gained from sources other than SexEd.

 

 

 

Requirements

-Vanilla Fallout 4 (no DLCs needed)

-AAF with working animations. Sex Education contains no animations of its own.

-MCM, for mod settings and overall function.

-Tags for your animations (soft requirement). The main effect of missing tags will be a non-working Aggressive Sex XP% setting. I recommend installing AAF Themes. Alternatively, you can use animations that are tagged by the author, like those made by SavageCabbage (1.2.4+) and BP70 (2.7+). Certain patches add, revise, or substitute their own tags as well.

-Optional Requirement: AAF Spectators. If installed, integration settings can be used to earn XP when NPCs watch you have sex.

-Optional Requirement: Sex Attributes. If installed, integration settings can be used to earn self esteem after consensual sex.

 

Known Issues

-Gen 3 synths all use human race, so they'll be tracked as one race type instead of separately. Arguably, that's how they should be treated anyway...

-If a player animation starts while a separate NPC animation is in progress, player may receive XP credit for the NPC's spectators (when using AAF Spectators integration).

 

My Thanks To

-kinggath, who I cannot praise enough for his incredibly detailed and informative “Bethesda Mod School” series on YouTube. Don't stab around in the dark, go learn from his hundreds (thousands?) of hours of modding experience.

-EgoBallistic, twistedtrebla, and Nebuchadnezzer2, all of whose excellent scripting I studied, scoured, pondered, and otherwise picked apart to figure out how to make my mods hum.

-Double secret bonus thanks to Nebuchadnezzer2, whose top notch Cum Overlays mod had such a good AAF listening structure that I tried my best not to just plagiarize it directly (and partially succeeded) ?.

-Special thanks to the AAF Help discord for sorting me out back when I was a wide-eyed newbie, to whom the secrets of mod-making were akin to sorcery.

-Honorable mention to Saya_Scarlett for the often thankless work of maintaining the definitive AAF Fucking Manual.

 

 

Permissions

Feel free to re-post, re-host, patch, translate, and/or incorporate into your own mods as long as the result is freely available and not paywalled. Just give credit back to me and the original LL post. No support offered for sites outside of LL.


  • Submitter
  • Submitted
    04/19/2021
  • Category
  • Requires
    AAF, Animations, MCM, Themes (soft req.), AAF Spectators (optional)

 

Edited by spicydoritos
Updated description for 1.21
Link to comment
9 hours ago, spicydoritos said:

Known Issues

-Because Sex Education tracks races for XP Decay dynamically, we're at the mercy of Bethesda's race types. For example, there are three races of vanilla dogs (ViciousDogRace, RaiderDogRace, and DogmeatRace) that will be tracked separately when arguably they should use a single entry. Same issue with Gen 2 synths and Valentine, who inexplicably has his own race. Plus, of course, Gen 3 synths all use human race, so they'll be tracked as the same race type instead of separately. I think it's a worthwhile tradeoff for the flexibility of handling any vanilla, DLC, or custom race type.

 

-Group sex XP makes more sense as the catcher than as a pitcher. Regardless of your role in an animation, you'll earn the same XP. So take, for example, an all-human MMMF animation with your character as the female center of attention. You would earn 3x baseline XP before multipliers and get statistics incremented for 3 human male partners. On the other hand, if your character was one of those human males, you would still earn 3x baseline XP while also having your statistics incremented by 2 human males and 1 human female. Sex Education simply cannot differentiate “having sex with someone” from “sharing a partner”.

The former, I think, could be handled somewhat similar to Violate's handling of races, with an array of similar races clustered together, and treated as one.
I think another way around requiring DLC in the plugin, would be to wait for `OnAAFReady`, then use `GetActorTypeList`, and go through that array to fill out one or more lists of similar races (Dogs being the most obvious example). Would have to go digging more, but the method you went with is, as you say, a worthwhile tradeoff, I think.

 

The latter, you can set up separate XP rewards for 'participating' vs 'receiving', and check the actors for the player. Should only need to have stored the player reference as an `Actor Property`, in much the same way I did `OverlayRef`, and a short `While` loop to check through the actor array, with an if/else to use one, or the other.

Actually, looking at the script, with some more added to the `If actors.find(PlayerRef)`, you could do that.
For example;

Spoiler

Instead of
       If actors.find(PlayerRef) < 0
            DTrace("Player was not involved in this animation.")
            Return
        EndIf

 

        int actorPlayer = actors.find(PlayerRef)
        If actorPlayer < 0
            DTrace("Player was not involved in this animation.")
            Return

        EndIf

        If actorPlayer == 0
            DTrace("Player was 'receiver' in this animation.")

        ElseIf actorPlayer > 0

            DTrace("Player was 'giver' in this animation.")

        EndIf

Either way, nicely done.
I remember seeing someone mention something about getting XP from AAF scenes recently, so good timing, too.
Will have to go on the list for if when I finally update and adjust my install to use it again.

Congrats on releasing it :smile:

Link to comment
45 minutes ago, Nebuchadnezzer2 said:

The former, I think, could be handled somewhat similar to Violate's handling of races, with an array of similar races clustered together, and treated as one.
I think another way around requiring DLC in the plugin, would be to wait for `OnAAFReady`, then use `GetActorTypeList`, and go through that array to fill out one or more lists of similar races (Dogs being the most obvious example). Would have to go digging more, but the method you went with is, as you say, a worthwhile tradeoff, I think.

 

The latter, you can set up separate XP rewards for 'participating' vs 'receiving', and check the actors for the player. Should only need to have stored the player reference as an `Actor Property`, in much the same way I did `OverlayRef`, and a short `While` loop to check through the actor array, with an if/else to use one, or the other.

Actually, looking at the script, with some more added to the `If actors.find(PlayerRef)`, you could do that.
For example;

  Hide contents

Instead of
       If actors.find(PlayerRef) < 0
            DTrace("Player was not involved in this animation.")
            Return
        EndIf

 

        int actorPlayer = actors.find(PlayerRef)
        If actorPlayer < 0
            DTrace("Player was not involved in this animation.")
            Return

        EndIf

        If actorPlayer == 0
            DTrace("Player was 'receiver' in this animation.")

        ElseIf actorPlayer > 0

            DTrace("Player was 'giver' in this animation.")

        EndIf

Either way, nicely done.
I remember seeing someone mention something about getting XP from AAF scenes recently, so good timing, too.
Will have to go on the list for if when I finally update and adjust my install to use it again.

Congrats on releasing it :smile:

Yeah I see what you're talking about with Violate's race arrays.  I waffled back and forth on whether to include the race types as properties for some kind of grouping (and I like the arrays better than the scripted groupings I might have done otherwise).  In the end I decided I'd rather have total flexibility of race types even if the player gets a bit more XP than expected, occasionally.  Race tracking really only matters for the XP decay setting anyway.  On the DLC note, if you know of a way to reference those creatures without requiring the plugin, that'd be quite useful!  Granted, I think it's silly for anyone to not have the DLC at this point in the game's life...

 

I like that technique to differentiate pitchers and catchers.  That might be worth adding, along with an MCM option to let the player choose whether their position influences XP gained.  It'd work very well for animations with one catcher and multiple pitchers.  There are a couple outlier cases where I think it might break down, notably the Love Triangle and Lesbian Threesome animations by BP70.  Player *might* end up as actor[0] in those animations or not, while still being either giver, receiver, or both.

 

And thank you!  The script structure of Cum Overlays was a big help ("listen for an AAF animation and do X").

Link to comment
13 minutes ago, spicydoritos said:

  In the end I decided I'd rather have total flexibility of race types even if the player gets a bit more XP than expected, occasionally.  Race tracking really only matters for the XP decay setting anyway.

That was also part of why I thought "well, it's probably not worth the effort to combine 'em", especially with the options you've got already for customising things.

14 minutes ago, spicydoritos said:

On the DLC note, if you know of a way to reference those creatures without requiring the plugin, that'd be quite useful!  Granted, I think it's silly for anyone to not have the DLC at this point in the game's life...

Agreed, with how cheap it gets, now.

Can set up a similar method to getting the AAF API and checking MCM's installed.
There's `IsPluginInstalled`;

Spoiler

; Is the specified plugin (esm or esp) installed?
bool Function IsPluginInstalled(string asName) native global

Vanilla, I believe, but extended with F4SE.
Just need the plugin name to send it.
Can check if the relevant DLC's are installed in an `If`, and if so, go ahead and use `Game.GetFormFromFile` to fill some blank `Keyword Property`'s.

32 minutes ago, spicydoritos said:

There are a couple outlier cases where I think it might break down, notably the Love Triangle and Lesbian Threesome animations by BP70.  Player *might* end up as actor[0] in those animations or not, while still being either giver, receiver, or both.

It's assumed that actor[0] is (always) the 'receiving' actor, with the rest as 'giving', so most of the edge cases would be shit like the Love Triangle one, where it's a bit more ambiguous/there's technically more than one 'receiver', but for the most part, it'll be fine, and a little more XP here or there from something like that won't make much of a difference, in the end.

39 minutes ago, spicydoritos said:

And thank you!  The script structure of Cum Overlays was a big help ("listen for an AAF animation and do X").

I did see some familiar segments, but that's what the sources were for, and I'm glad it helped!
Borrowed some ideas from Ego's scripts for SEU/Violate, and beat my head on a few walls here and there in trying to think through how to get something working, and buried my head in other scripts (F4SE, MCM, Vanilla game ones, etc.) but it certainly paid off.

Link to comment
38 minutes ago, Nebuchadnezzer2 said:

It's assumed that actor[0] is (always) the 'receiving' actor, with the rest as 'giving', so most of the edge cases would be shit like the Love Triangle one, where it's a bit more ambiguous/there's technically more than one 'receiver', but for the most part, it'll be fine, and a little more XP here or there from something like that won't make much of a difference, in the end.

Yeah I suppose it's not the worst thing.  You'd also potentially encounter *less* XP if you're unexpectedly cast as a giver when you think you're a receiver.  However, those cases would be rare I think.  Rare enough to be worth the effort of parsing the roles out, dropping an MCM setting in place, and letting the player choose their poison. 

 

Quote

I did see some familiar segments, but that's what the sources were for, and I'm glad it helped!
Borrowed some ideas from Ego's scripts for SEU/Violate, and beat my head on a few walls here and there in trying to think through how to get something working, and buried my head in other scripts (F4SE, MCM, Vanilla game ones, etc.) but it certainly paid off.

I tried my best not to plagiarize too badly (except from Ego, whose mods were open season at the time of writing ?).  Nonetheless I'm happy to credit your work more directly if it's a little too familiar!

 

Edit: Additional credit has been applied and you can't stop me.

Link to comment
1 minute ago, spicydoritos said:

I tried my best not to plagiarize too badly (except from Ego, whose mods were open season at the time of writing ?).  Nonetheless I'm happy to credit your work more directly if it's a little too familiar!

Totally didn't do the same before he had a hiatus:no_mouth:

Reminds me, will have to remember to go look at Kinggath's youtube stuff, too...

And no, you're fine. A mention like you've got there's plenty, to me.
Almost a year, and 27k downloads later (jesus, I didn't realise it hit that many), I still get a kick outta spottin my mod in load orders (usually when helpin out in the AAF Discord).
Just glad it's been useful and isn't bug riddled :P

 

Congrats again :classic_smile:

Link to comment

Education.... Really?

For some reason I don't understand why or why is education a reward?

Rewarding an activity like killing or ... plugging is one of the proponents of the game ... so it’s a player development tool.

So "development" would be a good term ...  ye.gif.5021f635a33fbd52009db5eaa8a69178.gif

"Sex Developer" or "Sex promote development" or anything like that...

Here, think about this ...

 

2071223949_Fallout42021-04-2000-45-38-58.jpg.dcfaad48f64198643ddf044c48730481.jpg

 

Valamiért nem értem mitől vagy miért "nevelés" a jutalmazás? A szexuális tevékenység díjazása... ?

A magyar az oktatás és a nevelés kifejezést használja ehhez a szóhoz. Az idomítás csak időszakos használatú de az se illik ide. Szerintem... nem.  A tevékenység jutalmazása mint a gyilkolás vagy a ... dugás a játék egyik előrevivő ... tehát a játékost fejlesztő eszköz. Így a "fejlesztés" lenne a jó kifejezés...

"Szexfejlesztő", "Szexfejlődés segítése" vagy bármi hasonló az... realitás. Tessék ezen elgondolkodni ...

 

2112372635_Fallout42021-04-2014-52-46-81.jpg.a25934833107bcda2eff5bf4443f21a3.jpg

Link to comment
3 hours ago, kukoricamorzsa said:

Education.... Really?

For some reason I don't understand why or why is education a reward?

 

The mod title is a reference to classes in the US where they teach students about the basics of human sexuality (anatomy, reproduction, safe sex, birth control, etc).  Such classes are  often called "Sex Education".

Link to comment
35 minutes ago, spicydoritos said:

The mod title is a reference to classes in the US where they teach students about the basics of human sexuality (anatomy, reproduction, safe sex, birth control, etc).  Such classes are  often called "Sex Education".


I have a friend who writes erotica, her stories are a slew of American pop culture puns so I get it.

 

Link to comment
On 4/20/2021 at 4:54 PM, spicydoritos said:

The mod title

Hahaha... but this is game! 

And if I'm not wrong at school they don't give a reward because ... students fuck ... hahaha... 

One of the fucking games rewarding supplement. It doesn't really have much to do with the "to idea or (to conception)"!

The whole supply is different from the "imagination" just described. 

 

The more you fuck, the more the reward.

Would that be the essence of sex education and upbringing? Or is this the basic idea of a street girl education !? hahaha....

 

Maybe the shotgun ... should not be caught the other way around when shooting!  ye.gif.00b1e42be5cbf41baacf415eb48c0bf5.gif 

 

Still, it's very good ... as it is. If so, what about? What should have been accepted should be accepted. Then in another round, in a more thoughtful way, you will PROHIBIT the fucking show instead of rewarding it and then the current idea will also take place. But then they won't be used as much as they are now ...

 

586532707_Fallout42021-04-2001-55-14-48.jpg.41c5ec9de2b609dddf1bde5e12182f75.jpg

 

Nerm deduction ... reward. 

You do not get it, right?  hahaha...

 

 

_______________________________

De ez egy játék! A baszós játék egyik jutalmazó kiegészítője. Valójában nem sok köze van az "elképzeléshez" !

és ha nem tévedek az iskolában nem adnak jutalmat azért mert a... diákok dugnak...

Az egész kínálat másban mutatkozik mint a most leírt "képzelgés". 

 

** A mód azért "fizet" (jutalmaz)... hogy basszál.

Minél többet baszol, annál több a jutalom. 

A szexuális nevelés alapja... nem az, hogy fűvel-fával dugj. Az a bizonyos oktatási forma a társadalmi elvek szerinti elvárásokat próbálja érvényesíteni. Tehát a visszafogást és a felelősségtejes viselkedést tanítja. Elsődlegesen azt, hogy a kutya, ló, gorilla... nem a szexuális igény kielégítésére való. 

 

Minden bizonnyal a teljes elgondolást újra kellene definiálni.... de akkor ki a fenét érdekelne... ITT!?

 

Mindazonáltal nagyon jó úgy... ahogyan van. Ha így sikerül, na és? El kellene fogadni annak ami lett. ye.gif.00b1e42be5cbf41baacf415eb48c0bf5.gif  Majd egy másik körben átgondoltabb módon TILTANI FOGJA a baszóműsort jutalmazás helyett és akkor a mostani elképzelés is helyet nyer. De akkor közel sem fogják annyian használni, mint most...

 

A jutalom... az jutalom.  Az iskolai oktatás ( - a program mód szerint - egy kurvaképző) azonban olyan, amilyen.

577901496_Fallout42021-04-2117-39-18-24.jpg.b1e8af3623702299d6745fe87a1a8407.jpg

Link to comment

Version 1.10 is up!

-Includes optional integration with AAF Spectators.  If that mod is installed, you can earn XP when NPCs watch you get busy.

(thanks for the great suggestion, kakkaohjus!)

 

Edit: Posted a 1.10a version to fix an issue I found with counting of spectators.

Link to comment
On 4/19/2021 at 9:20 AM, spicydoritos said:

Known Issues

-Because Sex Education tracks races for XP Decay dynamically, we're at the mercy of Bethesda's race types. For example, there are three races of vanilla dogs (ViciousDogRace, RaiderDogRace, and DogmeatRace) that will be tracked separately when arguably they should use a single entry. Same issue with Gen 2 synths and Valentine, who inexplicably has his own race. Plus, of course, Gen 3 synths all use human race, so they'll be tracked as the same race type instead of separately. I think it's a worthwhile tradeoff for the flexibility of handling any vanilla, DLC, or custom race type.

 

Here, from the work on the mod I'm currently doing:

 

Spoiler

Race Function GetNativeHumanRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x00013746, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeHumanChildRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x0011D83F, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeFeralGhoulRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x0006B4EC, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeGhoulRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x000EAFB6, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeGlowingOneRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x000A96BF, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeGhoulChildRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x0011EB96, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeSuperMutantRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x0001A009, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeMutantHoundRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x00090C33, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeBehemothRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x000BB7D9, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeGen1SynthRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x000E8D09, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeGen2SynthRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x0010BD65, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeGen2P5SynthRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x002261A4, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeMrHandyRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x000359F4, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeEyeBotRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x000A563A, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeSentryBotRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x000AE0B7, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeTripodTurretRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x000B1F08, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeBubbleTurretRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x000B28D3, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeVertibirdRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x000D77E3, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeAssaultronRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x000D8417, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeProtectronRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x000DFB33, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeLibertyPrimeRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x00108019, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeSettlementTurretRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x001A6D64, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeRobobrainAutomatronRace(string callerId = "Default") global
	if Game.IsPluginInstalled("DLCRobot.esm")
		return Game.GetFormFromFile(0x00001129, "DLCRobot.esm") as Race
	endif
	return None
EndFunction

Race Function GetNativeSettlementSpotlightAutomatronRace(string callerId = "Default") global
	if Game.IsPluginInstalled("DLCRobot.esm")
		return Game.GetFormFromFile(0x00002804, "DLCRobot.esm") as Race
	endif
	return None
EndFunction

Race Function GetNativeBubbleTurretFarHarborRace(string callerId = "Default") global
	if Game.IsPluginInstalled("DLCCoast.esm")
		return Game.GetFormFromFile(0x00009591, "DLCCoast.esm") as Race
	endif
	return None
EndFunction

Race Function GetNativeIndexerFarHarborRace(string callerId = "Default") global
	if Game.IsPluginInstalled("DLCCoast.esm")
		return Game.GetFormFromFile(0x0002E010, "DLCCoast.esm") as Race
	endif
	return None
EndFunction

Race Function GetNativeRobobrainFarHarborRace(string callerId = "Default") global
	if Game.IsPluginInstalled("DLCCoast.esm")
		return Game.GetFormFromFile(0x00033E79, "DLCCoast.esm") as Race
	endif
	return None
EndFunction

Race Function GetNativeAnimatronicAlienNukaWorldRace(string callerId = "Default") global
	if Game.IsPluginInstalled("DLCNukaWorld.esm")
		return Game.GetFormFromFile(0x000019126, "DLCNukaWorld.esm") as Race
	endif
	return None
EndFunction

Race Function GetNativeZetanAlienRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x00184C4D, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeBloodbugRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x0002456D, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeBloatflyRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x00029463, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeRadroachRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x0004716C, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeStingwingRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x0005FBB1, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeCaveCricketNukaWorldRace(string callerId = "Default") global
	if Game.IsPluginInstalled("DLCNukaWorld.esm")
		return Game.GetFormFromFile(0x0000AAFE, "DLCNukaWorld.esm") as Race
	endif
	return None
EndFunction

Race Function GetNativeSwarmNukaWorldRace(string callerId = "Default") global
	if Game.IsPluginInstalled("DLCNukaWorld.esm")
		return Game.GetFormFromFile(0x0000B028, "DLCNukaWorld.esm") as Race
	endif
	return None
EndFunction

Race Function GetNativeAntNukaWorldRace(string callerId = "Default") global
	if Game.IsPluginInstalled("DLCNukaWorld.esm")
		return Game.GetFormFromFile(0x0000CE5E, "DLCNukaWorld.esm") as Race
	endif
	return None
EndFunction

Race Function GetNativeMirelurkRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x00023FFC, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeMirelurkHunterRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x00064C60, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeMirelurkKingRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x000B7F91, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeMirelurkQueenRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x000E12A6, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeAnglerFarHarborRace(string callerId = "Default") global
	if Game.IsPluginInstalled("DLCCoast.esm")
		return Game.GetFormFromFile(0x0000FEEA, "DLCCoast.esm") as Race
	endif
	return None
EndFunction

Race Function GetNativeFogCrawlerFarHarborRace(string callerId = "Default") global
	if Game.IsPluginInstalled("DLCCoast.esm")
		return Game.GetFormFromFile(0x00014174, "DLCCoast.esm") as Race
	endif
	return None
EndFunction

Race Function GetNativeHermitCrabFarHarborRace(string callerId = "Default") global
	if Game.IsPluginInstalled("DLCCoast.esm")
		return Game.GetFormFromFile(0x000180A8, "DLCCoast.esm") as Race
	endif
	return None
EndFunction

Race Function GetNativeGulperFarHarborRace(string callerId = "Default") global
	if Game.IsPluginInstalled("DLCCoast.esm")
		return Game.GetFormFromFile(0x000247C1, "DLCCoast.esm") as Race
	endif
	return None
EndFunction

Race Function GetNativeSmallGulperFarHarborRace(string callerId = "Default") global
	if Game.IsPluginInstalled("DLCCoast.esm")
		return Game.GetFormFromFile(0x0004E28E, "DLCCoast.esm") as Race
	endif
	return None
EndFunction

Race Function GetNativeMoleRatRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x0001D810, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeDeathclawRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x0001DB4A, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeBrahminRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x0002047E, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeMongrelRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x0003578A, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeRadscorpionRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x000636AB, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeRadstagRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x0007ED1D, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeYaoGuaiRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x000A0F2F, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeCatRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x000C9ACF, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeGorillaRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x000D9804, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeRaiderDogRace(string callerId = "Default") global
	return Game.GetFormFromFile(0x00187AF9, "Fallout4.esm") as Race
EndFunction

Race Function GetNativeMutatedWolfFarHarborRace(string callerId = "Default") global
	if Game.IsPluginInstalled("DLCCoast.esm")
		return Game.GetFormFromFile(0x0003D077, "DLCCoast.esm") as Race
	endif
	return None
EndFunction

Race Function GetNativeRadRabbitFarHarborRace(string callerId = "Default") global
	if Game.IsPluginInstalled("DLCCoast.esm")
		return Game.GetFormFromFile(0x0003DDDE, "DLCCoast.esm") as Race
	endif
	return None
EndFunction

Race Function GetNativeRadChickenFarHarborRace(string callerId = "Default") global
	if Game.IsPluginInstalled("DLCCoast.esm")
		return Game.GetFormFromFile(0x0003FD66, "DLCCoast.esm") as Race
	endif
	return None
EndFunction

Race Function GetNativeBloodwormNukaWorldRace(string callerId = "Default") global
	if Game.IsPluginInstalled("DLCNukaWorld.esm")
		return Game.GetFormFromFile(0x0000A1A6, "DLCNukaWorld.esm") as Race
	endif
	return None
EndFunction

Race Function GetNativeRadRatNukaWorldRace(string callerId = "Default") global
	if Game.IsPluginInstalled("DLCNukaWorld.esm")
		return Game.GetFormFromFile(0x0000C606, "DLCNukaWorld.esm") as Race
	endif
	return None
EndFunction

Race Function GetNativeQuantumDeathclawNukaWorldRace(string callerId = "Default") global
	if Game.IsPluginInstalled("DLCNukaWorld.esm")
		return Game.GetFormFromFile(0x0000D329, "DLCNukaWorld.esm") as Race
	endif
	return None
EndFunction

Race Function GetNativeBrahmiluffNukaWorldRace(string callerId = "Default") global
	if Game.IsPluginInstalled("DLCNukaWorld.esm")
		return Game.GetFormFromFile(0x00023435, "DLCNukaWorld.esm") as Race
	endif
	return None
EndFunction

Race Function GetNativeGatorclawNukaWorldRace(string callerId = "Default") global
	if Game.IsPluginInstalled("DLCNukaWorld.esm")
		return Game.GetFormFromFile(0x0003637A, "DLCNukaWorld.esm") as Race
	endif
	return None
EndFunction

; Alternative (cleaner?) approach would be to define stuff in FormLists
; That, however, will not allow for dynamic DLCs resolution in runtime and will add hard dependency 
bool Function IsHumanRace(Race source, string callerId = "Default") global
	if source == GetNativeHumanRace(callerId)
		return true
	endif
	if source == GetNativeHumanChildRace(callerId)
		return true
	endif
	return false
EndFunction

bool Function IsGhoulRace(Race source, string callerId = "Default") global
	if source == GetNativeFeralGhoulRace(callerId)
		return true
	endif
	if source == GetNativeGhoulRace(callerId)
		return true
	endif
	if source == GetNativeGlowingOneRace(callerId)
		return true
	endif
	if source == GetNativeGhoulChildRace(callerId)
		return true
	endif
	return false
EndFunction

bool Function IsMutantRace(Race source, string callerId = "Default") global
	if source == GetNativeSuperMutantRace(callerId)
		return true
	endif
	if source == GetNativeMutantHoundRace(callerId)
		return true
	endif
	if source == GetNativeBehemothRace(callerId)
		return true
	endif
	
	return false
EndFunction

bool Function IsSynthRace(Race source, string callerId = "Default") global
	if source == GetNativeGen1SynthRace(callerId)
		return true
	endif
	if source == GetNativeGen2SynthRace(callerId)
		return true
	endif
	if source == GetNativeGen2P5SynthRace(callerId)
		return true
	endif
	
	return false
EndFunction

bool Function IsRobotRace(Race source, string callerId = "Default") global
	if source == GetNativeMrHandyRace(callerId)
		return true
	endif
	if source == GetNativeEyeBotRace(callerId)
		return true
	endif
	if source == GetNativeSentryBotRace(callerId)
		return true
	endif
	if source == GetNativeTripodTurretRace(callerId)
		return true
	endif
	if source == GetNativeBubbleTurretRace(callerId)
		return true
	endif
	if source == GetNativeVertibirdRace(callerId)
		return true
	endif
	if source == GetNativeAssaultronRace(callerId)
		return true
	endif
	if source == GetNativeProtectronRace(callerId)
		return true
	endif
	if source == GetNativeLibertyPrimeRace(callerId)
		return true
	endif
	if source == GetNativeSettlementTurretRace(callerId)
		return true
	endif
	
	if Game.IsPluginInstalled("DLCRobot.esm")
		if source == GetNativeRobobrainAutomatronRace(callerId)
			return true
		endif
		if source == GetNativeSettlementSpotlightAutomatronRace(callerId)
			return true
		endif
	endif
	
	if Game.IsPluginInstalled("DLCCoast.esm")
		if source == GetNativeBubbleTurretFarHarborRace(callerId)
			return true
		endif
		if source == GetNativeIndexerFarHarborRace(callerId)
			return true
		endif
		if source == GetNativeRobobrainFarHarborRace(callerId)
			return true
		endif
	endif
	
	if Game.IsPluginInstalled("DLCNukaWorld.esm")
		if source == GetNativeAnimatronicAlienNukaWorldRace(callerId)
			return true
		endif
	endif
	
	return false
EndFunction

bool Function IsBugRace(Race source, string callerId = "Default") global
	if source == GetNativeBloodbugRace(callerId)
		return true
	endif
	if source == GetNativeBloatflyRace(callerId)
		return true
	endif
	if source == GetNativeRadroachRace(callerId)
		return true
	endif
	if source == GetNativeStingwingRace(callerId)
		return true
	endif
	
	if Game.IsPluginInstalled("DLCNukaWorld.esm")
		if source == GetNativeCaveCricketNukaWorldRace(callerId)
			return true
		endif
		if source == GetNativeSwarmNukaWorldRace(callerId)
			return true
		endif
		if source == GetNativeAntNukaWorldRace(callerId)
			return true
		endif
	endif
	
	return false
EndFunction

bool Function IsSeaworldRace(Race source, string callerId = "Default") global
	if source == GetNativeMirelurkRace(callerId)
		return true
	endif
	if source == GetNativeMirelurkHunterRace(callerId)
		return true
	endif
	if source == GetNativeMirelurkKingRace(callerId)
		return true
	endif
	if source == GetNativeMirelurkQueenRace(callerId)
		return true
	endif
	
	if Game.IsPluginInstalled("DLCCoast.esm")
		if source == GetNativeAnglerFarHarborRace(callerId)
			return true
		endif
		if source == GetNativeFogCrawlerFarHarborRace(callerId)
			return true
		endif
		if source == GetNativeHermitCrabFarHarborRace(callerId)
			return true
		endif
		if source == GetNativeGulperFarHarborRace(callerId)
			return true
		endif
		if source == GetNativeSmallGulperFarHarborRace(callerId)
			return true
		endif
	endif
	
	return false
EndFunction

bool Function IsAnimalRace(Race source, string callerId = "Default") global
	if source == GetNativeMoleRatRace(callerId)
		return true
	endif
	if source == GetNativeDeathclawRace(callerId)
		return true
	endif
	if source == GetNativeBrahminRace(callerId)
		return true
	endif
	if source == GetNativeMongrelRace(callerId)
		return true
	endif
	if source == GetNativeRadscorpionRace(callerId)
		return true
	endif
	if source == GetNativeRadstagRace(callerId)
		return true
	endif
	if source == GetNativeYaoGuaiRace(callerId)
		return true
	endif
	if source == GetNativeCatRace(callerId)
		return true
	endif
	if source == GetNativeGorillaRace(callerId)
		return true
	endif
	if source == GetNativeRaiderDogRace(callerId)
		return true
	endif
	
	if Game.IsPluginInstalled("DLCCoast.esm")
		if source == GetNativeMutatedWolfFarHarborRace(callerId)
			return true
		endif
		if source == GetNativeRadRabbitFarHarborRace(callerId)
			return true
		endif
		if source == GetNativeRadChickenFarHarborRace(callerId)
			return true
		endif
	endif
	
	if Game.IsPluginInstalled("DLCNukaWorld.esm")
		if source == GetNativeBloodwormNukaWorldRace(callerId)
			return true
		endif
		if source == GetNativeRadRatNukaWorldRace(callerId)
			return true
		endif
		if source == GetNativeQuantumDeathclawNukaWorldRace(callerId)
			return true
		endif
		if source == GetNativeBrahmiluffNukaWorldRace(callerId)
			return true
		endif
		if source == GetNativeGatorclawNukaWorldRace(callerId)
			return true
		endif
	endif
	
	return false
EndFunction

 

 

Feel free to use / rehash / restructure. It will definitely solve the problems with mapping the native races into something you want to identify as the same thing.

Link to comment
5 minutes ago, Operand said:

Feel free to use / rehash / restructure. It will definitely solve the problems with mapping the native races into something you want to identify as the same thing.

I know I *can* map the races with script properties and form calls to combine them; I did it for my other mod (She's Got That Glow).  The issue is that I can't map them without also losing the flexibility to track current (and future) custom races as separate entries.  Ditto for DLC races.  As far as I know I can't run form calls on other mods without incurring unwanted dependencies.  For the purposes of this mod, I'm of the opinion that flexibility is more valuable than race groupings.

Link to comment
17 minutes ago, spicydoritos said:

As far as I know I can't run form calls on other mods without incurring unwanted dependencies

 

You can. CallFunction / CallGlobalFunction / GetFormFromFile are meant to be used exactly for that (you can also see the usage of the latter in the code above to dynamically resolve DLCs and use records from them without introducing hard DLC dependencies in the mod). But - oh well, I wished for the best. Apologies for the bother.

Link to comment
11 minutes ago, Operand said:

 

You can. CallFunction / CallGlobalFunction / GetFormFromFile are meant to be used exactly for that (you can also see the usage of the latter in the code above to dynamically resolve DLCs and use records from them without introducing hard DLC dependencies in the mod). But - oh well, I wished for the best. Apologies for the bother.

No, I appreciate the input, and I apologize if I came off short.

 

That's actually good to know about the non-dependency, and upon reflection I asked myself why I was stuck on doing it fully one way or another (form calls vs purely GetRace).  There's no reason I couldn't do a hybrid and just make a couple extra property arrays for the races I want to group.

Link to comment
16 minutes ago, spicydoritos said:

That's actually good to know about the non-dependency, and upon reflection I asked myself why I was stuck on doing it fully one way or another (form calls vs purely GetRace).  There's no reason I couldn't do a hybrid and just make a couple extra property arrays for the races I want to group.

 

To be frank, your issue sounds like a perfect use-case for doing the dynamic resolution. Why? Because new mods featuring races in Fallout4 come out so rare that even now there are less new races (worth attention) than fingers on one hand. Or two hands, if you include everything. This means that occasional update for it would need to be done once per half a year (if at all). And that update would be either adding a new native race option (like in the code above) or just another entry to the internal array (like you mentioned).

 

I chose methods over arrays because recompiling a script with another method call from within an existing method is completely safe and can be updated just by overwriting the old mod version whereas arrays require some updating mechanism since they are stored in the saves.

 

So knowing that, you can reliably map the native racial entries to whichever structures you want. 99.99% of the work needs to be done only once - for races from base game and game DLCs.

Link to comment
30 minutes ago, Operand said:

 

To be frank, your issue sounds like a perfect use-case for doing the dynamic resolution. Why? Because new mods featuring races in Fallout4 come out so rare that even now there are less new races (worth attention) than fingers on one hand. Or two hands, if you include everything. This means that occasional update for it would need to be done once per half a year (if at all). And that update would be either adding a new native race option (like in the code above) or just another entry to the internal array (like you mentioned).

 

I chose methods over arrays because recompiling a script with another method call from within an existing method is completely safe and can be updated just by overwriting the old mod version whereas arrays require some updating mechanism since they are stored in the saves.

 

So knowing that, you can reliably map the native racial entries to whichever structures you want. 99.99% of the work needs to be done only once - for races from base game and game DLCs.

Honestly what I'll do is just leave the current tracking methods in place, but add a secondary check for the races I want to group... which are really only dogs and Gen 2 synths anyway. No need to make entries for every race.

 

Meanwhile I'll ponder whether the DLC races are worth any extra effort.  The only ones I know of with animations are from Far Harbor, and those creatures are sufficiently different that I wouldn't group them with vanilla creatures anyway.

Link to comment

Version 1.15 is up!

-The three dog races (Dogmeat, RaiderDog, and ViciousDog) will now be tracked as a single race type. Gen 2 Synths and Valentine will also be tracked as a single race type. A clean save is not necessary.  However, XP decay for the above races will restart if an existing save is updated.

 

Hopefully that's the last major change and I can slow down the pace of updates a bit.

Link to comment

After playing with the previous version for a bit longer, I noticed many instances where observers from AAF Spectators were not being counted accurately.  So here's a fix.

 

Version 1.16 is up!

-Greatly improve AAF Spectators listening function. Now it will periodically check for new observers as long as the player animation is in progress. This allows time for distant walkers to arrive.

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