Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions src/000-SCRIPT_OBJ/Helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -921,6 +921,33 @@ App.PR = new function() {
return this.TokenizeRating(Player, "BODY", "Penis", this.GetRating("Penis", pPercent));
};

/**
* Print how does the futa state matches current body state
* @param {App.Entity.Player} Player
* @returns {string}
*/
this.pFutaStatus = function (Player) {
const pFuta = Player.GetStatPercent("STAT", "Futa");
const hormones = Player.GetStat("STAT", "Hormones");
if ((hormones > 100)) {
const pPenis = Player.GetStatPercent("BODY", "Penis");
const dp = pFuta - pPenis;
if (dp > 90) return "You crave for a bigger penis."
if (dp > 60) return "You feel an urge to grow a bigger penis."
if (dp > 30) return "You are pretty sure a bigger penis would be a good thing to get."
if (dp > 5) return "You feel your penis could be a bit bigger."
return "You consider your penis size to be about right for you."
} else if (hormones) {
const pBust = Player.GetStatPercent("BODY", "Bust");
const db = pFuta - pBust;
if (db > 90) return "You crave for bigger tits."
if (db > 60) return "You feel an urge to grow your boobs."
if (db > 30) return "You are pretty sure bigger tits would be a good thing to get."
if (db > 5) return "You feel your bust could be a bit bigger."
return "You consider your bust size to be about right for you."
}
}

/**
* Prints out a description of the Player's height statistic.
* @param {App.Entity.Player} Player
Expand Down
16 changes: 14 additions & 2 deletions src/000-SCRIPT_OBJ/Player.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ App.Entity.PlayerState = function (){
"Fitness": 0,
"Toxicity": 0,
"Hormones": 0,
"Energy": 0
"Energy": 0,
"Futa": 0
};

this.CoreStatsXP = {
Expand All @@ -67,7 +68,8 @@ App.Entity.PlayerState = function (){
"Fitness": 0,
"Toxicity": 0,
"Hormones": 0,
"Energy": 0
"Energy": 0,
"Futa": 0,
};

this.BodyStats = {
Expand Down Expand Up @@ -2309,6 +2311,16 @@ App.Entity.Player = /** @class Player @type {Player} */ class Player {
return this.Inventory.EquippedReelItems();
}

/**
* @returns {boolean}
*/
IsFuta() {
if (this._state.CoreStats["Futa"] > 0) {
return true;
}
return false;
}

// endregion

/**
Expand Down
10 changes: 10 additions & 0 deletions src/001-SCRIPT_DATA/CLOTHES/uncatagorized_clothes.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,16 @@ App.Data.Clothes["choker"] = {
"WearEffect": [ "FEMININE_CLOTHING" ]
};

App.Data.Clothes["ancient metal collar"] = {
"Name": "ancient metal collar",
"ShortDesc": "an ancient metal collar",
"LongDesc": "An ancient collar made of metal inlaid with a few big gems of various colours.",
"Slot": "Neck", "Restrict": ["Neck"], "Color": "silver",
"Style": "LEGENDARY", "Type" : "ACCESSORY",
"WearEffect": [ "FUTA_COLLAR" ],
"InMarket" : false
};

// NIPPLES SLOT

// BRA SLOT
Expand Down
50 changes: 33 additions & 17 deletions src/001-SCRIPT_DATA/EFFECTS/effects_body_natural.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
App.Data.EffectLib.NATURAL_HEALING = {
"FUN" : /** @param {App.Entity.Player} p
@param {App.Items.Consumable} o*/
function(o, p) {
function(o, p) {
var Health = 5 + Math.ceil(p.GetStat('STAT', 'Energy') * 2) +
Math.ceil(p.GetStat('STAT', 'Fitness') / 10); // 5 + 0-20 + 0-10
var Energy = Math.floor( (p.GetStat('STAT', 'Nutrition')/25) + (p.GetStat('STAT', 'Fitness')/25)); // 1 - 8
Expand All @@ -20,19 +20,19 @@ App.Data.EffectLib.NATURAL_HEALING = {
};

// Resting healing.
App.Data.EffectLib.NATURAL_RESTING =
App.Data.EffectLib.NATURAL_RESTING =
{
"FUN" : /** @param {App.Entity.Player} p
@param {App.Items.Consumable} o*/
function(o, p) {
function(o, p) {
var Heal = Math.max(1, Math.min(Math.ceil( (p.GetStat('STAT', 'Nutrition')/20) + (p.GetStat('STAT', 'Fitness')/20)), 10)); // 1 - 10
var mod = 1 - Math.max(0, Math.min(p.GetStat('STAT', 'Toxicity')/150, 1.0)); // 0 - 1
p.AdjustStat('Health', Math.ceil(Heal * mod));
p.AdjustStat('Energy', 1);
p.AdjustStat('Toxicity', -5);
},
"VALUE" : 0,
"KNOWLEDGE" : [ "Healing+" ]
"VALUE" : 0,
"KNOWLEDGE" : [ "Healing+" ]
}
App.Data.EffectLib.NATURAL_QUEST_HOOKS = {
"FUN" : /** @param {App.Entity.Player} p */
Expand All @@ -56,7 +56,7 @@ App.Data.EffectLib.NATURAL_NUTRITION = {
p.AdjustBodyXP("Waist", nutritionXP - 150); // Get Fatter!?
setup.Notifications.AddMessage("STATUS_CHANGE", p.Day+1, "@@color:yellow;You feel as if you ate too much yesterday.@@");
}

var nutrition = p.GetStat("STAT", "Nutrition");
// Going hungry, lose some belly fat.
if (nutrition <= 40) {
Expand Down Expand Up @@ -84,18 +84,18 @@ App.Data.EffectLib.NATURAL_DETOXIFICATION = {
App.Data.EffectLib.NATURAL_TOXIC_DAMAGE = {
"FUN" : /** @param {App.Entity.Player} p
@param {App.Items.Consumable} o*/
function(o, p) {
function(o, p) {
var Tox = p.GetStat('STAT', 'Toxicity');
var dmg = Tox <= 100 ? 0 : Math.ceil(10 * (Tox/300));

if (dmg > 0) {
p.AdjustStat('Health', (dmg * -1.0));
setup.Notifications.AddMessage("STATUS_CHANGE", p.Day+1, "@@color:red;&dArr;You feel slightly sick@@... your current " +
setup.Notifications.AddMessage("STATUS_CHANGE", p.Day+1, "@@color:red;&dArr;You feel slightly sick@@... your current " +
App.PR.ColorizeString(p.GetStatPercent("STAT", "Toxicity"), "Toxicity") +
" is probably to blame.");
}
},
"VALUE" : 0,
"VALUE" : 0,
"KNOWLEDGE" : [ "Poisoned+" ]
};

Expand All @@ -108,6 +108,10 @@ App.Data.EffectLib.NATURAL_HORMONE_SHIFT = {
//Adjust physical characteristics based on hormone balance. Only shift body if there is XP related to the hormone
//shift stored in the player object.
var HormoneShift = 0;
// The "Futa" stat blocks penis, bust, and balls shrinking if their stats are lower or equal to the futa stat.
// Also, if the balls stat percent is lower than the futa one, balls do not produce hormonal shift.
// If, however, the futa stat is higher than the penis or bust stat, it results in willpower drain down to 15
const FutaPercent = p.GetStatPercent("STAT", "Futa");

if ((p.GetStat("STAT", "Hormones") > 100) && p.GetStatXP("STAT", "Hormones") > 0 ) {
HormoneShift = ( p.GetStat("STAT", "Hormones") - 100 );
Expand All @@ -116,23 +120,35 @@ App.Data.EffectLib.NATURAL_HORMONE_SHIFT = {
p.AdjustBodyXP("Lips", HormoneShift , 40);
p.AdjustBodyXP("Ass", HormoneShift , 10);
p.AdjustBodyXP("Hips", HormoneShift , 10);
p.AdjustBodyXP("Penis", (HormoneShift * -1.0) , 1);
p.AdjustBodyXP("Balls", (HormoneShift * -1.0) , 0);
const PenisPercent = p.GetStatPercent("BODY", "Penis");
if (PenisPercent > FutaPercent) {
p.AdjustBodyXP("Penis", (HormoneShift * -1.0) , 1);
} else if (FutaPercent > PenisPercent) {
p.AdjustStatXP("WillPower", FutaPercent - PenisPercent, 15);
}
if (p.GetStatPercent("BODY", "Balls") > FutaPercent) {
p.AdjustBodyXP("Balls", (HormoneShift * -1.0) , 0);
}
} else if (p.GetStat("STAT", "Hormones") < 100 && p.GetStatXP("STAT", "Hormones") < 0 ) {
HormoneShift = ( 100 - p.GetStat("STAT", "Hormones"));
HormoneShift = (100 - p.GetStat("STAT", "Hormones"));
const BustPercent = p.GetStatPercent("BODY", "Bust");
p.AdjustBodyXP("Face", (HormoneShift * -1.0), p.GetStartStat("BODY", "Face"));
p.AdjustBodyXP("Bust", (HormoneShift * -1.0), p.GetStartStat("BODY", "Bust"));
if (BustPercent > FutaPercent) {
p.AdjustBodyXP("Bust", (HormoneShift * -1.0), p.GetStartStat("BODY", "Bust"));
} else if (FutaPercent > BustPercent) {
p.AdjustStatXP("WillPower", FutaPercent - BustPercent, 15);
}
p.AdjustBodyXP("Lips", (HormoneShift * -1.0), p.GetStartStat("BODY", "Lips"));
p.AdjustBodyXP("Ass", (HormoneShift * -1.0), p.GetStartStat("BODY", "Ass"));
p.AdjustBodyXP("Hips", (HormoneShift * -1.0), p.GetStartStat("BODY", "Hips"));
p.AdjustBodyXP("Penis", HormoneShift, p.GetStartStat("BODY", "Penis"));
p.AdjustBodyXP("Balls", HormoneShift, p.GetStartStat("BODY", "Balls"));
}

// Decrease the players hormone XP relative to the size of their balls.
var hormoneXP = Math.ceil(20 * ( p.GetStat('BODY', 'Balls')/100)) * -1.0
p.AdjustStatXP('Hormones', hormoneXP);
}
if (p.GetStatPercent("BODY", "Balls") > FutaPercent) {
p.AdjustStatXP("Hormones", ((p.GetStat("BODY", "Balls") / 5) * -1.0)); // Bigger balls add more male hormones.
}
}
};

/** FITNESS */
Expand Down
12 changes: 11 additions & 1 deletion src/001-SCRIPT_DATA/EFFECTS/effects_unique.js
Original file line number Diff line number Diff line change
Expand Up @@ -272,4 +272,14 @@ App.Data.EffectLib["BROW_THINNER"] = {
},
"VALUE" : 250,
"KNOWLEDGE" : [ "Eyebrows Thinner++", ]
};
};

App.Data.EffectLib["FUTA_COLLAR"] = {
"FUN" : /** @param {App.Entity.Player} p
@param {App.Items.Consumable} o*/
function(o,p) {
p.AdjustStatXP('Futa', 50);
},
"VALUE" : 50,
"KNOWLEDGE" : [ "Futanari Identity+" ]
};
19 changes: 19 additions & 0 deletions src/001-SCRIPT_DATA/GameData.js
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,25 @@ App.Data.Lists = {
200 : { "COST" : 190, "STEP" : 1, "ADJECTIVE" : "ladylike" , "COLOR" : 16}
}
},
"Futa": { "MIN" : 0, "MAX" : 100, "START" : 0,
"LEVELING" : {
5 : { "COST" : 100, "STEP" : 1, "ADJECTIVE" : "shy" , "COLOR" : 1},
10 : { "COST" : 100, "STEP" : 1, "ADJECTIVE" : "timid" , "COLOR" : 2},
15 : { "COST" : 125, "STEP" : 1, "ADJECTIVE" : "timid" , "COLOR" : 3},
20 : { "COST" : 125, "STEP" : 1, "ADJECTIVE" : "diffident" , "COLOR" : 4},
30 : { "COST" : 200, "STEP" : 1, "ADJECTIVE" : "diffident" , "COLOR" : 5},
32 : { "COST" : 225, "STEP" : 1, "ADJECTIVE" : "open" , "COLOR" : 6},
38 : { "COST" : 250, "STEP" : 1, "ADJECTIVE" : "open" , "COLOR" : 7},
46 : { "COST" : 300, "STEP" : 1, "ADJECTIVE" : "outright" , "COLOR" : 8},
54 : { "COST" : 350, "STEP" : 1, "ADJECTIVE" : "outright" , "COLOR" : 9},
62 : { "COST" : 400, "STEP" : 1, "ADJECTIVE" : "daring" , "COLOR" : 10},
71 : { "COST" : 450, "STEP" : 1, "ADJECTIVE" : "daring" , "COLOR" : 12},
80 : { "COST" : 500, "STEP" : 1, "ADJECTIVE" : "daring" , "COLOR" : 13},
89 : { "COST" : 550, "STEP" : 1, "ADJECTIVE" : "perfect" , "COLOR" : 15},
98 : { "COST" : 600, "STEP" : 1, "ADJECTIVE" : "perfect" , "COLOR" : 16},
100 : { "COST" : 1500, "STEP" : 1, "ADJECTIVE" : "perfect" , "COLOR" : 16}
}
},
"Energy": { "MIN" : 0, "MAX" : 10, "START" : 3,
"LEVELING" : {
"NONE" : { "COST" : 0, "STEP" : 0 }
Expand Down
11 changes: 10 additions & 1 deletion src/103-ABAMOND/TreasureRoom.twee
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,13 @@ After a long and arduous trek you've finally made your way into the deepest and

Towards the back of the room you see a small opening. Upon inspecting it, it appears to be a secret tunnel leading back to the surface.

@@color:lime;Travel@@: [[Into the Jungle|Jungle]]
<<set _QE = window.App.QuestEngine>>\
<<set $GameBookmark = passage(); >>\
<<if _QE.QuestCompleted(setup.player, "FUTACOLLAR") == false>>
In one of the corners you notice remains of a human skeleton. Upon a closer look you notice something shining near it. Trying to take that thing out you discover that it was bound around the neck of the human, whose dead remains seem to be lying in this chamber for hundreds of years. Fortunately, it is not hard to pull it out through already rotten bones. Slightly cleaning the object you recognize a neck collar, made of a heavy, shining metal, and decorated with a few big gems. You decide to take the collar with you.

<<run setup.player.AddItem("CLOTHES", "ancient metal collar", 1);>>\
<<run _QE.SetQuestFlag(setup.player, "FUTACOLLAR", "COMPLETED");>>
<</if>>

@@color:lime;Travel@@: [[Into the Jungle|Jungle]]
2 changes: 2 additions & 0 deletions src/200-WIDGETS/printPlayerDescription.twee
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ You have a <<print App.PR.pFace(setup.player);>> <<print App.PR.pHair(setup.play
<<print App.PR.pHips(setup.player);>> <<print App.PR.pWaist(setup.player);>> and \
<<print App.PR.pFigure(setup.player);>>. You have <<print App.PR.pPenis(setup.player);>> and \
<<print App.PR.pBalls(setup.player);>> between your legs.
<<if setup.player.IsFuta()>><<print window.App.PR.pFutaStatus(setup.player);>><</if>>

You consider your natural beauty to be <<print App.PR.pBeauty(setup.player);>>.
The fetish appeal of your body is <<print App.PR.pFetish(setup.player);>>.\
Expand All @@ -23,6 +24,7 @@ You have a <<print window.App.PR.pFace(setup.player);>> <<print window.App.PR.pH
<<print window.App.PR.pHips(setup.player);>> <<print window.App.PR.pWaist(setup.player);>> and \
<<print window.App.PR.pFigure(setup.player);>>. You have <<print window.App.PR.pPenis(setup.player);>> and \
<<print window.App.PR.pBalls(setup.player);>> between your legs.
<<if setup.player.IsFuta()>><<print window.App.PR.pFutaStatus(setup.player);>><</if>>

You consider your natural beauty to be <<print window.App.PR.pBeauty(setup.player);>>.
The fetish appeal of your body is <<print window.App.PR.pFetish(setup.player);>>.\
Expand Down