Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • Elvenoob/degrees-of-lewdity
  • FreeER/degrees-of-lewdity
  • CrimsonTide/degrees-of-lewdity
  • scyne/degrees-of-lewdity
  • asbjorn/degrees-of-lewdity
  • liah55/degrees-of-lewdity
  • CanolaCulture/degrees-of-lewdity
  • Spectacular/degrees-of-lewdity
  • vultureangels/degrees-of-lewdity
  • stepidbesterd/degrees-of-lewdity
  • larsrand/degrees-of-lewdity
  • Music5264/degrees-of-lewdity
  • gayskele/degrees-of-lewdity
  • Pregmodder/degrees-of-lewdity
  • GoodMan_624/degrees-of-lewdity
  • AshNoBad/degrees-of-lewdity
  • poonta/degrees-of-lewdity
  • ezsh/degrees-of-lewdity
  • Obelus/degrees-of-lewdity
  • garbageman/degrees-of-lewdity
  • Noot/degrees-of-lewdity
  • Vrelnir/degrees-of-lewdity
  • aimozg/degrees-of-lewdity
  • Blank_/degrees-of-lewdity
  • klorpa/degrees-of-lewdity
  • bcy603/degrees-of-lewdity
  • Uncanine/degrees-of-lewdity
  • lewdmodder/degrees-of-lewdity
  • setsuna/degrees-of-lewdity
  • electronemissary/degrees-of-lewdity
  • 00c356/degrees-of-lewdity
  • pettan/degrees-of-lewdity
  • soup/degrees-of-lewdity
  • nickylass/degrees-of-lewdity
  • BelshazzarII/degrees-of-lewdity
  • Mauno/degrees-of-lewdity
  • Stuffedgame/degrees-of-lewdity
  • TaiwanSmurf/degrees-of-lewdity
  • Icemourne/degrees-of-lewdity
  • Hitcihker42/degrees-of-lewdity
  • LuckyLucky/degrees-of-lewdity
  • CasaBlanc/degrees-of-lewdity
  • YetAnotherDeviant/degrees-of-lewdity
  • number361/degrees-of-lewdity
  • shikiyoku/degrees-of-lewdity
  • siowyisheng/degrees-of-lewdity
  • unlined4928/degrees-of-lewdity
  • mihairu/degrees-of-lewdity
  • araven/degrees-of-lewdity
  • Hexogen/degrees-of-lewdity
  • Klain/degrees-of-lewdity
  • Chingonerio/degrees-of-lewdity
  • lewddude/degrees-of-lewdity
  • Dinesty30/degrees-of-lewdity
  • zerou/degrees-of-lewdity
  • SumGai/degrees-of-lewdity
  • QuadChroma/degrees-of-lewdity
  • hwp/degrees-of-lewdity
  • DitFranXX/degrees-of-lewdity
  • ndarkflame/degrees-of-lewdity
  • fuguer/degrees-of-lewdity
  • bean/degrees-of-lewdity
  • xomikob988/degrees-of-lewdity
  • purity/degrees-of-lewdity
  • voa/degrees-of-lewdity
  • FeralMoon/degrees-of-lewdity
  • mw.wabbit/degrees-of-lewdity
  • sassyenzie1/degrees-of-lewdity
  • katiek/degrees-of-lewdity
  • Dolmodder328/degrees-of-lewdity
  • 2ndSnake/degrees-of-lewdity
  • AbelofAurelia/degrees-of-lewdity
  • Sommar/degrees-of-lewdity
  • bsin/degrees-of-lewdity
  • Braymann/degrees-of-lewdity
  • YUNKING/degrees-of-lewdity
  • loofaaa/degrees-of-lewdity
  • RedStar/degrees-of-lewdity
  • JohnFilitov/degrees-of-lewdity
  • Raahs/degrees-of-lewdity
  • that_coding_dumbass/degrees-of-lewdity
  • PubNut/degrees-of-lewdity
  • CLUBDOGMApa/degrees-of-lewdity
  • Xhianil/degrees-of-lewdity
  • ANotNiceMouse/degrees-of-lewdity
  • tremainekason/degrees-of-lewdity
  • coldblood512/degrees-of-lewdity
  • b.smith/degrees-of-lewdity
  • erutheae/degrees-of-lewdity
  • vv3r3vv0lf/degrees-of-lewdity
  • LordCydano/degrees-of-lewdity
  • noteleven/degrees-of-lewdity
  • theabyssatmidnight/degrees-of-lewdity
  • Redalastor13/degrees-of-lewdity
  • noeinan/degrees-of-lewdity
  • PhaseDave/degrees-of-lewdity
  • BigBlackAwoo/degrees-of-lewdity
  • oyea/degrees-of-lewdity
  • hedpets/degrees-of-lewdity
  • C0D3/degrees-of-lewdity
  • small-keyman/degrees-of-lewdity
  • GayRaccoon/degrees-of-lewdity
  • DAPdev6/degrees-of-lewdity
  • ScribblingScribe/degrees-of-lewdity
  • Ybyx/degrees-of-lewdity
  • Area/degrees-of-lewdcraft
  • im_definitely_not_a_/degrees-of-lewdity
  • jgl/degrees-of-lewdity
  • Dualium/degrees-of-lewdity
  • b12481632/degrees-of-lewdity
  • kink-kat/degrees-of-lewdity
  • Devalk/degrees-of-lewdity
  • Cord/degrees-of-lewdity
  • Beat120/degrees-of-lewdity
  • ano/degrees-of-lewdity
  • djnjsed/degrees-of-lewdity
  • TalliasVijaandUraniu/degrees-of-lewdity
  • StinkyLizard/degrees-of-lewdity
  • Kamikaza404/degrees-of-lewdity
  • ammm/more-shortcuts
  • rustynails/degrees-of-lewdity-kylar-expansion-mod
  • lifeAnime/degrees-of-lewdity
  • KrystalwithaK/degrees-of-lewdity
  • AzureSheep/degrees-of-lewdity
  • khovel/degrees-of-lewdity
  • luna/degrees-of-lewdity
  • dust36/degrees-of-lewdity
  • shun/degrees-of-lewdity
  • TonyFox/degrees-of-lewdity
  • Eilitai/dol-solar
  • dolcontributor/degrees-of-lewdity
  • stalesandwich/degrees-of-lewdity
  • HZero/degrees-of-lewdity
  • KiraaCorsac/degrees-of-lewdity
  • Ruheon/degrees-of-lewdity
  • PixelArtFirend/degrees-of-lewdity-test-mod
  • Trinidad/grados-de-lascivia
  • QuiltedQuail/degrees-of-lewdity
  • evrgentesee/degrees-of-lewdity
  • ALambert/degrees-of-lewdity-the-cat-mod
  • Green745/degrees-of-lewdity
  • saltyycoffee/dol-saltyys-mod
  • xao321/degrees-of-lewdity
  • Vogel100/degrees-of-lewdity
  • FadedLines/degrees-of-lewdity
  • deformedgodcomplex/degrees-of-lewdity
  • tracktack00/dol
  • VortluexIridum/DOL
  • ChickChuck2/degrees-of-lewdity-pt-br
  • pumpinglemma/degrees-of-lewdity
  • Host/degrees-of-lewdity
  • ChexAndBalances/degrees-of-lewdity
  • Fost3r/degrees-of-lewdity
  • Tarkin/degrees-of-lewdity
  • Juno/dol-saltyys-mod
  • TonyBologna/degrees-of-lewdity-foster
  • Stadler76/degrees-of-lewdity
  • Akoz/degrees-of-lewdity
  • treeib7/degrees-of-lewdity
  • dechet/degrees-of-lewdity
  • TheDivineHeir/degrees-of-lewdity
  • Enty/degrees-of-lewdity
  • 24khp/degrees-of-lewdity
  • slenderostrich/degrees-of-lewdity
  • Kirsty/degrees-of-lewdity
  • Anony5261/degrees-of-lewdity
  • veritas1A4/degrees-of-lewdity-plus
  • HeepSelk/degrees-of-lewdity
  • ThomazLIRA27/degrees-of-lewdity
  • striderxfossility/degrees-of-lewdity
  • piotrejo/degrees-of-lewdity
  • Idekk/degrees-of-lewdity
  • branthepeach/degrees-of-lewdity
  • thermal/degrees-of-lewdity
  • cutiland/degrees-of-lewdity
  • anony5264/degrees-of-lewdity
  • Warui430/degrees-of-lewdity-testing
  • Skullky/degrees-of-lewdity
  • netolilium/degrees-of-lewdity
  • TheLoneWolf3626/degrees-of-lewdity
  • majou/degrees-of-lewdity
  • joemamba/degrees-of-lewdity
  • Airbourne/degrees-of-lewd-remerged
  • FritzTheGlitch/degrees-of-lewdity
  • Orangeblur/degrees-of-lewdity
  • Bandrose1/degrees-of-lewdity
  • DoLSteph/degrees-of-lewdity
  • Newtnewt/degrees-of-lewdity
  • KinkyOne/degrees-of-lewdity
  • edward6/degrees-of-lewdity
  • Mira1/degrees-of-lewdity
  • TFS/degrees-of-lewdity
  • oxone/degrees-of-lewdity
  • golsil/degrees-of-lewdity
  • zR3V3NANTz/degrees-of-lewdity-dragon-mod
  • PepKitty/degrees-of-lewdity
  • preeded/degrees-of-lewdity
  • Beepbeep1/degrees-of-lewdity
  • LilTransDino/degrees-of-lewdity-project-1
  • warawanaineko/degrees-of-lewdity
  • salagadoola/degrees-of-lewdity
  • RatRat/transmod-plus
  • kodicraft/degrees-of-lewdity
  • wowdoge/dol-saltyys-mod
  • handleing1/degrees-of-lewdity
  • mrcomfy/degrees-of-lewdity-mall-proposal
  • CK_Rainbow/degrees-of-lewdity
  • KnotLikeThis/degrees-of-lewdity
  • popa/degrees-of-lewdity
  • Ryumi/degrees-of-lewdity
  • GayKitten/degrees-of-lewdity
  • EndlessGame/degrees-of-lewdity
  • bijikejepit/degrees-of-lewdity-modified
  • lafrlo/degrees-of-lewdity
  • auxhonater/degrees-of-lewdity
  • ParticleG/degrees-of-lewdity
  • astrox1/degrees-of-lewdity
  • AnonymousPancakes/degrees-of-lewdity-contribution-fork
  • y4vr/degrees-of-lewdity-ravishment
  • apflu/degrees-of-lewdity-dollification-mod
  • nemuzawa200101/degrees-of-lewdity
  • MagicalAstrogy/degrees-of-lewdity
  • Khaos423/degrees-of-lewdity
  • stranger/degrees-of-lewdity
  • eesoymilk/degrees-of-lewdity
  • Frostberg/degrees-of-lewdity-plus
  • ToumanLin/degrees-of-lewdity-toumanlin
  • Murkey/degrees-of-lewdity
  • MasterCast04/degrees-of-lewdity-chimera-tail-mod
  • Tanny78/tannymod
  • Gwen1/degrees-of-lewdity-scent
  • Ducati/degrees-of-lewdity-plus
  • lune/degrees-of-lewdity
  • snowywar/degrees-of-lewdity
  • TsundereBandit/degrees-of-lewdity-plus
  • Siede/degrees-of-lewdity
  • fire2244/degrees-of-lewdity
  • decarabia/degrees-of-lewdity
  • JinoWills/degrees-of-lewdity
  • creeping1023/degrees-of-lewdity
  • ShinH/degrees-of-lewdity
  • WHALER/degrees-of-lewdity
  • WHALERSWHALER/degrees-of-lewdity-whalers-mod
  • googlyman/degrees-of-lewdity
  • Dakser/degrees-of-lewdity-plus
  • mikatakamo/dolp-randomfix-randomcontribution
  • handle5/degrees-of-lewdity
  • SpaciousStarship/degrees-of-lewdity-plus-starship-fork
  • GeneralFire/degrees-of-lewdity
  • BrokenSoul/degrees-of-lewdity
  • Twig/degrees-of-lewdity
  • noneedforthis/slight-combat-rework
  • AiHoshino/degrees-of-lewdity-vn-mod
  • baileys/degrees-of-lewdity
  • Ddkdkk/degrees-of-lewdity-plus
  • miyakoAki4828/degrees-of-lewdity
  • ojicon/degrees-of-lewdity-indonesian-translation
  • PuppeterMaster25/degrees-of-lewdity
  • Chieferton/degrees-of-lewdity-plus
  • UnbarredStream/degrees-of-lewdity-dragon-mod
  • LupusXLass1404/degrees-of-lewdity
  • MisoSquared/degrees-of-lewdity
  • IndexIsDumb/degrees-of-lewdity
  • nekoboinick/degrees-of-lewdity
  • Testry/degrees-of-lewdity
  • Cuhloe69/degrees-of-lewdity-plus
  • omvjro/degrees-of-lewdity
  • Testry/degrees-of-lewdity-plus
  • Avos/degrees-of-lewdity
  • Averall/degrees-of-lewdity-plus
  • Sh1na/degrees-of-lewdity-plus
  • fizzyboi/degrees-of-lewdity
  • Sh1na/degrees-of-lewdity
  • Prnjujujaj/degrees-of-lewdity-plus
  • Nikonov/degrees-of-lewdity-plus
  • AnonymousPossum/degrees-of-lewdity-ap-temple
  • Sabot/degrees-of-lewdity-mecha-mod
  • Shadi1089/degrees-of-lewdity-plus
  • sbdto/degrees-of-lewdity
  • theothersteve7/degrees-of-lewdity
  • melllow/degrees-of-lewdity-mellows-files
  • WinterPeach/degrees-of-lewdity-bunny-plus
  • boolin/degrees-of-lewdity-dragon-mod
  • Izeija/degrees-of-lewdity-plus-Herm-NPCs
  • test126/degrees-of-lewdity-plus
  • WolfSeige/degrees-of-lewdity
  • Frostberg/transmod-plus
  • erdd/test-degrees-of-lewdity
  • ekdms4467/degrees-of-lewdity-plus
  • MrAdvisor/degrees-of-lewdity-mellows-files
  • bugmenot97/degrees-of-lewdity-plus-ryona-edition
  • numbersir/degrees-of-lewdity
  • Paragon/degrees-of-lewdity
  • eude/degrees-of-lewdity
  • liggems/degrees-of-lewdity
  • hoihoi/degrees-of-lewdity
  • WreckieRed/degrees-of-lewdity-plus-wreckie-red
  • BlueMuffin/degrees-of-lewdity
  • edwardspec/degrees-of-lewdity
  • Neng222/degrees-of-lewdity
  • SeiraHawawa/degrees-of-lewdity
  • trashee/degrees-of-lewdity
  • Dukesnwowisb/degrees-of-lewdity-plus
  • sugarcoma/degrees-of-lewdity
  • squ1dteeth/degrees-of-lewdity
  • shojoprotagonist/degrees-of-lewdity
  • Annon173/degrees-of-lewdity-annon173
  • Brrr/degrees-of-lewdity
  • goose/dol-goosemod
  • mizzzz/degrees-of-lewdity-mizz
  • Uchiki/degrees-of-lewdity
  • Leet0/degrees-of-lewdity
  • Someone1/degrees-of-lewdity
  • Ntimpaa88/wholesome-and-whoresome-addons
  • antnoodle/degrees-of-lewdity-plus
  • Isari/degrees-of-lewdity-plus
  • variegations/degrees-of-lewdity
  • nsqueet/degrees-of-lewdity
  • DevilD0L/degrees-of-lewdity
  • HypeS84/graus-de-lascivia
  • Dwarfblood/degrees-of-lewdity-plus
  • LurkerNo255/degrees-of-lewdity-nobody-safe
  • Sl/degrees-of-lewdity-mikili
  • arugula/transmod-fork
  • handlebeater/degrees-of-lewdity-plus
  • pizzaghg/degrees-of-lewdity-plus
  • RepoRogue6960/degrees-of-lewdity
  • CharaEmbry/degrees-of-lewdity-plus
  • nanabanashi/degrees-of-lewdity-plus
  • kagurazakanyaa/degrees-of-lewdity-plus
  • Songdog/degrees-of-lewdity
331 results
Show changes
Commits on Source (543)
Showing
with 1290 additions and 358 deletions
......@@ -165,20 +165,20 @@ module.exports = {
],
parserOptions: {
// Support back to ES2019 to cover old mobile devices with outdated WebView versions that fail on 2020 and up functions
// ecmaVersion: "2019", (taken care of by env es2019)
// Support back to ES2020 to cover old mobile devices with outdated WebView versions that fail on 2020 and up functions
// ecmaVersion: "2020", (taken care of by env es2020)
sourceType: "module",
},
env: {
browser: true,
es2019: true,
es2020: true,
jquery: true,
},
plugins: ["es"],
plugins: ["es-x"],
extends: ["eslint:recommended", "plugin:jsdoc/recommended", "prettier-standard/prettier-file", "plugin:es/restrict-to-es2019"],
extends: ["eslint:recommended", "plugin:jsdoc/recommended", "prettier-standard/prettier-file", "plugin:es-x/restrict-to-es2020"],
settings: {
jsdoc: {
......@@ -190,6 +190,8 @@ module.exports = {
rules: {
"object-shorthand": ["error", "always"],
"es-x/no-object-hasown": "off",
// SugarCube extends native objects and we follow it
"no-extend-native": "off",
......@@ -208,8 +210,5 @@ module.exports = {
/* eslint-plugin-prettier */
"prettier/prettier": "warn",
// Rule to fix Safari/Webkit not supporting a 4+ year old function you idiots
"es/no-regexp-lookbehind-assertions": "error",
},
};
### Most recent mainline merge is as of October 4, 2023 and includes the 0.4.2.4 update.
### Most recent mainline merge is as of January 16, 2024 and includes the 0.4.5.3 update.
### Fixed missing genital reactions
Fixed a long-standing bug where NPCs could no longer react to the PCs genitals, due to the code for managing that getting lost in some unknown update to the mod's code.
### 0.4.5.3 merge, bottom surgery expansion and trans-specific npc reveal reactions
Merged to 0.4.5.X (previously unlisted change). Implemented previously unused bottom surgery code as now the game's code can properly support implementing it as a feature, which allows players the option to have both genitals. Also added in unique NPC reactions on discovering that PC is trans.
### 0.4.4.3 merge and changing room tweak
Merged to 0.4.4.3 and tweaked the changing room code to prevent known trans PCs from being able to enter the changing rooms matching their presentation if nude gender appearance slider is set to "judge", with lower settings letting it slide so long as they look like they should belong in there.
### bugfix update (also 0.4.3.3, since I forgot to log it)
Fixed a bug in the changing room strip event causing the player to be stuck in place an unable to continue with the event. Also fixed whitney's toilet event text getting duplicated somewhat for trans PCs. Additionally added some logic checking into the genital surgery test code to prevent phantom liquids being left behind on body parts that no longer exist. Unlisted was the update to version 0.4.3.3
### 0.4.2.7 merge and bugfix
Merged to 0.4.2.7, fixed a bug with the danube modelling job that was causing the event to break. Fixed the changes I made to the changing room code working in unintended ways. And finally, the previous changelog was incorrect. As THIS time, I have, finally and for realsies, fixed the Whitney event code.
......
This diff is collapsed.
......@@ -48,6 +48,14 @@ function compile() {
TWEEGO_EXE="./devTools/tweego/tweego_linux86"
fi
;;
arm64)
echoMessage "arm64 arch"
if [ "$(uname -s)" = "Darwin" ]; then
TWEEGO_EXE="./devTools/tweego/tweego_m1" #for mac m1 and m2
#else
#not linux arm
fi
;;
*)
echoError "No system tweego binary found, and no precompiled binary for your platform available."
echoError "Please compile tweego and put the executable in PATH."
......
<?xml version='1.0' encoding='utf-8'?>
<widget
id="dol"
version="0.4.2.8"
version="0.4.5.4"
xmlns="http://www.w3.org/ns/widgets"
xmlns:cdv="http://cordova.apache.org/ns/1.0"
android-packageName="com.vrelnir.DegreesOfLewdity"
......
......@@ -212,7 +212,7 @@ function processSlot(setupfile,imgdir,varname,hasIntegrity) {
}
function convertAllClothes() {
let slots = ["hands", "face", "feet", "genitals", "hands", "head", "legs", "lower", "neck", "over_head", "over_lower", "over_upper", "upper"];
let slots = ["hands", "face", "feet", "genitals", "hands", "head", "legs", "lower", "neck", "over_head", "over_lower", "over_upper", "upper", "handheld"];
for (let slot of slots) {
processSlot(`game/base-clothing/clothing-${slot}.twee`, `img/clothes/${slot}/`, `setup.clothes.${slot}`, true);
}
......
File added
......@@ -222,19 +222,21 @@ Will return the number of days left before the player/npc will give birth, needs
- `<<if pregnancyDaysEta(getPregnancyObject()) lt 5>>`
- `<<set _pregnancyObject to getPregnancyObject()>><<print pregnancyDaysEta(_pregnancyObject)>> days remaining.`
#### childrenCountBetweenParents(parent1, parent2)
#### childrenCountBetweenParents(parent1, parent2, motherAndFather = false)
Returns the number of children between two parents, expects to be provided strings of their name.
Returns the number of children between two parents, expects to be provided strings of their name. When `motherAndFather` is set to true, `parent1` should be considered the `mother` while `parent2` should be considered the `father`.
- `<<set _childCount to childrenCountBetweenParents("pc", "Robin")`
- `<<if childrenCountBetweenParents("pc", "Robin") gt 1>>`
- `<<if childrenCountBetweenParents("pc", "Robin", true) gt 1>>` To check for children who the pc gave birth to.
#### pregnancyCountBetweenParents(parent1, parent2)
#### pregnancyCountBetweenParents(parent1, parent2, motherAndFather = false)
Returns the number of pregnancies between two parents, expects to be provided strings of their name.
Returns the number of pregnancies between two parents, expects to be provided strings of their name. When `motherAndFather` is set to true, `parent1` should be considered the `mother` while `parent2` should be considered the `father`.
- `<<set _childCount to pregnancyCountBetweenParents("pc", "Robin")`
- `<<if pregnancyCountBetweenParents("pc", "Robin") gt 0>>`
- `<<if pregnancyCountBetweenParents("pc", "Robin", true) gt 0>>` To check for children who the pc gave birth to.
#### setBabyIntro(mother, introFor, birthId)
......
......@@ -115,7 +115,6 @@ throwError = function (place, message, source, isExportable = true, isLogged = t
label: "Export",
},
() => {
updateExportDay();
Save.export("degrees-of-lewdity");
}
)
......
......@@ -28,7 +28,7 @@ stringFrom = function (value) {
const result = Array.from(value).map(([key, val]) => `${stringFrom(key)} \u2192 ${stringFrom(val)}`);
return `{\u202F${result.join(", ")}\u202F}`;
} else if (value instanceof Date) {
return value.toLocaleString();
return value.toLocaleString(returnTimeFormat());
} else if (value instanceof Element) {
if (value === document.documentElement || value === document.head || value === document.body) {
throw new Error("illegal operation; attempting to convert the <html>, <head>, or <body> tags to string is not allowed");
......@@ -49,7 +49,7 @@ stringFrom = function (value) {
}
case "undefined":
if (V && (V.options.debugdisable === "f" || V.debug === 1)) {
if (V && ((V.options && V.options.debugdisable === "f") || V.debug === 1)) {
Errors.report("Print macro attempted to return an undefined variable in " + Utils.GetStack());
}
return V && V.debug ? "[undefined]" : "";
......
Object.defineProperties(window, {
/* Story variables property. */
V: {
get() {
return State.variables;
},
},
/* Temporary variables property. */
T: {
get() {
return State.temporary;
},
},
/* Constants property. */
C: {
get() {
......
......@@ -30,7 +30,9 @@ This work of fiction contains content of a sexual nature and is inappropriate fo
<<set $settingsExitPassage to "Start2">>
<<initsettings>>
<<settingsStart>>
<div id="settingsStart">
<<settingsStart>>
</div>
:: Start2 [nosave exitCheckBypass]
......@@ -44,11 +46,11 @@ If you want to avoid trouble, dress modestly and stick to safe, well-lit areas.
<br><br>
<<if Time.season is "winter">>
The school year starts on the first Monday of January at <<ampm 9 0>>. The bus service is the easiest way to get around town. Don't forget your uniform!
The school year starts on the first Monday of January at <<ampm 9 0>>. The bus service is the easiest way to get around town. Don't forget your uniform and backpack!
<<elseif Time.season is "spring" or Time.season is "summer">>
School starts tomorrow at <<ampm 9 0>>. The bus service is the easiest way to get around town. Don't forget your uniform!
School starts tomorrow at <<ampm 9 0>>. The bus service is the easiest way to get around town. Don't forget your uniform and backpack!
<<else>>
The new school year starts tomorrow at <<ampm 9 00>>. The bus service is the easiest way to get around town. Don't forget your uniform!
The new school year starts tomorrow at <<ampm 9 00>>. The bus service is the easiest way to get around town. Don't forget your uniform and backpack!
<</if>>
<br><br>
......
......@@ -3,6 +3,21 @@ Config.history.controls = false;
Config.saves.slots = 9;
Config.history.maxStates = 1;
Config.saves.id = "degrees-of-lewdity"
/* LinkNumberify and images will enable or disable the feature completely */
/* debug will enable or disable the feature only for new games */
/* sneaky will enable the Sneaky notice banner on the opening screen and save display */
/* versionName will be displayed in the top right of the screen, leave as "" to not display anything */
window.StartConfig = {
debug: false,
enableImages: true,
enableLinkNumberify: true,
version: "0.4.5.3",
versionName: "",
sneaky: false,
};
State.prng.init();
window.versionUpdateCheck = true;
......@@ -10,7 +25,29 @@ window.onLoadUpdateCheck = false;
let pageLoading = false;
Config.saves.isAllowed = () => {
if (tags().includes("nosave") || V.replayScene) return false;
return true;
}
idb.footerHTML = `
<div class="savesListRow">
<div class="saveGroup">
<span style="margin: 0;">
Special thanks to all those who <a target="_blank" class="link-external" href="https://subscribestar.adult/vrelnir" tabindex="0">Support Degrees of Lewdity</a>
</span>
<div class="saveId"></div>
<div class="saveButton"></div>
<div class="saveName"></div>
<div class="saveDetails"></div>
</div>
<div class="saveButton">
<input type="button" class="saveMenuButton right" value="Delete All" onclick="idb.saveList('confirm clear')">
</div>
</div>`
function onLoad(save) {
// some flags for version update. ideally, all updating should be done here in onLoad, but we don't live in an ideal world
pageLoading = true;
window.onLoadUpdateCheck = true;
......@@ -21,27 +58,75 @@ function onLoad(save) {
// decompression should be the FIRST save modification
DoLSave.decompressIfNeeded(save);
// cache current date before assigning it to every frame in history
const date = new Date();
save.state.history.forEach(h => {
if (h.prng && Array.isArray(h.prng.S)) {
h.prng.S.forEach((i, index, array) => {
if (i < 0 || i > 255) array[index] %= 256;
});
}
h.variables.saveDetails = defaultSaveDetails(h.variables.saveDetails);
h.variables.saveDetails.loadTime = new Date();
const details = h.variables.saveDetails;
if (details) {
if (!details.playTime) details.playTime = 0;
if (!details.loadCount) details.loadCount = 0;
details.loadTime = date;
details.loadCount++;
}
});
}
window.onLoad = onLoad;
Save.onLoad.add(onLoad);
function onSave(save) {
/**
* increment saves counter and update relevant statistics
*
* @param {object} storyVars State.variables or similar object to modify
* @param {"slot"|"autosave"|"disk"|"serialize"} type save type
* @param {Date} date cached date object so we don't have to run `new Date()` hundreds of times
*/
function incSavesCount(storyVars = V, type, date) {
const details = storyVars.saveDetails;
if (!details) return; // really ancient save that somehow didn't get updated
switch (type) {
case "slot":
details.slot.count++;
break;
case "autosave":
details.auto.count++;
break;
case "disk":
details.exported.days = Time.days;
details.exported.count++;
break;
case "serialize":
details.exported.count++;
break;
}
if (date) details.playTime += date - details.loadTime;
}
function onSave(save, details) {
// * update feats * //
Wikifier.wikifyEval("<<updateFeats>>");
save.state.history.forEach(h => {
h.variables.saveDetails = defaultSaveDetails(h.variables.saveDetails);
h.variables.saveDetails.playTime += h.variables.saveDetails.loadTime ? new Date() - h.variables.saveDetails.loadTime : 0;
h.variables.saveDetails.loadCount++;
});
// don't run legacy code when idb is active
// * update $saveDetails wherever possible * //
const type = details.type;
const date = save.date;
// start with active vars, so we can view statistics
incSavesCount(V, type, date);
// then saved history, so moving back and forth doesn't reset it
State.history.forEach(h => incSavesCount(h.variables, type, date));
// then actual save vars
save.state.history.forEach(sh => incSavesCount(sh.variables, type, date));
// and finally, session data, so it persists even after f5
const session = State.getSessionState();
if (session != null) {
session.history.forEach(s => incSavesCount(s.variables, type, date));
State.setSessionState(session);
}
// * legacy code for old saves system * //
if (!(window.idb && window.idb.active)) {
// eslint-disable-next-line no-undef
prepareSaveDetails(); // defined in save.js
......@@ -53,21 +138,6 @@ function onSave(save) {
window.onSave = onSave;
Save.onSave.add(onSave);
Config.saves.id = "degrees-of-lewdity"
/* LinkNumberify and images will enable or disable the feature completely */
/* debug will enable or disable the feature only for new games */
/* sneaky will enable the Sneaky notice banner on the opening screen and save display */
/* versionName will be displayed in the top right of the screen, leave as "" to not display anything */
window.StartConfig = {
debug: false,
enableImages: true,
enableLinkNumberify: true,
version: "0.4.2.7",
versionName: "",
sneaky: false,
};
/* convert version string to numeric value */
const tmpver = StartConfig.version.replace(/[^0-9.]+/g, "").split(".");
window.StartConfig.version_numeric = tmpver[0] * 1000000 + tmpver[1] * 10000 + tmpver[2] * 100 + tmpver[3] * 1;
......@@ -81,16 +151,6 @@ Config.saves.isAllowed = function () {
return true;
};
$(document).on(":passagestart", function (ev) {
if (ev.passage.title === "Start2") {
$.event.trigger({
type: ":start2",
content: ev.content,
passage: ev.passage,
});
}
});
importStyles("style.css")
.then(function () {
console.log("External Style Sheet Active");
......@@ -121,41 +181,6 @@ importScripts([
console.log(err);
}); */
function defaultSaveDetails(input) {
let saveDetails = input;
if (!saveDetails) {
// In the rare case the variable doesnt exist
saveDetails = {
exported: {
days: clone(variables.days),
frequency: 15,
count: 0,
dayCount: 0,
},
auto: {
count: 0,
},
slot: {
count: 0,
dayCount: 0,
},
};
}
if (!saveDetails.playTime) {
saveDetails.playTime = 0;
saveDetails.loadCount = 0;
}
if (!saveDetails.f || saveDetails.f < 1) {
saveDetails.f = 1;
saveDetails.playTime = 0;
}
if (saveDetails.f < 3) {
saveDetails.playTime = 0;
saveDetails.f = 3;
}
return saveDetails;
}
// Runs before a passage load, returning a string redirects to the new passage name.
Config.navigation.override = function (dest) {
const checkPassages = dest => {
......@@ -189,6 +214,13 @@ Config.navigation.override = function (dest) {
case "Forest Shop Feet":
return "Forest Shop";
case "Cafe Fruit Salad":
case "Cafe Autumn Ale":
case "Cafe Summer Ale":
case "Cafe Spring Ale":
case "Cafe Winter Ale":
return "Cafe Eat";
case "Over Outfit Shop":
case "Outfit Shop":
case "Top Shop":
......@@ -453,6 +485,17 @@ Config.navigation.override = function (dest) {
return "Chalets Work One Sex";
case "Chalets Work One Rape Finish":
return "Chalets Work One Sex Finish";
case "Whitney Bully Parasite Event Submit":
case "Whitney Bully Parasite Event Escape Attempt":
return "Bully Parasite";
case "Whitney Bully Parasite Event Combat":
return "Bully Parasite Fight";
case "Whitney Bully Parasite Event Combat Loss":
case "Whitney Bully Parasite Event Combat Victory":
return "Bully Parasite Fight Finish";
default:
return false;
}
......
......@@ -95,7 +95,6 @@ function humanChildActivity(childId) {
]);
if (T.childTotalDays >= 50) activity.push("happy");
if (toySets.includes("baby rattles")) activity.push("babyRattle");
if (toySets.includes("teddy bears")) activity.push("teddyBear");
if (toySets.includes("toy cars")) activity.push("toyCar");
......@@ -106,6 +105,10 @@ function humanChildActivity(childId) {
}
if (toySets.includes("clown")) activity.push("clown");
if (T.robin_location === "orphanage") activity.push("Robin");
if (child.father === "Ivory Wraith") {
wikifier("rngWraith", 1);
if (T.wraithEvent) activity.push("Wraith");
}
}
} else if (between(T.childTotalDays, 100, 200)) {
if (Time.dayState === "night") {
......@@ -138,6 +141,10 @@ function humanChildActivity(childId) {
if (toySets.includes("clown")) activity.push("clown");
if (child.localVariables.talking >= 10 && T.childTotalDays >= 150) activity.push("talking2");
if (T.robin_location === "orphanage") activity.push("Robin");
if (child.father === "Ivory Wraith") {
wikifier("rngWraith", 1);
if (T.wraithEvent) activity.push("Wraith");
}
}
}
......
......@@ -12,7 +12,7 @@ function generateBabyName(name, gender, childId) {
});
}
if (!!name && name !== "Unnamed") {
return name.replace(/[^a-zA-ZÀ-ÿ ]+/g, "").substring(0, 30);
return name.replace(/[^a-zA-ZÀ-ÿ\u4e00-\u9fa5 ]+/g, "").substring(0, 30);
}
let names = [];
switch (gender) {
......@@ -52,6 +52,10 @@ function spermObjectToArray(spermObject = [], player, disableRng) {
case "wolfgirl":
if (V.playerPregnancyBeastDisable === "t" && player) continue;
break;
case "hawk":
case "harpy":
if ((V.playerPregnancyBeastDisable === "t" || V.playerPregnancyEggLayingDisable === "t") && player) continue;
break;
default:
continue;
}
......@@ -88,8 +92,12 @@ function fetishPregnancy({ genital = "vagina", target = null, spermOwner = null,
const diff = Math.abs(menstruation.stages[2] - menstruation.currentDay);
multi = Math.clamp(diff > 1 ? 1 - diff * 0.15 : 1, 0, 1);
} else if (C.npc[target] && C.npc[target].pregnancy && C.npc[target].pregnancy.enabled) {
const diff = Math.abs(pregnancy.cycleDangerousDay - pregnancy.cycleDay);
multi = Math.clamp(diff > 1 ? 1 - diff * 0.15 : 1, 0, 1);
if (target === "Great Hawk") {
multi = pregnancy.cycleDay >= pregnancy.cycleDangerousDay ? 1 : 0;
} else {
const diff = Math.abs(pregnancy.cycleDangerousDay - pregnancy.cycleDay);
multi = Math.clamp(diff > 1 ? 1 - diff * 0.15 : 1, 0, 1);
}
}
} else {
// Other non-cycle modifiers
......@@ -100,6 +108,11 @@ function fetishPregnancy({ genital = "vagina", target = null, spermOwner = null,
multi = 1 / Math.pow(4, C.npc[target].pregnancy.nonCycleRng[0]);
}
}
if (["hawk", "harpy"].includes(spermType) || target === "Great Hawk") {
if (!["pc", "Great Hawk"].includes(target)) return false;
if ((target === "pc" && !V.harpyEggs) || (target === "Great Hawk" && multi === 1)) return false;
forcePregnancy = true;
}
if (pregnancy && pregnancy.type === null) {
let chance = 100 / (target === "pc" ? 100 - V.basePlayerPregnancyChance : 20 - V.baseNpcPregnancyChance);
......@@ -147,13 +160,19 @@ function playerPregnancyAttempt(baseMulti = 1, genital = "vagina") {
if (V.skin.pubic.pen === "magic" && V.skin.pubic.special === "pregnancy") {
fertilityBoost -= 0.4;
}
let baseChance = Math.floor((100 - V.basePlayerPregnancyChance) * Math.clamp(fertilityBoost, 0.1, 1) * baseMulti);
/* The lower basePenalty is, the easier it is for the player to get pregnant */
let basePenalty = Math.floor((100 - V.basePlayerPregnancyChance) * Math.clamp(fertilityBoost, 0.1, 1) * baseMulti);
if (V.earSlime.growth >= 100 && V.earSlime.focus === "pregnancy") baseChance = Math.floor(baseChance * 2);
if (V.earSlime.growth >= 100 && V.earSlime.focus === "impregnation") baseChance = Math.floor(baseChance / 2);
if (V.earSlime.growth >= 100 && V.earSlime.focus === "pregnancy") basePenalty = Math.floor(basePenalty * 2);
if (V.earSlime.growth >= 100 && V.earSlime.focus === "impregnation") basePenalty = Math.floor(basePenalty / 2);
const rng = random(0, spermArray.length - 1 > baseChance ? spermArray.length - 1 : baseChance);
/*
When spermArray.length - 1 is lower than basePenalty, it uses basePenalty to determin if the pregnancy should occur or not
When spermArray.length - 1 is higher than basePenalty, the player will always get pregnant, so it uses spermArray.length - 1 to give all sperm a chance to impregnate the player
*/
const rng = random(0, spermArray.length - 1 > basePenalty ? spermArray.length - 1 : basePenalty);
/* When spermArray[rng] is undefined, the player failed to get pregnant */
if (spermArray[rng]) {
const fatherKnown = Object.keys(trackedNPCs).length === 1;
......@@ -167,9 +186,36 @@ window.playerPregnancyAttemptTest = (baseMulti, genital) => {
if (V.pregnancyTesting) return playerPregnancyAttempt(baseMulti, genital);
}; // V.pregnancyTesting Check should not be removed, debugging purposes only
function playerPregnancyHawkAttempt(genital = "vagina") {
const pregnancy = V.sexStats[genital].pregnancy;
if (pregnancy.fetus.length || !V.harpyEggs) return false;
const [trackedNPCs, spermArray] = spermObjectToArray(V.sexStats[genital].sperm, true);
const pills = V.sexStats.pills;
const contraceptive = Math.clamp(pills.pills.contraceptive.doseTaken || 0, 0, Infinity);
if (spermArray.length === 0 || (contraceptive && (random(0, 100) >= 10 || contraceptive > 1))) return false;
const harpySperm = spermArray.filter(source => ["hawk", "harpy"].includes(source.type)).random();
if (harpySperm) {
const fatherKnown = Object.keys(trackedNPCs).length === 1;
// Player becomes pregnant
return playerPregnancy(harpySperm.source, harpySperm.type, fatherKnown, genital, trackedNPCs);
}
return false;
}
DefineMacro("playerPregnancyHawkAttempt", playerPregnancyHawkAttempt);
window.playerPregnancyHawkAttempt = genital => {
if (V.pregnancyTesting) return playerPregnancyHawkAttempt(genital);
}; // V.pregnancyTesting Check should not be removed, debugging purposes only
const playerPregnancy = (npc, npcType, fatherKnown = false, genital = "vagina", trackedNPCs, awareOf = false) => {
if (V.playerPregnancyHumanDisable === "t" && npcType === "human") return false; // Human player pregnancy disabled
if (V.playerPregnancyBeastDisable === "t" && npcType !== "human") return false; // Beast player pregnancy disabled
if (V.playerPregnancyEggLayingDisable === "t" && ["hawk", "harpy"].includes(npcType)) return false; // Egg laying player pregnancy disabled
const pregnancy = clone(V.sexStats[genital].pregnancy);
let newPregnancy;
let backupSpermType;
......@@ -188,6 +234,20 @@ const playerPregnancy = (npc, npcType, fatherKnown = false, genital = "vagina",
newPregnancy = pregnancyGenerator.wolf("pc", npc, fatherKnown, genital, true);
backupSpermType = "wolf";
break;
case "hawk":
/* ToDo: Enable hawk pregnancy: Remove pregnancyTesting check */
if (V.pregnancyTesting) {
newPregnancy = pregnancyGenerator.hawk("pc", npc, fatherKnown, genital, false);
backupSpermType = "hawk";
}
break;
case "harpy":
/* ToDo: Enable hawk pregnancy: Remove pregnancyTesting check */
if (V.pregnancyTesting) {
newPregnancy = pregnancyGenerator.hawk("pc", npc, fatherKnown, genital, true);
backupSpermType = "hawk";
}
break;
}
if (newPregnancy && !(typeof newPregnancy === "string" || newPregnancy instanceof String) && newPregnancy.fetus.length) {
V.sexStats[genital].pregnancy = {
......@@ -199,6 +259,7 @@ const playerPregnancy = (npc, npcType, fatherKnown = false, genital = "vagina",
awareOf,
};
V.sexStats.vagina.menstruation.currentState = "pregnant";
if (V.harpyEggs) delete V.harpyEggs;
return true;
}
return false;
......@@ -226,6 +287,9 @@ function pregnancyProgress(genital = "vagina") {
case "wolf":
multiplier = 12 / V.wolfPregnancyWeeks;
break;
case "hawk":
multiplier = 1;
break;
}
// The `0.5 * ` is because it runs at both midnight and noon
pregnancy.timer += parseFloat((0.5 * multiplier).toFixed(3));
......@@ -277,6 +341,9 @@ function playerEndWaterProgress() {
return null;
}
// Intended to end a hawk pregnancy in a different way
if (pregnancy.type === "hawk") return false;
if (
!isNaN(pregnancy.waterBreakingTimer) &&
pregnancy.waterBreakingTimer > 0 &&
......@@ -313,7 +380,30 @@ function endPlayerPregnancy(birthLocation, location) {
if (!pregnancy || !pregnancy.fetus.length) return false;
giveBirthToChildren("pc", birthLocation, location);
if (pregnancy.fetus[0].father === "Alex") {
delete C.npc.Alex.pregnancy.pcKnowledge;
delete C.npc.Alex.pregnancy.test;
delete C.npc.Alex.pregnancy.ultraSound;
delete C.npc.Alex.pregnancy.sample;
delete C.npc.Alex.pregnancy.noBirthControl;
delete C.npc.Alex.pregnancy.ultraSoundPics;
C.npc.Alex.pregnancy.pills = "contraceptive";
C.npc.Alex.pregnancyAvoidance = 50;
if (Object.values(V.children).find(child => (child.mother === "Alex" || child.father === "Alex") && child.location === "home")) {
// Do Nothing
} else {
delete C.npc.Alex.pregnancy.fee;
}
}
let validBirth;
if (pregnancy.fetus[0].childId) {
giveBirthToChildren("pc", birthLocation, location);
validBirth = true;
} else if (pregnancy.type === "hawk") {
// ToDo: Perfect place to give the player unfertilized eggs?
}
switch (pregnancy.type) {
case "human":
......@@ -322,15 +412,18 @@ function endPlayerPregnancy(birthLocation, location) {
case "wolf":
menstruation.recoveryTime = random(1, 2) * V.wolfPregnancyWeeks;
break;
case "hawk":
menstruation.recoveryTime = 0.5;
break;
}
if ((genital === "vagina" && V.player.virginity.vaginal === true) || (genital === "anus" && V.player.virginity.anal === true)) {
if (validBirth && ((genital === "vagina" && V.player.virginity.vaginal === true) || (genital === "anus" && V.player.virginity.anal === true))) {
V.pregnancyStats.playerVirginBirths.pushUnique(pregnancy.fetus[0].birthId);
}
V.sexStats[genital].pregnancy = {
...pregnancy,
totalBirthEvents: (pregnancy.totalBirthEvents || 0) + 1,
totalBirthEvents: validBirth ? (pregnancy.totalBirthEvents || 0) + 1 : pregnancy.totalBirthEvents || 0,
fetus: [],
waterBreaking: false,
waterBreakingTimer: null,
......@@ -352,24 +445,12 @@ function endPlayerPregnancy(birthLocation, location) {
awareOfPeriodDelay: false,
};
delete V.sexStats[genital].pregnancy.ultrasoundDone;
delete V.templeVirginPregnancy;
delete V.caveHumanPregnancyDiscovered;
delete C.npc.Alex.pregnancy.knowledge;
delete C.npc.Alex.pregnancy.test;
delete C.npc.Alex.pregnancy.sample;
delete C.npc.Alex.pregnancy.noBirthControl;
C.npc.Alex.pregnancy.pills = "contraceptive";
C.npc.Alex.pregnancyAvoidance = 50;
if (Object.values(V.children).find(child => child.mother === "Alex" && child.location === "home") || Object.values(V.children).find(child => child.father === "Alex" && child.location === "home"))
{
} else {
delete C.npc.Alex.pregnancy.fee;
}
return true;
return validBirth;
}
DefineMacro("endPlayerPregnancy", endPlayerPregnancy);
window.endPlayerPregnancyTest = (birthLocation, location) => {
......@@ -395,6 +476,9 @@ function npcPregnancyCycle() {
case "wolf":
multiplier = 12 / V.wolfPregnancyWeeks;
break;
case "hawk":
multiplier = 1;
break;
}
pregnancy.timer += parseFloat(multiplier.toFixed(3));
if (pregnancy.timer > pregnancy.timerEnd * 0.2 && !pregnancy.npcAwareOf) {
......@@ -410,27 +494,25 @@ function npcPregnancyCycle() {
birthLocation = "wolf_cave";
location = "wolf_cave";
break;
case "Great Hawk":
birthLocation = "tower";
location = "tower";
break;
case "Alex":
if (!C.npc.Alex.pregnancy.missedBirth) {
C.npc.Alex.pregnancy.missedBirth = true;
C.npc.Alex.pregnancy.missedBirthCount = 1;
} else {
C.npc.Alex.pregnancy.missedBirth = true;
C.npc.Alex.pregnancy.missedBirthCount += 1;
}
if (C.npc.Alex.pregnancy.nursery === true) {
birthLocation = "alex_cottage";
location = "alex_cottage";
} else {
birthLocation = "alex_cottage";
location = "home";
}
break;
}
[birthLocation, location] = defaultBirthLocations(pregnancy.type, birthLocation, location);
......@@ -445,7 +527,9 @@ function npcPregnancyCycle() {
pregnancy.cycleDay++;
if (pregnancy.cycleDay >= pregnancy.cycleDaysTotal) {
pregnancy.cycleDay = 1;
} else if (between(pregnancy.cycleDay, pregnancy.cycleDangerousDay - 1, pregnancy.cycleDangerousDay + 1)) {
} else if (npcName === "Great Hawk" && pregnancy.cycleDay >= pregnancy.cycleDangerousDay) {
namedNpcPregnancyAttempt(npcName, true);
} else if (npcName !== "Great Hawk" && between(pregnancy.cycleDay, pregnancy.cycleDangerousDay - 1, pregnancy.cycleDangerousDay + 1)) {
namedNpcPregnancyAttempt(npcName);
}
} else {
......@@ -456,11 +540,9 @@ function npcPregnancyCycle() {
updateRecordedSperm("vagina", npcName, 1);
}
}
/* V.pregnancytype === "realistic" uses this function */
function namedNpcPregnancyAttempt(npcName) {
function namedNpcPregnancyAttempt(npcName, forcePregnancy = false) {
if (!C.npc[npcName] || C.npc[npcName].vagina === "none" || V.pregnancytype !== "realistic") return false;
const namedNpc = C.npc[npcName];
const pregnancy = namedNpc.pregnancy;
if (!pregnancy || !pregnancy.enabled || pregnancy.fetus.length) {
......@@ -468,12 +550,14 @@ function namedNpcPregnancyAttempt(npcName) {
return false;
}
const [trackedNPCs, spermArray] = spermObjectToArray(pregnancy.sperm, false);
const fertility = pregnancy.pills === "fertility" ? 0.8 : 1;
const contraceptive = pregnancy.pills === "contraceptive";
const baseChance = Math.floor((20 - V.baseNpcPregnancyChance) * fertility);
const rng = random(0, spermArray.length > baseChance ? spermArray.length : baseChance);
/* Works in a similar way to playerPregnancyAttempt */
const basePenalty = Math.floor((20 - V.baseNpcPregnancyChance) * fertility);
let rng = random(0, spermArray.length > basePenalty ? spermArray.length : basePenalty);
if (forcePregnancy && !spermArray[rng]) rng = 0;
if (contraceptive && random(0, 100) >= 10) {
/* NPC doesn't get pregnant due to contraceptive */
} else if (spermArray[rng]) {
......@@ -527,6 +611,26 @@ function namedNpcPregnancy(mother, father, fatherSpecies, fatherKnown = false, t
newPregnancy = pregnancyGenerator.wolf(mother, father, fatherKnown, "vagina", true);
backupSpermType = "wolf";
break;
case "humanhawk":
case "hawkhuman":
case "hawkhawk":
/* ToDo: Enable hawk pregnancy: Remove pregnancyTesting check */
if (V.pregnancyTesting) {
newPregnancy = pregnancyGenerator.hawk(mother, father, fatherKnown, "vagina", false);
backupSpermType = "hawk";
}
break;
case "humanharpy":
case "harpyhuman":
case "harpyhawk":
case "hawkharpy":
case "harpyharpy":
/* ToDo: Enable hawk pregnancy: Remove pregnancyTesting check */
if (V.pregnancyTesting) {
newPregnancy = pregnancyGenerator.hawk(mother, father, fatherKnown, "vagina", true);
backupSpermType = "hawk";
}
break;
}
if (newPregnancy && !(typeof newPregnancy === "string" || newPregnancy instanceof String) && newPregnancy.fetus.length) {
namedNpc.pregnancy = {
......@@ -554,18 +658,21 @@ function endNpcPregnancy(npcName, birthLocation, location) {
if (!pregnancy || pregnancy.enabled === undefined || !pregnancy.fetus.length) return false;
// Handled by Baileys Orphanage event and when naming them, this is backup for other situations
if (location !== "home" && pregnancy.fetus[0].mother !== "pc" && pregnancy.fetus[0].father === "pc") {
if (pregnancy.fetus[0].childId && location !== "home" && pregnancy.fetus[0].mother !== "pc" && pregnancy.fetus[0].father === "pc") {
document.getElementById("passages").children[0].append(Wikifier.wikifyEval('<<earnFeat "First Fatherhood">>'));
}
let validBirth;
if (pregnancy.fetus[0].childId) {
giveBirthToChildren(npcName, birthLocation, location);
validBirth = true;
}
giveBirthToChildren(npcName, birthLocation, location);
const birthEvents = clone(pregnancy.totalBirthEvents) + 1;
const birthEvents = clone(pregnancy.totalBirthEvents) + (validBirth ? 1 : 0);
const cycleDay = clone(pregnancy.cycleDaysTotal) - 3;
V.NPCName[V.NPCNameList.indexOf(npcName)].pregnancy = {
...pregnancy,
totalBirthEvents: (pregnancy.totalBirthEvents || 0) + 1,
totalBirthEvents: validBirth ? (pregnancy.totalBirthEvents || 0) + 1 : pregnancy.totalBirthEvents || 0,
fetus: [],
birthEvents,
timer: null,
......@@ -579,25 +686,21 @@ function endNpcPregnancy(npcName, birthLocation, location) {
};
if (npcName === "Alex") {
delete C.npc.Alex.pregnancy.knowledge;
delete C.npc.Alex.pregnancy.test;
delete C.npc.Alex.pregnancy.sample;
delete C.npc.Alex.pregnancy.selfKnowledge;
delete C.npc.Alex.pregnancy.noBirthControl;
C.npc.Alex.pregnancy.pills = "contraceptive";
C.npc.Alex.pregnancyAvoidance = 50;
C.npc.Alex.pregnancyAvoidance = 50;
if (Object.values(V.children).find(child => child.mother === "Alex" && child.location === "home") || Object.values(V.children).find(child => child.father === "Alex" && child.location === "home"))
{
if (Object.values(V.children).find(child => (child.mother === "Alex" || child.father === "Alex") && child.location === "home")) {
// Do Nothing
} else {
delete C.npc.Alex.pregnancy.fee;
}
}
V.pregnancyStats.npcTotalBirthEvents++;
return true;
if (validBirth) V.pregnancyStats.npcTotalBirthEvents++;
return validBirth;
}
DefineMacro("endNpcPregnancy", endNpcPregnancy);
window.endNpcPregnancyTest = (npcName, birthLocation, location) => {
......@@ -620,6 +723,9 @@ function randomPregnancyProgress() {
case "wolf":
multiplier = 12 / V.wolfPregnancyWeeks;
break;
case "hawk":
multiplier = 1;
break;
}
npc.pregnancy.timer += parseFloat(multiplier.toFixed(3));
if (npc.pregnancy.timer >= npc.pregnancy.timerEnd) {
......@@ -659,6 +765,10 @@ function defaultBirthLocations(type, birthLocation, location) {
if (!birthLocation) birthLocation = "wolf_cave";
if (!location) location = "wolf_cave";
break;
case "hawk":
if (!birthLocation) birthLocation = "tower";
if (!location) location = "tower";
break;
default: /* Considered an invalid location when the above is not updated */
if (!birthLocation) birthLocation = "unknown";
if (!location) location = "unknown";
......@@ -695,6 +805,9 @@ function giveBirthToChildren(mother, birthLocation, location, pregnancyOverride)
case "wolf_cave":
setKnowsAboutPregnancy(mother, "Black Wolf", birthId);
break;
case "tower":
setKnowsAboutPregnancy(mother, "Great Hawk", birthId);
break;
default:
break;
}
......@@ -706,13 +819,16 @@ function giveBirthToChildren(mother, birthLocation, location, pregnancyOverride)
case "wolf":
V.pregnancyStats.wolfToysUnlocked = true;
break;
case "hawk":
V.pregnancyStats.hawkToysUnlocked = true;
break;
}
pregnancy.fetus.forEach(childObject => {
pregnancy.givenBirth++;
V.children[childObject.childId] = {
...childObject,
name: generateBabyName(childObject.name, childObject.gender, childObject.childId),
name: !childObject.eggTimer ? generateBabyName(childObject.name, childObject.gender, childObject.childId) : "",
born: { day: clone(Time.monthDay), month: clone(Time.monthName), year: clone(Time.year) },
location,
birthLocation,
......@@ -731,6 +847,9 @@ function giveBirthToChildren(mother, birthLocation, location, pregnancyOverride)
case "wolf":
V.pregnancyStats.wolfChildren++;
break;
case "hawk":
V.pregnancyStats.hawkChildren++;
break;
}
});
return true;
......@@ -762,6 +881,7 @@ function recordSperm({
if (V.disableImpregnation) return false; // To be set at the start of sex scenes, unset with <<endcombat>>
if (V.playerPregnancyHumanDisable === "t" && spermType === "human" && target === "pc") return false; // Human player pregnancy disabled
if (V.playerPregnancyBeastDisable === "t" && spermType !== "human" && target === "pc") return false; // Beast player pregnancy disabled
if (V.playerPregnancyEggLayingDisable === "t" && ["hawk", "harpy"].includes(npcType)) return false; // Egg laying player pregnancy disabled
if (V.npcPregnancyDisable === "t" && target !== "pc") return false; // Npc pregnancy disabled
if (["realistic", "fetish"].includes(V.pregnancytype) && !["anus", "vagina"].includes(genital)) return null;
......@@ -990,8 +1110,9 @@ function playerPregnancyPossibleWith(NPC) {
case "wolf":
case "wolfboy":
case "wolfgirl":
// case "bird":
if (V.playerPregnancyBeastDisable === "t") {
case "hawk":
case "harpy":
if (V.playerPregnancyBeastDisable === "t" || (V.playerPregnancyEggLayingDisable === "t" && ["hawk", "harpy"].includes(NPCObject.type))) {
T.pregFalseReason = "pregnantDisabled";
return false;
} else break;
......
......@@ -38,7 +38,7 @@ function npcPregObject(person, mother) {
if (typeof person === "string" || person instanceof String) {
let parentId = parentFunction.findParent(person, parentType, true);
if (parentId === -1) {
parentId = addToParentList(person, undefined, parentType);
parentId = parentFunction.addToParentList(person, undefined, parentType);
}
if (person === "pc") {
// pregnancy isnt required for the player
......@@ -84,7 +84,7 @@ function npcPregObject(person, mother) {
if (person.fullDescription) {
let parentId = parentFunction.findParent(person.fullDescription, parentType, true);
if (parentId === -1) {
parentId = addToParentList(person.fullDescription, C.npc[person.fullDescription] ? undefined : person, parentType);
parentId = parentFunction.addToParentList(person.fullDescription, C.npc[person.fullDescription] ? undefined : person, parentType);
}
result = {
name: person.fullDescription,
......@@ -115,7 +115,7 @@ function npcPregObject(person, mother) {
}
// When adding new types, be sure to adjust related checks in other pregnancy code that check for "human","wolf","wolfboy","wolfgirl" etc
function pregPrep({ motherObject, fatherObject, parasiteType = null, genital = null }) {
function pregPrep({ motherObject, fatherObject, parasiteType = null, genital = null, override = null }) {
let pregnancy;
let fertility = 0;
let magicTattoo = 0;
......@@ -135,8 +135,10 @@ function pregPrep({ motherObject, fatherObject, parasiteType = null, genital = n
pregnancy = V.sexStats[genital].pregnancy;
// Prevent any pregnancy if a Non-parasitic pregnancy already exists
if (pregnancy.type !== "parasite" && pregnancy.fetus.length) return ["Player currently pregnant and cannot support other types"];
// Prevent any pregnancy if a Non-parasitic pregnancy already exists unless a specific override is provided
if (override === "hawk" && pregnancy.type === "hawk") {
if (pregnancy.fetus.length && pregnancy.fetus[0] && pregnancy.fetus[0].eggTimer) return ["Hawk eggs already fertilised"];
} else if (pregnancy.type !== "parasite" && pregnancy.fetus.length) return ["Player currently pregnant and cannot support other types"];
// Prevent any non-parasitic pregnancy a parasitic pregnancy already exists
if (pregnancy.type === "parasite" && !parasiteType) return ["Player currently pregnant with parasite and cannot support other types"];
......@@ -157,6 +159,12 @@ function pregPrep({ motherObject, fatherObject, parasiteType = null, genital = n
if (!pregnancy || !pregnancy.enabled) {
return ["Pregnancy not supported or disabled by the player"];
}
// Prevent any pregnancy if a Non-parasitic pregnancy already exists unless a specific override is provided
if (override === "hawk" && pregnancy.type === "hawk") {
if (pregnancy.fetus.length && pregnancy.fetus[0] && pregnancy.fetus[0].eggTimer) return ["Hawk eggs already fertilised"];
} else if (pregnancy.type !== "parasite" && pregnancy.fetus.length) return ["NPC currently pregnant and cannot support other types"];
if (pregnancy.pills === "fertility") {
fertility += 1;
}
......@@ -554,4 +562,60 @@ window.pregnancyGenerator = {
T.impregnatedParasite = null;
return false;
},
hawk: (mother, father, fatherKnown = false, genital = "vagina", monster = false) => {
// Hard coded limit
const limit = Object.values(V.children).length;
const motherObject = npcPregObject(mother, true);
let fatherObject;
if (father) fatherObject = npcPregObject(father);
const [pregnancy, fertility, magicTattoo] = pregPrep({ motherObject, genital, override: "hawk" });
if (typeof pregnancy === "string" || pregnancy instanceof String) return pregnancy;
if (pregnancy) {
const result = { fetus: [], type: "hawk", timer: 0, timerEnd: random(3, 6) };
let count;
if (mother === "pc") {
count = Math.clamp(V.harpyEggs, 0, 3);
} else {
count = random(1, 3);
}
if (!count) return false;
if (fertility || magicTattoo) count++;
const featherColour = ["white", "brown"];
for (let i = 0; i < count; i++) {
// Hard coded limit
if (limit + result.fetus.length >= 1000) return;
const childId =
"m" + motherObject.parentId.id + "b" + motherObject.parentId.kids + "d" + fatherObject.parentId.id + "f" + fatherObject.parentId.kids;
const birthId = motherObject.parentId.births;
let gender = random(0, 100) > 50 ? "f" : "m";
if ((motherObject.gender === "h" || fatherObject.gender === "h") && (motherObject.name === fatherObject.name || random(0, 100) >= 75))
gender = "h";
const baby = babyBase({
childId,
birthId,
mother: motherObject.name,
father: fatherObject.name,
fatherKnown,
type: "hawk",
monster: monster ? "monster" : 0,
gender,
size: bodySizeCalc(V.bodysize),
eyeColour: [eyeColourCalc(motherObject.name), eyeColourCalc(fatherObject.name)][random(0, 1)],
hairColour: featherColour[random(0, featherColour.length - 1)],
});
// Hours
baby.eggTimer = new DateTime(Time.date).addHours(random(24 * 26, 24 * 32)).timeStamp;
result.fetus.push(baby);
parentFunction.increaseKids(motherObject.parentId.id, 0, fatherObject.parentId.id);
}
return result;
}
return false;
},
};
......@@ -47,6 +47,9 @@ function playerBellySize(pregnancyOnly = false) {
case "wolf":
if (!vpregnancy.gaveBirth) maxSize += 20 + Math.clamp(vpregnancy.fetus.length / 2, 1, 4);
break;
case "hawk":
if (!vpregnancy.gaveBirth) maxSize += 7 + Math.clamp(vpregnancy.fetus.length, 1, 3);
break;
}
switch (apregnancy.type) {
case "parasite":
......@@ -58,6 +61,9 @@ function playerBellySize(pregnancyOnly = false) {
case "wolf":
if (!apregnancy.gaveBirth) maxSize += 20 + Math.clamp(apregnancy.fetus.length / 2, 1, 4);
break;
case "hawk":
if (!apregnancy.gaveBirth) maxSize += 7 + Math.clamp(apregnancy.fetus.length, 1, 3);
break;
}
// The '+ 5' inflates the pregnancy belly size, meaning that the early stages of pregnancy will have no belly size increase due to it being reduced by the '- 5'
bellySize += Math.clamp(pregnancyProgress * Math.clamp(maxSize + 5, 0, 24 + 5) - 5, 0, 24);
......@@ -92,6 +98,9 @@ function npcBellySize(npc) {
case "wolf":
maxSize += 20 + Math.clamp(pregnancy.fetus.length / 2, 1, 4);
break;
case "hawk":
maxSize += 8 + Math.clamp(pregnancy.fetus.length, 1, 3);
break;
}
// The '+ 5' inflates the pregnancy belly size, meaning that the early stages of pregnancy will have no belly size increase due to it being reduced by the '- 5'
bellySize += Math.clamp(pregnancyProgress * Math.clamp(maxSize + 5, 0, 24 + 5) - 5, 0, 24);
......@@ -165,7 +174,7 @@ window.playerNormalPregnancyType = playerNormalPregnancyType;
function wakingPregnancyEvent() {
const pregnancy = getPregnancyObject();
if (!pregnancy.fetus || V.statFreeze) return false;
if ((!V.player.vaginaExist && playerNormalPregnancyTotal() === 0) || pregnancy.type === "parasite") return false;
if ((!V.player.vaginaExist && playerNormalPregnancyTotal() === 0 && !playerIsPregnant()) || pregnancy.type === "parasite") return false;
const rng = random(0, 100);
const menstruation = V.sexStats.vagina.menstruation;
......@@ -256,7 +265,7 @@ window.wakingPregnancyEvent = wakingPregnancyEvent;
function dailyPregnancyEvent() {
const pregnancy = getPregnancyObject();
if (!pregnancy.fetus || V.statFreeze) return false;
if ((!V.player.vaginaExist && playerNormalPregnancyTotal() === 0) || pregnancy.type === "parasite") return false;
if ((!V.player.vaginaExist && playerNormalPregnancyTotal() === 0 && !playerIsPregnant()) || pregnancy.type === "parasite") return false;
const rng = random(0, 100) + (V.daily.pregnancyEvent || 0);
const menstruation = V.sexStats.vagina.menstruation;
......@@ -264,7 +273,9 @@ function dailyPregnancyEvent() {
const pregnancyStage = pregnancy.timerEnd ? Math.clamp(pregnancy.timer / pregnancy.timerEnd, 0, 1) : false;
let dailyEffects;
if ((between(pregnancyStage, 0.9, 0.95) && rng > 80) || (between(pregnancyStage, 0.95, 1) && rng >= 75)) {
if (pregnancy.gaveBirth) {
/* Show no events right after giving birth */
} else if ((between(pregnancyStage, 0.9, 0.95) && rng > 80) || (between(pregnancyStage, 0.95, 1) && rng >= 75)) {
dailyEffects = "nearBirthEvent";
} else if ((between(pregnancyStage, 0.7, 0.8) && rng > 85) || (between(pregnancyStage, 0.8, 0.9) && rng >= 80)) {
dailyEffects = "nearBirth";
......@@ -526,6 +537,8 @@ function pregnancyDaysEta(pregnancyObject) {
return Math.floor(timerLeft / (9 / V.humanPregnancyMonths));
case "wolf":
return Math.floor(timerLeft / (12 / V.wolfPregnancyWeeks));
case "hawk":
return Math.floor(timerLeft);
default:
return null;
}
......@@ -698,7 +711,7 @@ function knowsAboutAnyPregnancy(mother, whoToCheck) {
}
return !!Object.entries(V.pregnancyStats.awareOfBirthId)
.filter(awareOf => awareOf[0].includes(mother))
.find(awareOf => awareOf.includes(whoToCheckConverted));
.find(awareOf => awareOf[1].includes(whoToCheckConverted));
}
window.knowsAboutAnyPregnancy = knowsAboutAnyPregnancy;
......@@ -725,7 +738,13 @@ function knowsAboutChildrenTotal(motherOrFather, whoToCheck, location) {
}
window.knowsAboutChildrenTotal = knowsAboutChildrenTotal;
function childrenCountBetweenParents(parent1, parent2) {
function childrenCountBetweenParents(parent1, parent2, motherAndFather = false) {
if (motherAndFather) {
return Object.values(V.children).reduce((prev, curr) => {
if (curr.father !== curr.mother && [parent1].includes(curr.mother) && [parent2].includes(curr.father)) return prev + 1;
return prev;
}, 0);
}
return Object.values(V.children).reduce((prev, curr) => {
if (curr.father !== curr.mother && [parent1, parent2].includes(curr.mother) && [parent1, parent2].includes(curr.father)) return prev + 1;
return prev;
......@@ -733,7 +752,13 @@ function childrenCountBetweenParents(parent1, parent2) {
}
window.childrenCountBetweenParents = childrenCountBetweenParents;
function pregnancyCountBetweenParents(parent1, parent2) {
function pregnancyCountBetweenParents(parent1, parent2, motherAndFather = false) {
if (motherAndFather) {
return Object.values(V.children).reduce((prev, curr) => {
if (curr.father !== curr.mother && [parent1].includes(curr.mother) && [parent2].includes(curr.father)) prev.pushUnique(curr.mother + curr.birthId);
return prev;
}, []).length;
}
return Object.values(V.children).reduce((prev, curr) => {
if (curr.father !== curr.mother && [parent1, parent2].includes(curr.mother) && [parent1, parent2].includes(curr.father))
prev.pushUnique(curr.mother + curr.birthId);
......
......@@ -218,7 +218,6 @@ var IronMan = (Save => {
}
function exportSlot(slot = 8) {
updateExportDay();
const data = Save.slots.get(slot);
const saveId = data.metadata.saveId;
const saveName = data.metadata.saveName;
......@@ -232,7 +231,6 @@ var IronMan = (Save => {
*/
// eslint-disable-next-line no-unused-vars
function exportCurrent() {
updateExportDay();
Save.export();
}
......@@ -243,7 +241,6 @@ var IronMan = (Save => {
* @returns {string} Containing the encoded data.
*/
function exportDebug(slot) {
updateExportDay();
const data = Save.slots.get(slot);
const details = DoLSave.SaveDetails.get(slot);
if (data == null) {
......@@ -320,7 +317,6 @@ var IronMan = (Save => {
*/
function uiExportButton() {
const exportName = "degrees-of-lewdity" + (V.saveName !== "" ? "-" + V.saveName : "");
updateExportDay();
Save.export(exportName);
}
......
......@@ -98,31 +98,9 @@ function handleTouchMove(evt) {
yDown = null;
}
const disableNumberifyInVisibleElements = ["#passage-testing-room"];
// Number-ify links
window.Links = window.Links || {};
Links.currentLinks = [];
function getPrettyKeyNumber(counter) {
let str = "";
if (counter > 30) str = "Ctrl + ";
else if (counter > 20) str = "Alt + ";
else if (counter > 10) str = "Shift + ";
if (counter % 10 === 0) str += "0";
else if (counter < 10) str += counter;
else {
const c = Math.floor(counter / 10);
str += (counter - 10 * c).toString();
}
return str;
}
//Links.disableNumberifyInVisibleElements.push("#passage-testing-room");
$(document).on(":passagerender", function (ev) {
Links.currentLinks = [];
if (passage() === "GiveBirth") {
$(ev.content)
......@@ -132,48 +110,6 @@ $(document).on(":passagerender", function (ev) {
Links.generateLinkNumbers(ev.content);
});
}
Links.generateLinkNumbers(ev.content);
});
Links.keyNumberMatcher = /^\([^)]+\)/;
Links.generateLinkNumbers = content => {
if (!V.options.numberify_enabled || !StartConfig.enableLinkNumberify) return;
for (let i = 0; i < disableNumberifyInVisibleElements.length; i++) {
if ($(content).find(disableNumberifyInVisibleElements[i]).length || $(content).is(disableNumberifyInVisibleElements[i])) return; // simply skip this render
}
// wanted to use .macro-link, but wardrobe and something else doesn't get selected, lmao
Links.currentLinks = $(content).find(".link-internal").not(".no-numberify *, .no-numberify");
$(Links.currentLinks).each(function (i, el) {
if (Links.keyNumberMatcher.test(el.innerHTML)) {
el.innerHTML = el.innerHTML.replace(Links.keyNumberMatcher, `(${getPrettyKeyNumber(i + 1)})`);
} else {
$(el).html("(" + getPrettyKeyNumber(i + 1) + ") " + $(el).html());
}
});
};
Links.generate = () => Links.generateLinkNumbers(document.getElementsByClassName("passage")[0] || document);
$(document).on("keyup", function (ev) {
if (!V.options.numberify_enabled || !StartConfig.enableLinkNumberify || V.tempDisable) return;
if (document.activeElement.tagName === "INPUT" && document.activeElement.type !== "radio" && document.activeElement.type !== "checkbox") return;
if ((ev.keyCode >= 48 && ev.keyCode <= 57) || (ev.keyCode >= 96 && ev.keyCode <= 105)) {
const fixedKeyIndex = ev.keyCode < 60 ? ev.keyCode - 48 : ev.keyCode - 96;
let requestedLinkIndex = [9, 0, 1, 2, 3, 4, 5, 6, 7, 8][fixedKeyIndex];
if (ev.ctrlKey) requestedLinkIndex += 30;
else if (ev.altKey) requestedLinkIndex += 20;
else if (ev.shiftKey) requestedLinkIndex += 10;
if ($(Links.currentLinks).length >= requestedLinkIndex + 1) $(Links.currentLinks[requestedLinkIndex]).click();
}
});
function ensureIsArray(x, check = false) {
......@@ -728,20 +664,26 @@ function onInputChanged(func) {
window.onInputChanged = onInputChanged;
function closeOverlay() {
wikifier("journalNotesTextareaSave");
updateOptions();
delete T.currentOverlay;
delete V.tempDisable;
T.buttons.reset();
$("#customOverlay").addClass("hidden").parent().addClass("hidden");
}
window.closeOverlay = closeOverlay;
function journalNotesReplacer(name) {
return name.replace(/[^a-zA-Z0-9\u4e00-\u9fa5' _-]+/g, "");
}
window.journalNotesReplacer = journalNotesReplacer;
function updatehistorycontrols() {
// if undefined, initiate new variable based on engine config
if (V.options.maxStates === undefined) V.options.maxStates = Config.history.maxStates;
else Config.history.maxStates = V.options.maxStates; // update engine config
// option to only save active state into sessionStorage, for better performance
if (V.options.sessionHistory === undefined) V.options.sessionHistory = true; // todo: delete this line in 0.4.2.x
if (V.options.sessionHistory) Config.history.maxSessionStates = V.options.maxStates;
else Config.history.maxSessionStates = 1;
......@@ -820,3 +762,9 @@ window.loadCharacterViewerDate = () => {
textArea.value = "Invalid Import";
}
};
function returnTimeFormat() {
if (!V || !V.options) return "en-GB";
return V.options.dateFormat;
}
window.returnTimeFormat = returnTimeFormat;