Jump to content

SexLab Expressions - Submit MFG Presets


Recommended Posts

I went ahead and experimented with these.  Using all of shinji72's female pain and adding the following:

female PAIN Phase 5:

  • Expression 9 100
  • Modifier 0 100
  • Modifier 1 100
  • Modifier 2 100
  • Modifier 3 100
  • Modifier 4 100
  • Modifier 5 100
  • Modifier 6 50
  • Modifier 7 50
  • Modifier 11 100
  • Modifier 12 30
  • Modifier 13 40
  • phoneme 0 30
  • phoneme 2 100
  • phoneme 5 40
  • phoneme 13 20
  • Phoneme 15 40

This seemed to work pretty well actually, especially for my purposes.

I then wanted to see how using my system above the expression would change through the phases.  The hoped outcome would be that it would change from pain to pleasure with rising intensity, and that the pain and pleasure aspects would never be lost. 

 

Plugging in each of these numbers for the phases provided the exact sort of result I was looking for.

 

However, I didn't like the way it scaled.  The extremes of values didn't produce the bias I was looking for.  So I changes the equation:
Enjoyment = 5 + ((9-Purity)*Stage) + (Proficiency*Stage)

This produces a number between 10 and 90 which gives a stronger pull on either side than my original formulation.

Link to comment

At the risk of complicating things I had a thought.

 

What if the expression was tied to the level of enjoyment being received.

For the sake of argument we'll define enjoyment as:

  purity_enjoyment = 50 - (6-stage)*Purity

  Proficiency_enjoyment =  (stage)*Proficiency

 

Divided by 2 if they're sexual orientation is not compatible.

 

For example if a character is having sex, and the purity is 5, and the proficiency is 3, the stages would produce this much enjoyment:

Stage 1:

  25 from imPurity + 3 from Proficiency = 28

Stage 2:

  30 from imPurity + 6 from Proficiency = 36

Stage 3:

  35 from imPurity + 9 from Proficiency = 44

Stage 4:

  40 from imPurity + 12 from Proficiency = 52

Stage 5:

  45 from imPurity + 15 from Proficiency = 60

 

 

Then let's then define a "Pure Pleasure" Face.

 

Then the face would be the weighted average between "Pure Pleasure" and the 'base act'.

 

Suppose we defined Pure Pleasure as:

  • expression 2 100
  • phoneme 1 100
  • phoneme 11 60
  • modifier 6 100
  • modifier 7 100
  • modifier 11 100

And we chose 'Pain' as a base for Victim (cribbing off shinji72):

  • Expression 9 100
  • Modifier 2 100
  • Modifier 3 100
  • Modifier 4 100
  • Modifier 5 100
  • Modifier 11 90
  • Phoneme 0 100
  • Phoneme 2 100
  • Phoneme 11 40

Out Stage 3 result would be weighted 56% pain and 44% pleasure, giving us something like:

  • Expression 9 56 (pick the highest base)
  • modifier 2 56
  • modifier 3 56
  • modifier 4 56
  • modifier 5 56
  • modifier 6 44
  • modifier 7 44
  • modifier 11 80
  • phoneme 0 56
  • phoneme 1 44
  • phoneme 2 56
  • phoneme 11 49

 

This would make the pleasure being received so far as the facial expression dynamic.  One defines a base emotion for various acts at stages and then adjusts them toward pleasure.  Assuming that consensual vanilla acts would produce 'bored' which is going to be mostly neutral, that should work quite well.

 

 

I like the idea, my main concern though would be how "good" some of the mixes would end up looking as they progress, and what to do with NPC/NPC scenes as purity and proficiency levels are only available to the player, so npc's would need to fudge the numbers or rely on randomness to some degree.

Link to comment

 

I like the idea, my main concern though would be how "good" some of the mixes would end up looking as they progress, and what to do with NPC/NPC scenes as purity and proficiency levels are only available to the player, so npc's would need to fudge the numbers or rely on randomness to some degree.

 

 

Yeah, unfortunately without actually writing a script with various values to test it, I can't tell either.  I tested some by hand, and those seemed to work well, but that doesn't mean it always would.

 

For NPC/NPC, you could just double the Purity values (which if they can't be found on NPC's, you could use Morality as a proxy maybe?)... Basically assume that a less pure person would also have a higher proficiency.  It also might be worthwhile to add a little randomness to the original formulation anyway...

Link to comment

 

 

I like the idea, my main concern though would be how "good" some of the mixes would end up looking as they progress, and what to do with NPC/NPC scenes as purity and proficiency levels are only available to the player, so npc's would need to fudge the numbers or rely on randomness to some degree.

 

 

Yeah, unfortunately without actually writing a script with various values to test it, I can't tell either.  I tested some by hand, and those seemed to work well, but that doesn't mean it always would.

 

For NPC/NPC, you could just double the Purity values (which if they can't be found on NPC's, you could use Morality as a proxy maybe?)... Basically assume that a less pure person would also have a higher proficiency.  It also might be worthwhile to add a little randomness to the original formulation anyway...

 

 

I don't know how familiar you are with Skyrim's scripting, but I put this together last night to try and test it out some:

int function GetEnjoyment()
	; // Scale higher with stage
	int BaseWeight = 5 + (5 * Stage)
	; // Weights for proficency and purity stat, ~0-7 starting
	int ProficencyWeight
	int PurityWeight = Lib.Stats.CalcLevel(Purity, 0.2)

	; // Animations involving Vaginal
	if Animation.HasTag("Vaginal")
		; // Base enjoyment for vaginal
		BaseWeight += 5
		; // Add proficency level
		ProficencyWeight += Vaginal
		; // Give more enjoyment for "pure" characters
		if Purity > 0
			PurityWeight += 2
		endIf
	endIf

	; // Animations involving Anal
	if Animation.HasTag("Anal")
		; // Base enjoyment for anal
		BaseWeight += 7
		if !IsFemale
			; // Males enjoys it more
			BaseWeight += 7
		else
			; // Females have slight discomfort, canceled out by impurity
			BaseWeight -= 2
		endIf
		; // Add proficency level
		ProficencyWeight += Anal
		; // Impure characters enjoy it more
		if Purity > 0
			PurityWeight -= 2
		else
			PurityWeight += 2
		endIf
	endIf

	; // Animations involving Oral
	if Animation.HasTag("Oral")
		; // Base enjoyment for oral
		BaseWeight += 7
		if !IsFemale
			; // Males enjoys it more
			BaseWeight += 5
		endIf
		; // Add proficency level
		ProficencyWeight += Oral

		; // Impure characters enjoy it more
		if Purity > 0
			PurityWeight -= 1
		else
			PurityWeight += 1
		endIf
	endIf

	; // Animations considered "dirty"
	if Animation.HasTag("Dirty")
		; // Pure characters don't like it
		if Purity > 0
			PurityWeight -= 3
		; // Impure characters do
		else
			PurityWeight += 3
		endIf
	endIf

	; // Calculate enjoyment
	int Enjoyment = BaseWeight + ((9 + PurityWeight) * Stage) + (ProficencyWeight * Stage)
	; // Cut in half if they are victim in animation
	if IsVictim
		Enjoyment = Enjoyment / 2
	endIf

	return Enjoyment
endFunction

It attempts to weight their enjoyment based on specific animation's, giving weights to different animation types for different genders (The male position enjoying an oral animation more than the female position for example), and weighing it differently based on the actors given proficiency and purity stats.

 

If a scene has the player, it uses the players stats for purity and proficiency, if the scene doesn't have the player, the NPC will generate and save a random proficiency level from 0 to 5 and a purity from -5 to 5 at the start of the scene.

 

It results in okay numbers, though proficiency doesn't weigh into the final number as much as I'd like. I haven't plugged it into an expression yet, nor figured out a good way of mixing in the pained expression.

Link to comment

 

 

int function GetEnjoyment()
	; // Scale higher with stage //+ (5 * Stage) is unnecessary if we do it at the bottom
        ; // So Baseweight should range from ~1-6 ?
	int BaseWeight = 3 
	; // Weights for proficency and purity stat, ~0-7 starting
	int ProficencyWeight
        ; // Is this also ~0-7?
	int PurityWeight = Lib.Stats.CalcLevel(Purity, 0.2)

	; // Animations involving Vaginal
	if Animation.HasTag("Vaginal")
		; // Base enjoyment for vaginal // This shouldn't be lower than the others
		// BaseWeight += 5 In fact let's get rid of it
                if IsFemale
                  ; // Females enjoys it more
                  BaseWeight += 3
                endIf
		; // Add proficency level
		ProficencyWeight += Vaginal
		; // Give more enjoyment for "pure" characters 
                ; // Why would Pure characters enjoy sex more?  Maybe ifMarried +=2 else -=1?
		if Purity > 0
			PurityWeight += 2
		endIf
	endIf

	; // Animations involving Anal
	if Animation.HasTag("Anal")
		; // Base enjoyment for anal
		// BaseWeight += 7
		if !IsFemale
			; // Males enjoys it more
			BaseWeight += 2
		else
			; // Females have slight discomfort, canceled out by impurity
			BaseWeight -= 1
		endIf
		; // Add proficency level
		ProficencyWeight += Anal
		; // Impure characters enjoy it more
		if Purity > 0
			PurityWeight -= 2
		else
			PurityWeight += 2
		endIf
	endIf

	; // Animations involving Oral
	if Animation.HasTag("Oral")
		; // Base enjoyment for oral
		// BaseWeight += 7
		if !IsFemale
			; // Males enjoys it more
			BaseWeight += 2
		endIf
		; // Add proficency level
		ProficencyWeight += Oral

		; // Impure characters enjoy it more
		if Purity > 0
			PurityWeight -= 1
		else
			PurityWeight += 1
		endIf
	endIf

	; // Animations considered "dirty"
	if Animation.HasTag("Dirty")
		; // Pure characters don't like it
		if Purity > 0
			PurityWeight -= 3
		; // Impure characters do
		else
			PurityWeight += 3
		endIf
	endIf

	; // Calculate enjoyment (Baseweight get scaled by stage at the top)
        ; // However this is calculated it needs to range between (0 an 20)*Stage
	int Enjoyment = (BaseWeight + PurityWeight + ProficencyWeight) * Stage
	; // Cut in half if they are victim in animation
	if IsVictim
		Enjoyment = Enjoyment / 2
	endIf

	return Enjoyment
endFunction

It attempts to weight their enjoyment based on specific animation's, giving weights to different animation types for different genders (The male position enjoying an oral animation more than the female position for example), and weighing it differently based on the actors given proficiency and purity stats.

 

If a scene has the player, it uses the players stats for purity and proficiency, if the scene doesn't have the player, the NPC will generate and save a random proficiency level from 0 to 5 and a purity from -5 to 5 at the start of the scene.

 

It results in okay numbers, though proficiency doesn't weigh into the final number as much as I'd like. I haven't plugged it into an expression yet, nor figured out a good way of mixing in the pained expression.

 

 

I like this, though I put come comments into your code where I thought it could be improved.  

It seemed a little Male-centric, so I adjusted that some, and I think the way I laid it out is simpler.  Though I did want to clarify one thing.

 

BaseWeight + PurityWeight + ProficencyWeight has to range from 0 to 20.  (since it's going to be multiplied by 1 to 5).

That means to bias in favor of each of these you need to change that components range.  A balances approach would be to have:

0 < BaseWeight < 6

0 < PurityWeight < 7

0 < ProficencyWeight < 7

 

However if you wanted to focus on Proficiency more you could do:

0 < BaseWeight < 4

0 < PurityWeight < 4

0 < ProficencyWeight < 12

 

This might be the most fun:

0 < BaseWeight < 3

0 < PurityWeight < 7

0 < ProficencyWeight < 10

 

Also, it seems like the Base Emotion are roughly as follows:

Masturbation -> Shy

Vaginal Sex -> Bored

Aggressor Sex -> Angry

Victim Sex -> Scared

Anal Sex Giving -> ?

Anal Sex Receiving -> Pain

Oral Sex Giving -> Bored

Oral Sex Receiving (male) -> Bored

Oral Sex Receiving (Female) -> Shy? or Bored

 

I'm going to checkout the development branch and see if I can play with this a little.

 

 

Link to comment

Also, for NPC's:

Purity = (3*Morality) (assuming a 0-9 scale)
Proficency = (Speech / 12) (assuming a 0-9 scale)

Or Proficiency may be better as:
Proficency = ((Speech - 20)/13)+Morality

 

and Purity might be better as:
Purity = Morality+(4-Confidence)

Link to comment

Okay, so I spent a whole lot of time going through the script piece by piece.

; // Returns a number between 0 and 100
Actor Property PlayerREF Auto

; // I don't know which 'actor' to choose for NPC
int function GetEnjoyment()
	int BaseWeight = 9 ; // 6 to 12
	int SpeechWeight = Actor.GetAV('Speech') / 25 ; // 0 to 4
	
	if Actor === PlayerREF
	    int PurityWeight = GetPlayerPurityLevel() ; // -6 to +6
        int ProficencyWeight ; 0 to 6 
	else ; // If it's an NPC infer the Purity and Proficiency
	    int PurityWeight =  4-(Morality+(4-Actor.GetAV('Confidence')))*1.5
		int ProficencyWeight = ((Actor.GetAV('Speech') - 20)/13)+ABS(PurityWeight)
	endIf
	
	; // Easy way of assigning bonuses
	if PurityWeight > 0
	    PuritySign = 1
    else
		PuritySign = -1
	endIf

	; // Masturbation needs to be accounted for as well
    if Animation.HasTag("Masturbate")
		ProficencyWeight += PurityWeight*PuritySign
        BaseWeight = 12
    endIf
	
	; // Vaginal is the preferred choice for females, and is considered 'pure'
	if Animation.HasTag("Vaginal")
        if IsFemale
            BaseWeight += 2
        endIf
		ProficencyWeight += Vaginal
        BaseWeight += PuritySign
    endIf

	; // Anal is slightly uncomfortable for the receptive partner
	if Animation.HasTag("Anal")
		if !IsFemale
			BaseWeight += 1
		else
			BaseWeight -= 1
		endIf
		ProficencyWeight += Anal
        BaseWeight -= PuritySign*2
	endIf

	; // Oral is not especially great for the giving partner
	if Animation.HasTag("Oral")
		if !IsFemale
			BaseWeight += 1
		endIf
		ProficencyWeight += Oral
        BaseWeight -= PuritySign
	endIf

    ; // Dirty preference moves the negative to positive and vice versa
	if Animation.HasTag("Dirty")
        PurityWeight *= -1
    elseIf !Animation.HasTag("Loving")
        PurityWeight *= PuritySign
    endIf

	; // BaseWeight + Purity = 6 to 18, Proficincy is thus multiplied to keep in line, Speech gives a small bonus
	; // Together they come to 0 to 40.  * .5, 1, 1.5, 2, 2.5 for the various stages giving a range of 0 to 100
	int Enjoyment = ((BaseWeight + PurityWeight) + ProficencyWeight*3)+SpeechWeight) * (Stage/2)
	
	; // Sexual Assault isn't fun for the victim
	if IsVictim
		Enjoyment = Enjoyment / 2
	endIf
	
	; // if SexualOrientationMismatch
	; //     Enjoyment = Enjoyment / 2
	; // endif
	
endFunction

I'm a programmer, but I'm still new to Papyrus, so you'll have to take that as pseudo-code.  However it should be mostly set.
 

Link to comment

Setting Expression based on current enjoyment


; // Sets an expression based on current enjoyment
int function SetExpressionBasedOnEnjoyment()
	int Enjoyment = GetEnjoyment() ; // .0 to 1.00
	float Enjoymodifer = Enjoyment / 100
	float Unenjoyment = 1 - Enjoyment
	
	while i < 8 ; // Loop through all possible expressions
		BaseExpression = GetExpression('actor', i)-Enjoyment ; // Magical Function that returns the value of an expression
		if BaseExpression > 50:
			ActorRef.SetExpressionOverride(i, BaseExpression)
		else
			ActorRef.SetExpressionOverride(2, Enjoyment)
		endif		
	endwhile
	
	while i < 16  ; // Here I make up a function GetPhoneme
		if i == 1
			MfgConsoleFunc.SetPhonemeModifier(ActorRef, Phoneme, 1, GetPhoneme(1)*(Unenjoyment)+(100+Enjoymodifier))
		elseif i == 11
			MfgConsoleFunc.SetPhonemeModifier(ActorRef, Phoneme, 11, GetPhoneme(11)*(Unenjoyment)+(60+Enjoymodifier))
		else
			MfgConsoleFunc.SetPhonemeModifier(ActorRef, Phoneme, i, GetPhoneme(i)*(Unenjoyment))
		endif
	endwhile ; // This would all be better if the "purePleasure" was a referencable object, but I couldn't figure that out...

	while i < 14  ; // Here I make up a function GetModifier
		if i == 6
			MfgConsoleFunc.SetPhonemeModifier(ActorRef, Phoneme, 6, GetModifier(6)*(Unenjoyment)+(100+Enjoymodifier))
		elseif i == 7
			MfgConsoleFunc.SetPhonemeModifier(ActorRef, Phoneme, 7, GetModifier(7)*(Unenjoyment)+(100+Enjoymodifier))
		elseif i == 11
			MfgConsoleFunc.SetPhonemeModifier(ActorRef, Phoneme, 11, GetModifier(11)*(Unenjoyment)+(100+Enjoymodifier))
		else
			MfgConsoleFunc.SetPhonemeModifier(ActorRef, Phoneme, i, GetModifier(i)*(Unenjoyment))
		endif
	endwhile ; // This would all be better if the "purePleasure" was a referencable object, but I couldn't figure that out...
	
endFunction

 

Here I, again, couldn't figure out how to actually reference another Expression Preset, or the Current actors MFG values.  However if you can reference those a function sort of like this would work.  Even better if the purePleasure preset could be referenced, you could check for membership in that, and turn these three functions into one liners.

Link to comment

So, I apparently downloaded the wrong branch because it's missing all the expression stuff...

Even looking at your changelog I'm not positive I understand how I'd hook it in.  

 

You have to checkout the development branch after cloning the repo, it clones the master branch by default, which is the current official release.

 

The branch doesn't have any of this enjoyment stuff yet though, as I'm still trying to piece most of it together in a cohesive manner. I'm working that now but i'm god awful at trying to do anything remotely algorithm related. You seem to have some grasp on that though, so if you have time right now and are up for helping me figure out a solution, PM me your Steam or Skype ID and we can hash out details of it easier that way.

Link to comment

It shouldn't be capped at 100 in my opinion, it should aim for 100 but be able to scale over it. Otherwise the only way an actor will be able to achieve a high enjoyment is if they have a maxed out applicable proficiency and purity, which makes it more or less unattainable for most.

 

The higher their stats the easier it should be to reach ~85+, and likewise low stats should make them unlikely to reach ~85+ unless under the most ideal of tagged animations and on the final stage.

 

Using your suggested formula/script as a guide I'm fairly certain I've reached a result I'm satisfied enough with.

int function GetEnjoyment()
	; // Init weights
	int BaseWeight
	int ProficencyWeight
	int PurityWeight
	int ActorCount = Controller.ActorCount
	; // Appropiate bonus = 1.multiplier -- leaving addition intact
	; // Inappropiate bonus = 0 -- canceling out the addition
	int FemaleBonus = (IsFemale as int)
	int MaleBonus = ((!IsFemale) as int)
	int PureBonus = (IsPure as int)
	int ImpureBonus = ((!IsPure) as int)
	; // Scaling purity modifier
	int PurityMod = 1 + (Purity / 2)
	; // Adjust bonuses based on type, gender, and purity
	if Animation.HasTag("Vaginal")
		ProficencyWeight += Vaginal
		BaseWeight   += FemaleBonus  * 2
		BaseWeight   += MaleBonus    * 3
	endIf
	if Animation.HasTag("Anal")
		ProficencyWeight += Anal
		BaseWeight   += FemaleBonus  * -1
		BaseWeight   += MaleBonus    * 3
		PurityWeight += PureBonus    * -PurityMod
		PurityWeight += ImpureBonus  * PurityMod
	endIf
	if Animation.HasTag("Oral")
		ProficencyWeight += Oral
		BaseWeight   += FemaleBonus  * -1
		BaseWeight   += MaleBonus    * 3
		PurityWeight += PureBonus    * -PurityMod
		PurityWeight += ImpureBonus  * PurityMod
	endIf
	if Animation.HasTag("Dirty")
		PurityWeight += PureBonus    * (-PurityMod - 1)
		PurityWeight += ImpureBonus  * PurityMod
	endIf
	if Animation.HasTag("Aggressive")
		PurityWeight += PureBonus    * (-PurityMod - 3)
	endIf
	if Animation.HasTag("Loving")
		PurityWeight += PureBonus    * (PurityMod + 1)
	endIf
	if Animation.IsCreature
		PurityWeight += PureBonus    * (-PurityMod - 6)
	endIf
	if ActorCount > 2
		PurityWeight += PureBonus    * ((-PurityMod - 3) * (ActorCount - 2))
		PurityWeight += ImpureBonus  * ((PurityMod + 2) * (ActorCount - 2))
	endIf
	if ActorCount == 1
		ProficencyWeight += Purity
		PurityWeight += ImpureBonus  * (PurityMod + (ActorRef.GetActorValue("Confidence") as int))
	endIf
	; // Ramp up with stage and time spent, maxout time bonus at 2.5 minutes (8 seconds * 19 intervals = 152 seconds == ~2.5 minutes)
	BaseWeight += (4 * Stage) + Clamp(((Controller.TotalTime / 8.0) as int), 19)

	; // Calculate root enjoyment of the animation, give multipler by progress through the animation stages (1/5 stage = 1.20 multiplier)
	Enjoyment = (((BaseWeight + PurityWeight + (ProficencyWeight * 3)) as float) * ((Stage as float / Animation.StageCount as float) + 1.0)) as int
	; // Cap victim at 50 after halving
	if IsVictim
		Enjoyment = Clamp((Enjoyment / 2), 50)
	endIf
	; // Return raw enjoyment for modder use, if 100+ expression will clamp value
	return Enjoyment
endFunction

Testing on a couple different pairs of npcs they progressed fairly evenly through the stages, starting small and ending between 60 and 110.

 

Also put together these functions for calculating a NPC's proficiency and purity levels. I'm less sold on them right now, but they were "serviceable" in my testing.

int function CalcLevel(float total, float curve = 0.65)
	return Math.Sqrt(((Math.Abs(total) + 1.0) / 2.0) * Math.Abs(curve)) as int
endFunction

float function GetActorPurityStat(actor ActorRef)
	; // Get relevant-ish AI data
	int Aggression = ActorRef.GetActorValue("Aggression") as int
	int Morality = ActorRef.GetActorValue("Morality") as int
	int Assistance = ActorRef.GetActorValue("Assistance") as int
	; // Init base purity based on level and how aggressive they are
	float purity = ((ActorRef.GetLevel() / 2 ) * 9)
	float seed = ((((Aggression+1) as float) / 5.0) * 0.40)
	; // Actor doesn't care about crime, make more impure
	if Morality == 0
		seed += 0.10
	; // Actor refuses crime
	elseIf Morality == 3
		seed += 0.07
	endIf
	; // Actor is a morale pacifist, make more pure
	if Aggression == 0 && Morality != 0
		seed += 0.06
	; // Non aggessive, add small bit
	elseIf Aggression == 0
		seed += 0.02
	; // Aggressive only towards enemies
	elseIf Aggression == 1
		seed += 0.01
	endIf
	; // 0 = Actor won't help anybody, make more impure
	; // 2 = Actor helps friends+allies, make more pure
	if Assistance != 1
		seed += 0.05
	endIf
	; // Actor is immorale but helps friends+allies, make more pure
	if Assistance == 2 && Morality == 0
		seed -= 0.04
	endIf
	; // Generate largish purity with seed and base purity
	purity += ((purity * seed) * 1.75) * 1.5
	; // Sign purity to make impure, based on "bad" traits
	return sslUtility.SignFloat((Morality == 0 || Aggression >= 2 || (Assistance == 0 && Morality == 3)), purity)
endFunction

int function GetActorPurityLevel(actor ActorRef)
	return CalcLevel(GetActorPurityStat(ActorRef), 0.2)
endFunction

int function GetActorProficencyLevel(actor ActorRef)
	int xp = (ActorRef.GetLevel() * 2) + ((((ActorRef.GetActorValue("Speechcraft")*ActorRef.GetActorValue("Confidence")) + 1) / 2.0) as int)
	return CalcLevel(xp, 0.65)
endFunction

Right now proficiency just generates a generic stat that is applied to all the types (Vaginal, Anal, & Oral) which is probably good enough, I don't see much need to expand it to different types, the main purpose is just to get a consistent number out on an NPC rather than using random numbers.

 

Other mods may be able to make use of the stats on NPCs as well though, so I may expand it out to include separate types.

 

Now just to figure out how to use the number in conjunction with the expressions

 

Link to comment
Guest kimbale

Ooh, i like what you do with the scripting.

 

But i have some issues with it:

 

1) If the scripts would try to mix different presets, there could be severe fuckups as these presets all use a base mfg expression. These don't mix, you just have either one. And applying the modifiers to another base expression yields bad expressions overall.

 

2) Shifting from one preset to the other gives a nice effect, i'd even have them shift back and forth if possible at big increments. I do that in my game already and it works great as reacting to a position shift or anything like that. Having it progress slowly takes out those "twitches" i like....

 

In the end: If all this would be configurable i'd love to have it, otherwise i'd stick to simple sex stage -> mfg preset.

Link to comment

Those look great.  The NPC stats are serviceable, so that should work.

 

MCM:


; OID
bool dynamicOID_B ; // Enable Dynamic Expressions
int basefemaleOID_S ; // _S for slider
int basemaleOID_S ; _S for slider
int vaginalfemaleOID_S ; // _S for slider
int vaginalmaleOID_S ; _S for slider
int analfemaleOID_S ; // _S for slider
int analmaleOID_S ; _S for slider
int oralfemaleOID_S ; // _S for slider
int oralmaleOID_S ; _S for slider

; State
bool dynamic = true
int basefemale = 1 ; // Base Female Sexual Enjoyment
int basemale = 1 ; // Base Male Sexual Enjoyment
int vaginalfemale = 2 ; // Vaginal Female Sexual Enjoyment
int vaginalmale = 3 ; Vaginal Female Sexual Enjoyment
int analfemale = -1 ; // Anal Female Sexual Enjoyment
int analmale = 3 ; Anal Female Sexual Enjoyment
int oralfemale = -1 ; // Oral Female Sexual Enjoyment
int oralmaleS = 3 ; Oral Female Sexual Enjoyment


event OnPageReset(string page)
	AddHeaderOption("Dynamic Expressions")
	dynamicOID_B = AddToggleOption("Enable Dynamic Expressions", toggleState)
	basefemaleOID_S = AddSliderOption("Female Base Enjoyment", frequency, "Base for Receptive Partner")
	basemaleOID_S = AddSliderOption("Male Base Enjoyment", frequency, "")
	vaginalfemaleOID_S = AddSliderOption("Female Vaginal Enjoyment", frequency, "Vaginal Receptive")
	vaginalmaleOID_S = AddSliderOption("Male Vaginal Enjoyment", frequency, "")
	analfemaleOID_S = AddSliderOption("Female Anal Enjoyment", frequency, "Anal Receptive")
	analmaleOID_S = AddSliderOption("Male Anal Enjoyment", frequency, "")
	oralfemaleOID_S = AddSliderOption("Female Oral Enjoyment", frequency, "Oral Receptive")
	oralmaleOID_S = AddSliderOption("Male Oral Enjoyment", frequency, "")
endEvent




event OnOptionSelect(int option)
	if (option == dynamicOID_
		toggleState = !toggleState
		SetToggleOptionValue(dynamicOID_B, toggleState)
	endIf
endEvent

event
	if (option == basefemaleOID_S)
		SetSliderDialogStartValue(basefemale)
		SetSliderDialogDefaultValue(1)
		SetSliderDialogRange(0, 5)
		SetSliderDialogInterval(1)
	elseIf (option == basemaleOID_S)
		SetSliderDialogStartValue(basemale)
		SetSliderDialogDefaultValue(1)
		SetSliderDialogRange(0, 5)
		SetSliderDialogInterval(1)
	elseIf (option == basefemaleOID_S)
		SetSliderDialogStartValue(vaginalfemaleOID_S)
		SetSliderDialogDefaultValue(2)
		SetSliderDialogRange(-3, 3)
		SetSliderDialogInterval(1)
	elseIf (option == basefemaleOID_S)
		SetSliderDialogStartValue(vaginalmaleOID_S)
		SetSliderDialogDefaultValue(3)
		SetSliderDialogRange(-3, 3)
		SetSliderDialogInterval(1)
	elseIf (option == basefemaleOID_S)
		SetSliderDialogStartValue(analfemaleOID_S)
		SetSliderDialogDefaultValue(-1)
		SetSliderDialogRange(-3, 3)
		SetSliderDialogInterval(1)
	elseIf (option == basefemaleOID_S)
		SetSliderDialogStartValue(analmaleOID_S)
		SetSliderDialogDefaultValue(3)
		SetSliderDialogRange(-3, 3)
		SetSliderDialogInterval(1)
	elseIf (option == basefemaleOID_S)
		SetSliderDialogStartValue(oralfemaleOID_S)
		SetSliderDialogDefaultValue(-1)
		SetSliderDialogRange(-3, 3)
		SetSliderDialogInterval(1)
	elseIf (option == basefemaleOID_S)
		SetSliderDialogStartValue(oralmaleOID_S)
		SetSliderDialogDefaultValue(3)
		SetSliderDialogRange(-3, 3)
		SetSliderDialogInterval(1)
	endIf
endEvent


event OnOptionSliderAccept(int option, float value)
	if (option == dynamicOID_
		dynamic = value
		SetSliderOptionValue(dynamicOID_B, dynamic, "")
	elseIf (option == basefemaleOID_S)
		basefemale = value
		SetSliderOptionValue(basefemaleOID_S, basefemale, "")
	elseIf (option == basemaleOID_S)
		basemale = value
		SetSliderOptionValue(basemaleOID_S, basemale, "")
	elseIf (option == vaginalfemaleOID_S)
		vaginalfemale = value
		SetSliderOptionValue(vaginalfemaleOID_S, vaginalfemale, "")
	elseIf (option == vaginalmaleOID_S)
		vaginalmale = value
		SetSliderOptionValue(vaginalmalenOID_S, vaginalmale, "")
	elseIf (option == analfemaleOID_S)
		analfemale = value
		SetSliderOptionValue(analfemaleOID_S, analfemale, "")
	elseIf (option == analmalefemaleOID_S)
		analmale = value
		SetSliderOptionValue(analmaleOID_S, analmale, "")
	elseIf (option == oralfemaleOID_S)
		oralfemale = value
		SetSliderOptionValue(oralfemaleOID_S, oralfemale, "")
	elseIf (option == oralmaleOID_S)
		oralmale = value
		SetSliderOptionValue(oralmaleOID_S, oralmale, "")
	endIf
endEvent

Which using your code would produce

int function GetEnjoyment()
	if !dynamic
		return 0 ; // Also need to make vanilla sex be pleasurable base instead of neutral
	endIf
	
	; // Init weights
	int BaseWeight
	int ProficencyWeight
	int PurityWeight
	int ActorCount = Controller.ActorCount
	; // Appropiate bonus = 1.multiplier -- leaving addition intact
	; // Inappropiate bonus = 0 -- canceling out the addition
	int FemaleBonus = (IsFemale as int) * basefemale
	int MaleBonus = ((!IsFemale) as int) * basemale
	int PureBonus = (IsPure as int)
	int ImpureBonus = ((!IsPure) as int)
	; // Scaling purity modifier
	int PurityMod = 1 + (Purity / 2)
	; // Adjust bonuses based on type, gender, and purity
	if Animation.HasTag("Vaginal")
		ProficencyWeight += Vaginal
		BaseWeight   += FemaleBonus  * vaginalfemale
		BaseWeight   += MaleBonus    * vaginalmale
	endIf
	if Animation.HasTag("Anal")
		ProficencyWeight += Anal
		BaseWeight   += FemaleBonus  * analfemale
		BaseWeight   += MaleBonus    * analmale
		PurityWeight += PureBonus    * -PurityMod
		PurityWeight += ImpureBonus  * PurityMod
	endIf
	if Animation.HasTag("Oral")
		ProficencyWeight += Oral
		BaseWeight   += FemaleBonus  * oralfemale
		BaseWeight   += MaleBonus    * oralmale
		PurityWeight += PureBonus    * -PurityMod
		PurityWeight += ImpureBonus  * PurityMod
	endIf
	if Animation.HasTag("Dirty")
		PurityWeight += PureBonus    * (-PurityMod - 1)
		PurityWeight += ImpureBonus  * PurityMod
	endIf
	if Animation.HasTag("Aggressive")
		PurityWeight += PureBonus    * (-PurityMod - 3)
	endIf
	if Animation.HasTag("Loving")
		PurityWeight += PureBonus    * (PurityMod + 1)
	endIf
	if Animation.IsCreature
		PurityWeight += PureBonus    * (-PurityMod - 6)
	endIf
	if ActorCount > 2
		PurityWeight += PureBonus    * ((-PurityMod - 3) * (ActorCount - 2))
		PurityWeight += ImpureBonus  * ((PurityMod + 2) * (ActorCount - 2))
	endIf
	if ActorCount == 1
		ProficencyWeight += Purity
		PurityWeight += ImpureBonus  * (PurityMod + (ActorRef.GetActorValue("Confidence") as int))
	endIf
	; // Ramp up with stage and time spent, maxout time bonus at 2.5 minutes (8 seconds * 19 intervals = 152 seconds == ~2.5 minutes)
	BaseWeight += (4 * Stage) + Clamp(((Controller.TotalTime / 8.0) as int), 19)

	; // Calculate root enjoyment of the animation, give multipler by progress through the animation stages (1/5 stage = 1.20 multiplier)
	Enjoyment = (((BaseWeight + PurityWeight + (ProficencyWeight * 3)) as float) * ((Stage as float / Animation.StageCount as float) + 1.0)) as int
	; // Cap victim at 50 after halving
	if IsVictim
		Enjoyment = Clamp((Enjoyment / 2), 50) ; // Should probably have this be configurable too...
	endIf
	; // Return raw enjoyment for modder use, if 100+ expression will clamp value
	return Enjoyment
endFunction

You'll have to play around with the allowable ranges, I'm not quite sure what is reasonable.

 

 

That MCM should allow people to have their own male/female enjoyment equations and solve the fact that some people may not want it at all.

 

Though, as far as your objection kimbale, I wouldn't have bothered if experiments by hand hadn't produced reasonable results.

"Twitchiness" could possibly be put in, but it seems like feature creep to think about it right now... ;)

Link to comment

One more thing.

Most of this doesn't change very often, so can be calculated once at the start, and then modified each stage:


; // This needs to be run when the scene starts
int function GetStartEnjoyment()
	if !dynamic
		return 0 ; // Also need to make vanilla sex be pleasurable base instead of neutral
	endIf
	
	; // Init weights
	int BaseWeight
	int ProficencyWeight
	int PurityWeight
	int ActorCount = Controller.ActorCount
	; // Appropiate bonus = 1.multiplier -- leaving addition intact
	; // Inappropiate bonus = 0 -- canceling out the addition
	int FemaleBonus = (IsFemale as int) * basefemale
	int MaleBonus = ((!IsFemale) as int) * basemale
	int PureBonus = (IsPure as int)
	int ImpureBonus = ((!IsPure) as int)
	; // Scaling purity modifier
	int PurityMod = 1 + (Purity / 2)
	; // Adjust bonuses based on type, gender, and purity
	if Animation.HasTag("Vaginal")
		ProficencyWeight += Vaginal
		BaseWeight   += FemaleBonus  * vaginalfemale
		BaseWeight   += MaleBonus    * vaginalmale
	endIf
	if Animation.HasTag("Anal")
		ProficencyWeight += Anal
		BaseWeight   += FemaleBonus  * analfemale
		BaseWeight   += MaleBonus    * analmale
		PurityWeight += PureBonus    * -PurityMod
		PurityWeight += ImpureBonus  * PurityMod
	endIf
	if Animation.HasTag("Oral")
		ProficencyWeight += Oral
		BaseWeight   += FemaleBonus  * oralfemale
		BaseWeight   += MaleBonus    * oralmale
		PurityWeight += PureBonus    * -PurityMod
		PurityWeight += ImpureBonus  * PurityMod
	endIf
	if Animation.HasTag("Dirty")
		PurityWeight += PureBonus    * (-PurityMod - 1)
		PurityWeight += ImpureBonus  * PurityMod
	endIf
	if Animation.HasTag("Aggressive")
		PurityWeight += PureBonus    * (-PurityMod - 3)
	endIf
	if Animation.HasTag("Loving")
		PurityWeight += PureBonus    * (PurityMod + 1)
	endIf
	if Animation.IsCreature
		PurityWeight += PureBonus    * (-PurityMod - 6)
	endIf
	if ActorCount > 2
		PurityWeight += PureBonus    * ((-PurityMod - 3) * (ActorCount - 2))
		PurityWeight += ImpureBonus  * ((PurityMod + 2) * (ActorCount - 2))
	endIf
	if ActorCount == 1
		ProficencyWeight += Purity
		PurityWeight += ImpureBonus  * (PurityMod + (ActorRef.GetActorValue("Confidence") as int))
	endIf

	float StartingEnjoyment = (((BaseWeight + PurityWeight + (ProficencyWeight * 3)) as float)
endFunction
	
; // This needs to be undated regularly
int function GetEnjoyment()
	Enjoyment = StartingEnjoyment
	; // Ramp up with stage and time spent, maxout time bonus at 2.5 minutes (8 seconds * 19 intervals = 152 seconds == ~2.5 minutes)
	Enjoyment += (4 * Stage) + Clamp(((Controller.TotalTime / 8.0) as int), 19)

	; // Calculate root enjoyment of the animation, give multipler by progress through the animation stages (1/5 stage = 1.20 multiplier)
	Enjoyment =  Enjoyment * ((Stage as float / Animation.StageCount as float) + 1.0)) as int
	; // Cap victim at 50 after halving
	if IsVictim
		Enjoyment = Clamp((Enjoyment / 2), 50) ; // Should probably have this be configurable too...
	endIf
	; // Return raw enjoyment for modder use, if 100+ expression will clamp value
	return Enjoyment
endFunction
Link to comment

I (more or less) figured out a way to handles mixing the expressions

; // In sslBaseExpression
int[] male1 = new int[32]
int[] male2 = new int[32]
int[] male3 = new int[32]
int[] male4 = new int[32]
int[] male5 = new int[32]

int[] female1 = new int[32]
int[] female2 = new int[32]
int[] female3 = new int[32]
int[] female4 = new int[32]
int[] female5 = new int[32]

;// Such that
;// [expression, ex_val, 
;//	p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, 
;//	m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13]
;// Then

function ApplyPreset(int[] presets, actor ActorRef, bool openmouth = false)
	int i = 32
	while i
		i -= 1
		if i == 1
			ActorRef.SetExpressionOverride(presets[(i - 1)], presets[i]).
			return
		elseIf i < 17
			MfgConsoleFunc.SetPhonemeModifier(ActorRef, 'phoneme', i-2, presets[i])
		else
			MfgConsoleFunc.SetPhonemeModifier(ActorRef, 'modifier', i-17, presets[i])
		endIf
	endWhile
endFunction


int[] function PresetMixing(int[] basepreset, int[] mixingpreset, int phase, bool, isFemale, float bias)
	int[] newPreset = new int[32]
	int i = 32
	while i
		if basepreset[i] == None
			basepreset[i] = 0  ; // Papyrus allows sparse arrays...
		endIf
		if mixingpreset[i] == None
			mixingpreset[i] = 0
		endIf
		i -= 1
		if i == 1
			if (basepreset[1]*(1-bias)) > (mixingpreset[1]*bias)
				newPreset[0] = basepreset[0]
				newPreset[1] = basepreset[1]*(1-bias)
			else
				newPreset[0] = mixingpreset[0]
				newPreset[1] = mixingpreset[1]*bias
				ActorRef.SetExpressionOverride(newPreset[0], newPreset[1]) ; // I don't know whether this should be real time of cached...
			return newPreset ; // This will always happen
		elseIf i < 17
			newPreset[i] = (basepreset[i]*(1-bias))+(mixingpreset[i]*bias)
			MfgConsoleFunc.SetPhonemeModifier(ActorRef, 'phoneme', i-2, newPreset[i])
		else
			newPreset[i] = (basepreset[i]*(1-bias))+(mixingpreset[i]*bias)
			MfgConsoleFunc.SetPhonemeModifier(ActorRef, 'modifier', i-17, newPreset[i])
		endIf
	endWhile
endFunction
	

The only downside is that it means the presets will always be integer arrays of length 32, and requires re-factoring your code to use the index as the phoneme/modifier.  I think it's cleaner (and uses less memory) this way, but it means reworking code... :P

 

Link to comment

YOu can use the ECE expressions to get emotions too but I don't know if it'll be as compatible as using mfg(unless they're similar somehow, I've no idea). Anyways, ahegao pls (plz excuse the cursor)

 

 

hmt3.jpgUploaded with ImageShack.com

 

 

Excelent idea!

 

Also,you have a promissing modding,shinji72,eager to see how it will end,but the first set pictured better pain in my opnion,could you try doing something as .gifs or videos?It would be easier to give feedback,if you manage to do so.

 
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