Browse Source

Merge branch 'Development' into SC-Master

Stephan Fuchs 1 month ago
parent
commit
49fee5dca4
92 changed files with 583 additions and 425 deletions
  1. 2 1
      .gitignore
  2. 4 1
      .vscode/tasks.json
  3. 3 11
      glife.code-workspace
  4. 0 8
      mods/mod.html
  5. 3 0
      mods/util/BuildModFiles.bat
  6. 72 0
      mods/util/BuildModFiles.py
  7. 0 3
      mods/util/MakeMod.bat
  8. 0 35
      mods/util/MakeMod.py
  9. 0 3
      mods/util/MakeModableHtml.bat
  10. 0 21
      mods/util/MakeModableHtml.py
  11. 0 0
      sugarcube/devTools/tweeGo/storyFormats/sugarcube-2/format.js
  12. 4 5
      sugarcube/src/PassageFooter.tw
  13. 4 4
      sugarcube/src/PassageHeader.tw
  14. 3 0
      sugarcube/src/_myMod/myMod.tw
  15. 37 0
      sugarcube/src/activities/sex/sex_macro.ts
  16. 1 1
      sugarcube/src/activities/sex/widgets.tw
  17. 1 1
      sugarcube/src/activities/swim/swim.ts
  18. 1 1
      sugarcube/src/autogenerated/Gadyukino Characters/andreihunter.tw
  19. 1 1
      sugarcube/src/autogenerated/Gadyukino Characters/grigory.tw
  20. 1 1
      sugarcube/src/autogenerated/Gadyukino Characters/hunterLoveSex.tw
  21. 1 1
      sugarcube/src/autogenerated/Gadyukino Characters/hunter_ambient.tw
  22. 1 1
      sugarcube/src/autogenerated/Gadyukino Characters/hunter_favors.tw
  23. 1 1
      sugarcube/src/autogenerated/Gadyukino Characters/hunter_interactions.tw
  24. 1 1
      sugarcube/src/autogenerated/Gadyukino Characters/hunters.tw
  25. 1 1
      sugarcube/src/autogenerated/Gadyukino Characters/huntersex.tw
  26. 1 1
      sugarcube/src/autogenerated/Gadyukino Characters/igorhunter.tw
  27. 1 1
      sugarcube/src/autogenerated/Gadyukino Characters/mirafather.tw
  28. 1 1
      sugarcube/src/autogenerated/Gadyukino Characters/mirasex.tw
  29. 1 1
      sugarcube/src/autogenerated/Gadyukino Characters/miroslava.tw
  30. 1 1
      sugarcube/src/autogenerated/Gadyukino Characters/mitka.tw
  31. 1 1
      sugarcube/src/autogenerated/Gadyukino Characters/mitkabuh.tw
  32. 1 1
      sugarcube/src/autogenerated/Gadyukino Characters/mitkabuh_group.tw
  33. 1 1
      sugarcube/src/autogenerated/Gadyukino Characters/mitkasex.tw
  34. 1 1
      sugarcube/src/autogenerated/Gadyukino Characters/sergeihunter.tw
  35. 1 1
      sugarcube/src/autogenerated/Gadyukino Characters/swamp_woods.tw
  36. 1 1
      sugarcube/src/autogenerated/Gadyukino/backwater.tw
  37. 1 1
      sugarcube/src/autogenerated/Gadyukino/bicycle.tw
  38. 1 1
      sugarcube/src/autogenerated/Gadyukino/grandmahelp.tw
  39. 1 1
      sugarcube/src/autogenerated/Gadyukino/grandpahelp.tw
  40. 1 1
      sugarcube/src/autogenerated/Gadyukino/meadow.tw
  41. 1 1
      sugarcube/src/autogenerated/Gadyukino/miroslavahome.tw
  42. 1 1
      sugarcube/src/autogenerated/Gadyukino/swamp.tw
  43. 1 1
      sugarcube/src/autogenerated/Gadyukino/swamp_yard.tw
  44. 1 1
      sugarcube/src/autogenerated/Gadyukino/swamphouse.tw
  45. 1 1
      sugarcube/src/autogenerated/Gadyukino/swampspring.tw
  46. 5 0
      sugarcube/src/autogenerated/Stats/stat.tw
  47. 1 1
      sugarcube/src/autogenerated/Stimulus/dinSex2.tw
  48. 1 0
      sugarcube/src/events/_system/NavigationOverride.ts
  49. 3 0
      sugarcube/src/head.txt
  50. 30 7
      sugarcube/src/interfaces.d.ts
  51. 1 3
      sugarcube/src/js/prototypes/array/array_prototypes.js
  52. 3 0
      sugarcube/src/js/prototypes/array/getRandomWeighted.ts
  53. 4 0
      sugarcube/src/locations/_system/Location.ts
  54. 1 1
      sugarcube/src/locations/gadukino/gad_church.tw
  55. 1 1
      sugarcube/src/locations/gadukino/gadbana.tw
  56. 1 1
      sugarcube/src/locations/gadukino/gaddvor.tw
  57. 1 1
      sugarcube/src/locations/gadukino/gadfield.tw
  58. 1 1
      sugarcube/src/locations/gadukino/gadforest.tw
  59. 1 1
      sugarcube/src/locations/gadukino/gadforest_event.tw
  60. 1 1
      sugarcube/src/locations/gadukino/gadforestlost.tw
  61. 1 1
      sugarcube/src/locations/gadukino/gadgarden.tw
  62. 1 1
      sugarcube/src/locations/gadukino/gadhouse.tw
  63. 1 1
      sugarcube/src/locations/gadukino/gadmarket.tw
  64. 1 1
      sugarcube/src/locations/gadukino/gadprostitutes.tw
  65. 1 1
      sugarcube/src/locations/gadukino/gadriver.tw
  66. 1 1
      sugarcube/src/locations/gadukino/gadroad.tw
  67. 1 1
      sugarcube/src/locations/gadukino/gadsarai.tw
  68. 1 1
      sugarcube/src/locations/gadukino/gadukino.tw
  69. 1 1
      sugarcube/src/locations/gadukino/gadukino_event.tw
  70. 10 7
      sugarcube/src/locations/pavlov/brothel/abduction.tw
  71. 45 1
      sugarcube/src/locations/pavlov/brothel/brothel.ts
  72. 0 44
      sugarcube/src/locations/pavlov/brothel/brothel.tw
  73. 4 4
      sugarcube/src/locations/pavlov/brothel/hotel.tw
  74. 1 1
      sugarcube/src/locations/pavlov/brothel/reception.tw
  75. 4 0
      sugarcube/src/menu/Menu.tw
  76. 3 1
      sugarcube/src/menu/characterOverview/personality.tw
  77. 2 2
      sugarcube/src/npcs/_random/generate.ts
  78. 4 0
      sugarcube/src/npcs/_system/NPCsDict.ts
  79. 44 59
      sugarcube/src/playerCharacter/PlayerCharacter.ts
  80. 1 1
      sugarcube/src/playerCharacter/_submodules/pc_drugs.ts
  81. 1 1
      sugarcube/src/playerCharacter/personality/exhibitionism/exhibitionism.ts
  82. 16 0
      sugarcube/src/playerCharacter/personality/sexAbuseAverse/sexAbuseAverse.ts
  83. 14 5
      sugarcube/src/playerCharacter/skills/skills.ts
  84. 80 120
      sugarcube/src/quests/abduction/abduction.tw
  85. 41 0
      sugarcube/src/quests/abduction/scripts.ts
  86. 2 0
      sugarcube/src/settings/settings.ts
  87. 22 0
      sugarcube/src/start/index.tw
  88. 2 0
      sugarcube/src/start/scenario_selection.tw
  89. 2 0
      sugarcube/src/version/VersionControl.ts
  90. 22 23
      sugarcube/src/wardrobe/wardrobe.ts
  91. 2 2
      sugarcube_compile.bat
  92. 35 5
      sugarcube_postCompile.py

+ 2 - 1
.gitignore

@@ -45,7 +45,8 @@ glife.7z.tmp
 glife.7z
 
 *.test
-glife.html
+*.html
+*.php
 
 
 __pycache__/

+ 4 - 1
.vscode/tasks.json

@@ -56,7 +56,10 @@
 			"group": {
 				"kind": "build"
 			},
-			"problemMatcher": []
+			"problemMatcher": [],
+			"dependsOn": [
+				"MakeHTML"
+			]
 		},
 		{
 			"type": "typescript",

+ 3 - 11
glife.code-workspace

@@ -23,28 +23,20 @@
 				"filePath": "sugarcube_compile.bat",
 				"group": "Default"
 			},
-			{
-				"filePath": "sugarcube\\src\\npcs\\_system\\NPCsDict.js",
-				"group": "Default"
-			},
-			{
-				"filePath": "sugarcube\\src\\quests\\quests.js",
-				"group": "Default"
-			},
 			{
 				"filePath": "sugarcube\\src\\PassageFooter.tw",
 				"group": "Default"
 			},
 			{
-				"filePath": "sugarcube\\src\\playerCharacter\\mood\\moodlets.js",
+				"filePath": "sugarcube\\src\\macros\\0macros.twee-config.json",
 				"group": "Default"
 			},
 			{
-				"filePath": "sugarcube\\src\\macros\\0macros.twee-config.json",
+				"filePath": "sugarcube\\src\\playerCharacter\\PlayerCharacter.ts",
 				"group": "Default"
 			},
 			{
-				"filePath": "sugarcube\\src\\playerCharacter\\PlayerCharacter.ts",
+				"filePath": "sugarcube\\src\\npcs\\_system\\NPCsDict.ts",
 				"group": "Default"
 			}
 		]

+ 0 - 8
mods/mod.html

@@ -1,8 +0,0 @@
-<tw-passagedata pid="1680" name="intro_sg_select_char_after" tags="mod modExample" position="1225,20975" size="100,100">&lt;&lt;act &#39;Godess&#39;&gt;&gt;
-    &lt;&lt;gt &#39;modExample_intr_sg_select_godess&#39;&gt;&gt;
-&lt;&lt;/act&gt;&gt;</tw-passagedata>
-<tw-passagedata pid="1681" name="modExample_intr_sg_select_godess" tags="mod modExample" position="100,21100" size="100,100">&lt;h2&gt;Godess&lt;/h2&gt;
-	&lt;&lt;image &quot;system/1_openings/2_sg/nerd_0.jpg&quot;&gt;&gt;
-	&lt;p&gt;
-		Modded start.
-	&lt;/p&gt;</tw-passagedata>

+ 3 - 0
mods/util/BuildModFiles.bat

@@ -0,0 +1,3 @@
+@ECHO off
+
+Python -X utf8 mods/util/BuildModFiles.py

+ 72 - 0
mods/util/BuildModFiles.py

@@ -0,0 +1,72 @@
+#!/usr/bin/env python3
+import os
+import fileinput
+import re
+import sys
+
+
+modTag = "mod"
+
+file_path_html = 'glife.html'
+file_path_mod = 'mods'
+file_path_mod_online = 'mods'
+
+data = ''
+modData = {}
+scripts = {}
+dataWithoutModStuff = ''
+
+with open(file_path_html, 'r') as file:
+    data = file.read()
+
+dataWithoutModStuff = data
+
+i = 0
+regex = r"""<tw-passagedata pid="(\d+)" name="([\s\w]+)" tags="(.*?)" (?:position="\d+,\d+" )?(?:size="\d+,\d+")?>(.*?)</tw-passagedata>"""
+for match in re.finditer(regex,data,re.S):
+    tags = match.group(3).split()
+
+    if(modTag in tags):
+        modId = 'default'
+        for tag in tags:
+            if tag.startswith('mod_'):
+                modId = tag[4:]
+        if modId not in modData:
+            modData[modId] = ''    
+        modData[modId] += match.group(0)+'\n'
+        dataWithoutModStuff = dataWithoutModStuff.replace(match.group(0),'')
+
+    i += 1
+    if(i % 100 == 0):
+        print(i)
+
+regex = r"""/\*\s*Start Mod:\s*"([^"]*)"\s*\*/(.*?)/\*\s*End Mod:\s*"Mod"\s*\*/"""
+for match in re.finditer(regex,data,re.S):
+    modId = match.group(1).strip()
+    if not modId:
+        modId = 'default'
+    if modId not in scripts:
+        scripts[modId] = ''    
+    scripts[modId] += match.group(2)
+    dataWithoutModStuff = dataWithoutModStuff.replace(match.group(0),'')
+
+for modId, scriptContent in scripts.items():
+    if modId not in modData:
+        modData[modId] = ''  
+    modData[modId] += "\n.-.-.-. STORYDATA / SCRIPT .-.-.-.\n"
+    modData[modId] += scriptContent
+
+for modId, modContent in modData.items():
+    modPath = os.path.join(file_path_mod,modId+'.html')
+    with open(modPath, 'w') as file:
+        file.write(modContent)
+
+for modId, modContent in modData.items():
+    modPath = os.path.join(file_path_mod_online,modId+'.php')
+    with open(modPath, 'w') as file:
+        file.write(f'<?php header("Access-Control-Allow-Origin: *"); header(\'Content-type: text/javascript\'); echo($_GET[\'callback\']);?>(`{modContent}\n`);')
+
+with open(file_path_html, 'w') as file:
+    file.write(dataWithoutModStuff)
+
+print('Done')

+ 0 - 3
mods/util/MakeMod.bat

@@ -1,3 +0,0 @@
-@ECHO off
-
-Python -X utf8 mods/util/MakeMod.py

+ 0 - 35
mods/util/MakeMod.py

@@ -1,35 +0,0 @@
-#!/usr/bin/env python3
-import os
-import fileinput
-import re
-import sys
-
-
-modTag = "mod"
-
-file_path_html = 'glife.html'
-file_path_mod = 'mods/mod.html'
-
-data = ''
-modData = ''
-
-with open(file_path_html, 'r') as file:
-    data = file.read()
-
-i = 0
-regex = r"""<tw-passagedata pid="(\d+)" name="([\s\w]+)" tags="(.*?)" (?:position="\d+,\d+" )?(?:size="\d+,\d+")?>(.*?)</tw-passagedata>"""
-for match in re.finditer(regex,data,re.S):
-    tags = match.group(3).split()
-
-    if(modTag in tags):
-        modData += match.group(0)+'\n'
-    i += 1
-    if(i % 100 == 0):
-        print(i)
-
-
-
-with open(file_path_mod, 'w') as file:
-    file.write(modData)
-
-print('Done')

+ 0 - 3
mods/util/MakeModableHtml.bat

@@ -1,3 +0,0 @@
-@ECHO off
-
-Python -X utf8 mods/util/MakeModableHtml.py

+ 0 - 21
mods/util/MakeModableHtml.py

@@ -1,21 +0,0 @@
-#!/usr/bin/env python3
-import os
-import fileinput
-import re
-import sys
-
-file_path_html = 'glife.html'
-file_path_out = 'mods/modable_glife.html'
-
-data = ''
-with open(file_path_html, 'r') as file:
-    data = file.read()
-
-
-data = re.sub(r"""(<script id="script-sugarcube" type="text/javascript">)(.*?)(</script>)""",r"""\1$.ajax({  url: "mod.html",  cache: false})  .done(function( html ) {    $( "tw-storydata" ).append( html );\2});\3""",data,1, re.S)
-
-
-with open(file_path_out, 'w') as file:
-    file.write(data)
-
-print('Done')

File diff suppressed because it is too large
+ 0 - 0
sugarcube/devTools/tweeGo/storyFormats/sugarcube-2/format.js


+ 4 - 5
sugarcube/src/PassageFooter.tw

@@ -1,10 +1,9 @@
 :: PassageFooter
-
-<<if Story.has($here+'_after')>>
+/*<<if Story.has($here+'_after')>>
 	<<include `$here+'_after'`>>
-<</if>>
-<<set _afterPassages = Story.lookup("tags", $here+'_after')>>
-<<for _afterPassage range _afterPassages>>
+<</if>>*/
+<<for _afterPassage range Story.lookup("tags", $here+'_after')>>
+	<<run console.log('Included after-passage:',_afterPassage.title)>>
 	<<include _afterPassage.title>>
 <</for>>
 

+ 4 - 4
sugarcube/src/PassageHeader.tw

@@ -20,11 +20,11 @@
 <<include 'PassageHeaderAll'>>
 
 
-<<if Story.has($here+'_before')>>
-    <<include `$here+'_before'`>>
-<</if>>
+<<for _beforePassage range Story.lookup("tags", $here+'_before')>>
+	<<include _beforePassage.title>>
+<</for>>
 
-:: PassageHeaderAll
+:: PassageHeaderAll[include]
 <!-- Also exists for subpassages and if CLA was called -->
 <div id="connectedLocations"></div>
 <div id="messagesContainter">

+ 3 - 0
sugarcube/src/_myMod/myMod.tw

@@ -0,0 +1,3 @@
+:: mod_cheats_scripts[script]
+/* Start Mod: "Mod" */
+/* End Mod: "Mod" */

+ 37 - 0
sugarcube/src/activities/sex/sex_macro.ts

@@ -0,0 +1,37 @@
+const enum ESexEncounterFamiliarity{
+    LOVE="love",
+    FRIEND="friend",
+    ACQUAINTANCE="acquaintance",
+    STRANGER="stranger"
+}
+
+const enum ESexEncounterType {
+    VAGINAL="vaginal",
+    ANAL="anal",
+    BJ_GIVE="bj_give",
+    BJ_RECEIVE="bj_receive",
+    HJ_GIVE="hj_give",
+    HJ_RECEIVE="hj_receive"
+}
+
+Macro.add('sex', {
+	skipArgs : false,
+	handler  : function () {
+		try {
+			const pc = State.variables.pc;
+            const npcIdOrObject:NPC|string = this.args[0];
+            const flags:{[key:string]:any} = this.args[1] ?? {};
+
+            pc.sexEncounterRegister(
+                npcIdOrObject,
+                flags.type ?? ESexEncounterType.VAGINAL,
+                flags.fam ?? ESexEncounterFamiliarity.ACQUAINTANCE,
+                flags.aware ?? true,
+                flags.time ?? State.variables.time.now
+            )
+		}
+		catch (ex) {
+			return this.error('ERROR in sex-widget: ' + ex.message);
+		}
+	}
+});

+ 1 - 1
sugarcube/src/activities/sex/widgets.tw

@@ -1,4 +1,4 @@
-:: sex_widgets[widget]
+:: sex_widgets[deprecated]
 <<widget 'breakHymen'>>
     <<set $pc.pcs_vag = 1>>
 <</widget>>

+ 1 - 1
sugarcube/src/activities/swim/swim.ts

@@ -23,7 +23,7 @@ Macro.add('swim', {
 			jQuery(this.output).wiki(`<<mood 'swim' ${duration}>>`);
 		}
 		catch (ex) {
-			return this.error('ERROR in say-widget: ' + ex.message);
+			return this.error('ERROR in swim-widget: ' + ex.message);
 		}
 	}
 });

+ 1 - 1
sugarcube/src/autogenerated/Gadyukino Characters/andreihunter.tw

@@ -1,4 +1,4 @@
-:: andreihunter
+:: andreihunter[mod mod_gad]
 <<set $here = 'andreihunter'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- !2021/05/02-->

+ 1 - 1
sugarcube/src/autogenerated/Gadyukino Characters/grigory.tw

@@ -1,4 +1,4 @@
-:: grigory
+:: grigory[mod mod_gad]
 <<set $here = 'grigory'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- !2021/05/02-->

+ 1 - 1
sugarcube/src/autogenerated/Gadyukino Characters/hunterLoveSex.tw

@@ -1,4 +1,4 @@
-:: hunterLoveSex
+:: hunterLoveSex[mod mod_gad]
 <<set $here = 'hunterLoveSex'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- !2021/05/02-->

+ 1 - 1
sugarcube/src/autogenerated/Gadyukino Characters/hunter_ambient.tw

@@ -1,4 +1,4 @@
-:: hunter_ambient
+:: hunter_ambient[mod mod_gad]
 <<set $here = 'hunter_ambient'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- !Leaf conversation events-->

+ 1 - 1
sugarcube/src/autogenerated/Gadyukino Characters/hunter_favors.tw

@@ -1,4 +1,4 @@
-:: hunter_favors
+:: hunter_favors[mod mod_gad]
 <<set $here = 'hunter_favors'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- !2021/05/02-->

+ 1 - 1
sugarcube/src/autogenerated/Gadyukino Characters/hunter_interactions.tw

@@ -1,4 +1,4 @@
-:: hunter_interactions
+:: hunter_interactions[mod mod_gad]
 <<set $here = 'hunter_interactions'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- !2021/05/08-->

+ 1 - 1
sugarcube/src/autogenerated/Gadyukino Characters/hunters.tw

@@ -1,4 +1,4 @@
-:: hunters
+:: hunters[mod mod_gad]
 <<set $here = 'hunters'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- !!2022/05/06-->

+ 1 - 1
sugarcube/src/autogenerated/Gadyukino Characters/huntersex.tw

@@ -1,4 +1,4 @@
-:: huntersex
+:: huntersex[mod mod_gad]
 <<set $here = 'huntersex'>>
 <<set $ARGS = $location_var[$here]>>
 <<if $location_var[$here][0] == 'sexafterstrip1'>>

+ 1 - 1
sugarcube/src/autogenerated/Gadyukino Characters/igorhunter.tw

@@ -1,4 +1,4 @@
-:: igorhunter
+:: igorhunter[mod mod_gad]
 <<set $here = 'igorhunter'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- !2021/05/02-->

+ 1 - 1
sugarcube/src/autogenerated/Gadyukino Characters/mirafather.tw

@@ -1,4 +1,4 @@
-:: mirafather
+:: mirafather[mod mod_gad]
 <<set $here = 'mirafather'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- !2021/05/02-->

+ 1 - 1
sugarcube/src/autogenerated/Gadyukino Characters/mirasex.tw

@@ -1,4 +1,4 @@
-:: mirasex
+:: mirasex[mod mod_gad]
 <<set $here = 'mirasex'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- !2021/05/05-->

+ 1 - 1
sugarcube/src/autogenerated/Gadyukino Characters/miroslava.tw

@@ -1,4 +1,4 @@
-:: miroslava
+:: miroslava[mod mod_gad]
 <<set $here = 'miroslava'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- !2021/05/05-->

+ 1 - 1
sugarcube/src/autogenerated/Gadyukino Characters/mitka.tw

@@ -1,4 +1,4 @@
-:: mitka
+:: mitka[mod mod_gad]
 <<set $here = 'mitka'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- !2021/05/02-->

+ 1 - 1
sugarcube/src/autogenerated/Gadyukino Characters/mitkabuh.tw

@@ -1,4 +1,4 @@
-:: mitkabuh
+:: mitkabuh[mod mod_gad]
 <<set $here = 'mitkabuh'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- !2021/05/05-->

+ 1 - 1
sugarcube/src/autogenerated/Gadyukino Characters/mitkabuh_group.tw

@@ -1,4 +1,4 @@
-:: mitkabuh_group
+:: mitkabuh_group[mod mod_gad]
 <<set $here = 'mitkabuh_group'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- !2021/05/05-->

+ 1 - 1
sugarcube/src/autogenerated/Gadyukino Characters/mitkasex.tw

@@ -1,4 +1,4 @@
-:: mitkasex
+:: mitkasex[mod mod_gad]
 <<set $here = 'mitkasex'>>
 <<set $ARGS = $location_var[$here]>>
 <<set $menu_off = 1>>

+ 1 - 1
sugarcube/src/autogenerated/Gadyukino Characters/sergeihunter.tw

@@ -1,4 +1,4 @@
-:: sergeihunter
+:: sergeihunter[mod mod_gad]
 <<set $here = 'sergeihunter'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- !2021/05/02-->

+ 1 - 1
sugarcube/src/autogenerated/Gadyukino Characters/swamp_woods.tw

@@ -1,4 +1,4 @@
-:: swamp_woods
+:: swamp_woods[mod mod_gad]
 <<set $here = 'swamp_woods'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- !TODO: Break into more arg blocks-->

+ 1 - 1
sugarcube/src/autogenerated/Gadyukino/backwater.tw

@@ -1,4 +1,4 @@
-:: backwater
+:: backwater[mod mod_gad]
 <<set $here = 'backwater'>>
 <<set $ARGS = $location_var[$here]>>
 <<set $location_type = 'secluded'>>

+ 1 - 1
sugarcube/src/autogenerated/Gadyukino/bicycle.tw

@@ -1,4 +1,4 @@
-:: bicycle
+:: bicycle[mod mod_gad]
 <<set $here = 'bicycle'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- ! BikeLoc - tells us where bicycle is currently located-->

+ 1 - 1
sugarcube/src/autogenerated/Gadyukino/grandmahelp.tw

@@ -1,4 +1,4 @@
-:: grandmahelp
+:: grandmahelp[mod mod_gad]
 <<set $here = 'grandmahelp'>>
 <<set $ARGS = $location_var[$here]>>
 <<set $menu_off = 1>>

+ 1 - 1
sugarcube/src/autogenerated/Gadyukino/grandpahelp.tw

@@ -1,4 +1,4 @@
-:: grandpahelp
+:: grandpahelp[mod mod_gad]
 <<set $here = 'grandpahelp'>>
 <<set $ARGS = $location_var[$here]>>
 <<set $locclass to null>>

+ 1 - 1
sugarcube/src/autogenerated/Gadyukino/meadow.tw

@@ -1,4 +1,4 @@
-:: meadow
+:: meadow[mod mod_gad]
 <<set $here = 'meadow'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- !2021/05/05-->

+ 1 - 1
sugarcube/src/autogenerated/Gadyukino/miroslavahome.tw

@@ -1,4 +1,4 @@
-:: miroslavahome
+:: miroslavahome[mod mod_gad]
 <<set $here = 'miroslavahome'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- !2021/05/02-->

+ 1 - 1
sugarcube/src/autogenerated/Gadyukino/swamp.tw

@@ -1,4 +1,4 @@
-:: swamp
+:: swamp[mod mod_gad]
 <<set $here = 'swamp'>>
 <<set $ARGS = $location_var[$here]>>
 <<if $location_var[$here][0] == 'start'>>

+ 1 - 1
sugarcube/src/autogenerated/Gadyukino/swamp_yard.tw

@@ -1,4 +1,4 @@
-:: swamp_yard
+:: swamp_yard[mod mod_gad]
 <<set $here = 'swamp_yard'>>
 <<set $ARGS = $location_var[$here]>>
 <<gs 'hunter_ambient' 'schedule'>>

+ 1 - 1
sugarcube/src/autogenerated/Gadyukino/swamphouse.tw

@@ -1,4 +1,4 @@
-:: swamphouse
+:: swamphouse[mod mod_gad]
 <<set $here = 'swamphouse'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- !2021/05/02-->

+ 1 - 1
sugarcube/src/autogenerated/Gadyukino/swampspring.tw

@@ -1,4 +1,4 @@
-:: swampspring
+:: swampspring[mod mod_gad]
 <<set $here = 'swampspring'>>
 <<set $ARGS = $location_var[$here]>>
 <<set $loc = 'swampspring'>>

+ 5 - 0
sugarcube/src/autogenerated/Stats/stat.tw

@@ -1232,5 +1232,10 @@
 			<<set $bimbolevel = 0>>
 
 		<</if>>
+
+	<<for _afterPassage range Story.lookup("tags", 'stat_15minutes_changes_after')>>
+		<<include _afterPassage.title>>
+	<</for>>
+	
 <!-- END: stat_15minutes_changes -->
  */

+ 1 - 1
sugarcube/src/autogenerated/Stimulus/dinSex2.tw

@@ -81,7 +81,7 @@
 		<<else>>
 			<p>You feel the dildo penetrating your pussy. Between your legs feels nice, but the <<=_dildoData.length>>&nbsp;cm dildo is a bit too small for your pussy. Gradually, a warm and throbbing feeling grows in your lower abdomen, then the feeling slightly subsides and remains steady until the end _menstruationMessage.</p>
 		<</if>>
-		<<insertionEffectApply _insertionEffect>>
+		/*<<insertionEffectApply _insertionEffect>>*/
 		<<arouse 'vaginal_dildo' _sexLength _sexflags _dildoId>>
 	<</if>>
 :: dinSex2_old

+ 1 - 0
sugarcube/src/events/_system/NavigationOverride.ts

@@ -11,6 +11,7 @@ setup.navigationOverride = (destinationPassageName:string)=>{
 		!requestedLocation.tags.includesAny(tagsWithEventsDisabled)
 	){
 		State.variables.eventReturnLocation = requestedLocation;
+		State.variables.location.locationIdentifier = requestedLocation;
 		return 'event';
 	}
 }

+ 3 - 0
sugarcube/src/head.txt

@@ -0,0 +1,3 @@
+<meta name="rating" content="adult" />
+<meta name="author" content="Stephan Fuchs">
+<meta name="robots" content="nofollow" />

+ 30 - 7
sugarcube/src/interfaces.d.ts

@@ -68,7 +68,7 @@ declare module "twine-sugarcube" {
 		executeESCLocation:()=>void;
 		filterDict:<T extends {}>(obj:T,filter: Filter) => T;
 		func: (passage: string, ...arguments: Array<string|number>)=>any;
-		generateNPC:(dict:NPCsDict,purpose:string,flags:NPCGenerateOptions)=>string;
+		generateNPC:(dict:NPCsDict,purpose:string,flags:NPCGenerateOptions)=>NPC;
 		getActionTemplate:(id:string)=>ActionTemplate;
 		getBodyparts:()=> {[key: string]:BodypartDefinition };
 		getBodypart:(bodypartId:string)=>BodypartDefinition;
@@ -178,6 +178,7 @@ declare module "twine-sugarcube" {
 		location_var: object;
 		locationTravelRequest?:LocationTravelRequest;
 		media_path: string;
+		modVars:any;
 		quest: (id:string)=>Quest;
 		result: number | string;
 		/**
@@ -203,6 +204,7 @@ declare module "twine-sugarcube" {
 
 declare global {
 	export interface Array<T>{
+		getRandomWeighted(): T;
 		fancyMathEvaluate(): number;
 		filterByObject(filter: object): Array<T>;
 
@@ -855,7 +857,7 @@ declare global {
 		openTimes?:TimespanIdentifier;
 	}
 
-	export type NPC = NPCAccessor & Character;
+	export type NPC = NPCAccessor & Character & {[key:string]:any};
 
 	export interface NPCActivity{
 		location:string;
@@ -916,7 +918,7 @@ declare global {
 
 		generators?:string[];
 
-		fields?:{[key:string]:any};
+		fields?:{gender?:EGender} & {[key:string]:any};
 
 		vars?:{[key:string]:any};
 	}
@@ -1105,18 +1107,39 @@ declare global {
 		[priority:number]:GameEvent
 	}
 
-	export interface SexStatistics{
+	export interface SexEncounter{
+		
+		/**
+		 * The ID of the npc Sveta had sex with. If she has sex with more than one character (e.g. threesome) an encounter has to be created for each of them.
+		 * @type {string}
+		 */
+		npcId: string,
+		time:Date,
+		types: ESexEncounterType[],
+		/**
+		 * Is Sveta aware of the sex-act? False in case of hypnosis, blackouts, etc.
+		 * @type {boolean}
+		 */
+		aware: boolean,
+		/*civ: Cum in vagina
+		civa:Cum in vagina aware*/
+		tags: string[]
+	}
+
+	export interface SexStatistics{/*
 		bj:SexStatistic;
 		hj:SexStatistic;
 		vaginal:SexStatistic;
-		anal:SexStatistic;
+		anal:SexStatistic;*/
+		[key:string]: SexStatistic
 	}
 
 	export interface SexStatistic{
-		love:number[];
+		/*love:number[];
 		friend:number[];
 		acquaintance:number[];
-		stranger:number[];
+		stranger:number[];*/
+		[key:string]: number[]
 	}
 
 	export interface SkillDefinition{

+ 1 - 3
sugarcube/src/js/prototypes/array/array_prototypes.js

@@ -38,9 +38,7 @@ Array.prototype.filterByObject ??= function(filter){
 	return result;
 }
 
-Array.prototype.getRandomWeighted = function(flags={}){
-	return this[this.getRandomWeightedId(flags)];
-}
+
 
 Array.prototype.getRandomWeightedId = function(flags={}){
 	if(flags.isKeyValuePair){

+ 3 - 0
sugarcube/src/js/prototypes/array/getRandomWeighted.ts

@@ -0,0 +1,3 @@
+Array.prototype.getRandomWeighted = function(flags={}){
+	return this[this.getRandomWeightedId(flags)];
+}

+ 4 - 0
sugarcube/src/locations/_system/Location.ts

@@ -16,6 +16,10 @@ class GameLocation{
 		return new LocationIdentifier(this.passage,this.passageArguments);
 	}
 
+	set locationIdentifier(v:LocationIdentifier){
+		this.update(v.passage,v.passageArguments);
+	}
+
 	get passage(){return this._passage;}
 	set passage(v:string){
 		if(typeof v != "string")

+ 1 - 1
sugarcube/src/locations/gadukino/gad_church.tw

@@ -1,4 +1,4 @@
-:: gad_church
+:: gad_church[mod mod_gad]
 <<set $here = 'gad_church'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- !2021/05/04-->

+ 1 - 1
sugarcube/src/locations/gadukino/gadbana.tw

@@ -1,4 +1,4 @@
-:: Gadbana
+:: Gadbana[mod mod_gad]
 <<set $here = 'Gadbana'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- !2021/05/05-->

+ 1 - 1
sugarcube/src/locations/gadukino/gaddvor.tw

@@ -1,4 +1,4 @@
-:: gaddvor
+:: gaddvor[mod mod_gad]
 <<set $here = 'gaddvor'>>
 <<set $ARGS = $location_var[$here]>>
 <<if !$location_var[$here][0]>>

+ 1 - 1
sugarcube/src/locations/gadukino/gadfield.tw

@@ -1,4 +1,4 @@
-:: gadfield
+:: gadfield[mod mod_gad]
 <<set $here = 'gadfield'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- !2021/05/05-->

+ 1 - 1
sugarcube/src/locations/gadukino/gadforest.tw

@@ -1,4 +1,4 @@
-:: gadforest
+:: gadforest[mod mod_gad]
 <<set $here = 'gadforest'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- !2021/05/05-->

+ 1 - 1
sugarcube/src/locations/gadukino/gadforest_event.tw

@@ -1,4 +1,4 @@
-:: gadforest_event
+:: gadforest_event[mod mod_gad]
 <<set $here = 'gadforest_event'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- !2021/05/05-->

+ 1 - 1
sugarcube/src/locations/gadukino/gadforestlost.tw

@@ -1,4 +1,4 @@
-:: gadforestlost
+:: gadforestlost[mod mod_gad]
 <<set $here = 'gadforestlost'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- ! this file holds all the current code and events for player when lost-->

+ 1 - 1
sugarcube/src/locations/gadukino/gadgarden.tw

@@ -1,4 +1,4 @@
-:: gadgarden
+:: gadgarden[mod mod_gad]
 <<set $here = 'gadgarden'>>
 <<set $ARGS = $location_var[$here]>>
 <<if $location_var[$here][0] == 'garden'>>

+ 1 - 1
sugarcube/src/locations/gadukino/gadhouse.tw

@@ -1,4 +1,4 @@
-:: gadhouse
+:: gadhouse[mod mod_gad]
 <<set $here = 'gadhouse'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- !! VARIABLE LIST FOR GRANDPARENTS AND THEIR CHORES - START-->

+ 1 - 1
sugarcube/src/locations/gadukino/gadmarket.tw

@@ -1,4 +1,4 @@
-:: gadmarket
+:: gadmarket[mod mod_gad]
 <<set $here = 'gadmarket'>>
 <<set $ARGS = $location_var[$here]>>
 <<set $loc = 'gadmarket'>>

+ 1 - 1
sugarcube/src/locations/gadukino/gadprostitutes.tw

@@ -1,4 +1,4 @@
-:: gadprostitutes
+:: gadprostitutes[mod mod_gad]
 <<set $here = 'gadprostitutes'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- !2021/05/05-->

+ 1 - 1
sugarcube/src/locations/gadukino/gadriver.tw

@@ -1,4 +1,4 @@
-:: gadriver
+:: gadriver[mod mod_gad]
 <<set $here = 'gadriver'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- !!2022/05/02-->

+ 1 - 1
sugarcube/src/locations/gadukino/gadroad.tw

@@ -1,4 +1,4 @@
-:: gadroad
+:: gadroad[mod mod_gad]
 <<set $here = 'gadroad'>>
 <<set $ARGS = $location_var[$here]>>
 <<if !$location_var[$here][0]>>

+ 1 - 1
sugarcube/src/locations/gadukino/gadsarai.tw

@@ -1,4 +1,4 @@
-:: gadsarai
+:: gadsarai[mod mod_gad]
 <<set $here = 'gadsarai'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- !2021/05/08-->

+ 1 - 1
sugarcube/src/locations/gadukino/gadukino.tw

@@ -1,4 +1,4 @@
-:: gadukino
+:: gadukino[mod mod_gad]
 <<set $here = 'gadukino'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- !!2022/05/02-->

+ 1 - 1
sugarcube/src/locations/gadukino/gadukino_event.tw

@@ -1,4 +1,4 @@
-:: gadukino_event
+:: gadukino_event[mod mod_gad]
 <<set $here = 'gadukino_event'>>
 <<set $ARGS = $location_var[$here]>>
 <!-- !!2022/05/06-->

+ 10 - 7
sugarcube/src/locations/pavlov/brothel/abduction.tw

@@ -7,7 +7,7 @@
 		<<image "locations/shared/brothel/roombedtied.jpg">>
 		<<npc 'brothel_bar' undefined 'The barman'>><</npc>> drops you on the bed face down, stripped you and tied your hands and feet to the corners of the bed.
 		You are barely able to resist, giving minimal resistance to your aggressor.
-		<<say 'brothel_bar' '"Ha slut! Now you will get another drink from me, the freshest one!"'>>
+		<<say 'brothel_bar' "Ha slut! Now you will get another drink from me, the freshest one!">>
 		<<act 'Continue'>>
 			<<gt 'brothel_abduction' '1'>>
 		<</act>>
@@ -17,12 +17,12 @@
 		<<say 'Ouch! It... hurts... Ouch!'>> The pain forces you back to a brief, conscious moment.
 		<<pain 'asshole' 10>>
 		Aroused with your reaction, he pushes his finger into your pussy, one by one until there are four of them inside.
-		<<arousal 'vaginal_finger' `{fetishes:['rape'],orgasm:false}`>>
+		/*<<arousal 'vaginal_finger' `{fetishes:['rape'],orgasm:false}`>>*/
 		<<if $pc.horny >= 40>>
 			<<say 'brothel_bar' 'What a whore! She\'s already wet!'>>
 		<</if>>
 		He uses the juiced fingers and thrusts them into your anus, once again forcing you back to the living world.
-		<<arousal 'anal_finger' `{fetishes:['rape'],orgasm:false}`>>
+		/*<<arousal 'anal_finger' `{fetishes:['rape'],orgasm:false}`>>*/
 		<<say 'Auuuuuuu!'>> you wriggle in a cramp, feeling the sharp pain in your anus.
 		
 		
@@ -38,7 +38,7 @@
 		...and then forces it into your anus as far as it goes, while the sparkling wine gushes out deep into your intestines.
 		<<say '"Ayyyieeee!"'>> Again you scream aloud, shaking both in surprise and pain.
 		<<pain 'rectum' 40>>
-		<<arouse 'anal_dildo' 5 >>
+		/*<<arouse 'anal_dildo' 5 >>*/
 		
 		<<act 'Continue'>>
 			<<gt 'brothel_abduction' '3'>>
@@ -51,8 +51,11 @@
 		He cleans your ass from the remains of whatever little was inside.
 		His dick is not the biggest one, but it is quite thick.
 		Your pussy is the first victim of his phallus, and after a short while he moves to your anus.
+
+		<<sex 'brothel_bar' `{type:['vaginal','anal']}`>>
+
 		Another jolt of pain runs through your bottom, but this time you fade away for sure...
-		<<set $anal_slip += 4>>
+		/*<<set $anal_slip += 4>>
 		<<set $guy += 4>>
 		<<set $temp = 4>>
 		<<set $sexpartkno = 0>>
@@ -66,7 +69,7 @@
 
 		<<set $rape += 1>>
 		<<set $gang += 1>>
-		<<set $orgasm_or = ''>>
+		<<set $orgasm_or = ''>>*/
 		<<act 'Continue'>>
 			<<gt 'brothel_abduction' '4'>>
 		<</act>>
@@ -127,7 +130,7 @@
 
 		<<quest 'brothel' 0>>
 
-		<<actCLA 'Admit that you somehow liked it as you fancy to be dominated' undefined `{willpower:['misc','self','hard']}`>>
+		<<actCLA 'Admit that you somehow liked it as you fancy to be dominated' undefined `{personality:{sexAbuseAverse:{impact:10,max:0}}}`>>
 			<<gt 'brothel_abduction' 'like'>>
 		<</actCLA>>
 

+ 45 - 1
sugarcube/src/locations/pavlov/brothel/brothel.ts

@@ -1,4 +1,6 @@
 /// <reference path="../../../items/consumables/consumableMenus.ts" />
+/// <reference path="../../../npcs/_system/NPCAccessor.ts" />
+
 
 setup.consumableMenus.brothel = {
     payment:'both',
@@ -21,4 +23,46 @@ setup.consumableMenus.brothel = {
             }
         },
     }
-};
+};
+
+setup.npcs["brothel_bar"] = {
+	firstname:'Mirchik',
+	lastname:'Zhukov',
+	usedname:'The barman',
+	notes:'The barman of the hotel near the main road of Pavlovsk',
+	hotcat_rating:6,
+	intel:60,
+	defaults:['defaults'],
+	//nameknown: false,
+	rel: 50,
+	image: 'locations/shared/brothel/barman.jpg',
+	gender:EGender.MALE
+}
+
+setup.npcs["brothel_rec"] = {
+	firstname:'Nikolai',
+	lastname:'Zhukov',
+	usedname:'Receptionist',
+	notes:'',
+	hotcat_rating:4,
+	intel:70,
+	defaults:['defaults'],
+	//nameknown: false,
+	rel: 50,
+	image: 'locations/shared/brothel/receptionist.jpg',
+	gender:0
+}
+
+setup.npcs["brothel_sec"] = {
+	firstname:'Kristian',
+	lastname:'Chomski',
+	usedname:'Bouncer',
+	notes:'',
+	hotcat_rating:9,
+	intel:60,
+	defaults:['defaults'],
+	//nameknown: false,
+	rel: 50,
+	image: 'locations/shared/brothel/bouncer.jpg',
+	gender:0
+}

+ 0 - 44
sugarcube/src/locations/pavlov/brothel/brothel.tw

@@ -1,47 +1,3 @@
-:: brothel_scripts[script]
-setup.npcs ??= {};
-setup.npcs["brothel_bar"] = {
-	firstname:'Mirchik',
-	lastname:'Zhukov',
-	usedname:'The barman',
-	notes:'The barman of the hotel near the main road of Pavlovsk',
-	hotcat_rating:6,
-	intel:60,
-	defaults:['defaults'],
-	nameknown: false,
-	rel: 50,
-	image: 'locations/shared/brothel/barman.jpg',
-	gender:0
-}
-
-setup.npcs["brothel_rec"] = {
-	firstname:'Nikolai',
-	lastname:'Zhukov',
-	usedname:'Receptionist',
-	notes:'',
-	hotcat_rating:4,
-	intel:70,
-	defaults:['defaults'],
-	nameknown: false,
-	rel: 50,
-	image: 'locations/shared/brothel/receptionist.jpg',
-	gender:0
-}
-
-setup.npcs["brothel_sec"] = {
-	firstname:'Kristian',
-	lastname:'Chomski',
-	usedname:'Bouncer',
-	notes:'',
-	hotcat_rating:9,
-	intel:60,
-	defaults:['defaults'],
-	nameknown: false,
-	rel: 50,
-	image: 'locations/shared/brothel/bouncer.jpg',
-	gender:0
-}
-
 :: brothel_deprecated[deprecated]
 <<set $here = 'brothel'>>
 <<set $ARGS = $location_var[$here]>>

+ 4 - 4
sugarcube/src/locations/pavlov/brothel/hotel.tw

@@ -7,10 +7,10 @@
 		Next to a bar are doors leading to a toilet.
 		Alongside the windows are tables, each for about four to six people.
 	</p>
-	<<ConnectedLocation 'Leave' 'road' 20 'locations/highway/road.jpg' 5>>
-	<<ConnectedLocation 'Reception' 'brothel_reception' '' 'locations/shared/brothel/hotelreception.jpg' 1>>
-	<<ConnectedLocation 'Bar' 'brothel_bar' '' 'locations/shared/brothel/bar.jpg' 1>>
-	<<ConnectedLocation 'Bathroom' 'brothel_toilet' '' 'locations/shared/brothel/hoteltoilet.jpg' 1>>
+	<<ConnectedLocation 'Leave' 'road' 20 'locations/highway/road.jpg' 5 `{priority:1000}`>>
+	<<ConnectedLocation 'Reception' 'brothel_reception' '' 'locations/shared/brothel/hotelreception.jpg' 1 `{priority:500}`>>
+	<<ConnectedLocation 'Bar' 'brothel_bar' '' 'locations/shared/brothel/bar.jpg' 1 `{priority:500}`>>
+	<<ConnectedLocation 'Bathroom' 'brothel_toilet' '' 'locations/shared/brothel/hoteltoilet.jpg' 1 `{priority:100}`>>
 
 :: brothel_reception[public indoors]
 	<<ConnectedLocation 'Lobby' 'brothel' '' 'locations/shared/brothel/hotellobby.jpg' 1>>

+ 1 - 1
sugarcube/src/locations/pavlov/brothel/reception.tw

@@ -192,7 +192,7 @@
 						<p>
 							<<say 'brothel_rec' 'Have you met Natalia?'>>
 							<<npc 'brothel_rec' undefined 'The receptionist'>><</npc>> points at the slave.
-							<<say 'brothel_rec' 'She is my daughter. At least from a genetic point of few. You see, some years ago, I squirted some cum into a dirty slave. Nine months later, this one was placed in front of an orphanarium. Now that she is an adult, I thought, she might be interested in getting to know her daddy. So now we\'re spending some quality time together.'>>
+							<<say 'brothel_rec' 'She is my daughter. At least from a genetic point of view. You see, some years ago, I squirted some cum into a dirty slave. Nine months later, this one was placed in front of an orphanarium. Now that she is an adult, I thought, she might be interested in getting to know her daddy. So now we\'re spending some quality time together.'>>
 						</p>
 						<<actCLA 'Is she fine with this?'>>
 							<<image "locations/shared/brothel/receptionist_art.jpg">>

+ 4 - 0
sugarcube/src/menu/Menu.tw

@@ -70,6 +70,10 @@
 			<li><<radiobutton "$settings.autosave" "NONE" autocheck>> Never autosave.</li>
 		</ul>
 	</p>
+    <p>
+        <<set $settings.maxStates ??= Config.history.maxStates>>
+        History: <<attr 'min' 1 'max' 100>><<numberbox '$settings.maxStates' $settings.maxStates>><</attr>>
+    </p>
 	<p>
 		[[Achievements|AchievementsOverview]]
 	</p>

+ 3 - 1
sugarcube/src/menu/characterOverview/personality.tw

@@ -5,5 +5,7 @@
 
     <<for _scaleId, _scale range $pc.personalityScales>>
         <h3>_scale.label</h3>
-        _scale.current
+        <<image _scale.image>>
+        <p>_scale.current</p>
+        <p>_scale.desc</p>
     <</for>>

+ 2 - 2
sugarcube/src/npcs/_random/generate.ts

@@ -1,4 +1,4 @@
-setup.generateNPC = function(dict:NPCsDict,purpose:string,flags:NPCGenerateOptions):string{
+setup.generateNPC = function(dict:NPCsDict,purpose:string,flags:NPCGenerateOptions):NPC{
 	const npcId = dict.create(purpose);
 	const npc = dict.npc(npcId);
 
@@ -15,7 +15,7 @@ setup.generateNPC = function(dict:NPCsDict,purpose:string,flags:NPCGenerateOptio
 
 	for(const [fieldKey,fieldValue] of Object.entries(flags.fields ?? {}))
 		npc[fieldKey] = fieldValue;
-	return npcId;
+	return npc;
 }
 
 setup.npcGenerators = {};

+ 4 - 0
sugarcube/src/npcs/_system/NPCsDict.ts

@@ -79,6 +79,10 @@ class NPCsDict{
 		delete this._dynamicData[npcID];
 		this._generatedIds.delete(npcID);
 	}
+
+	generate(purpose:string,flags:NPCGenerateOptions):NPC{
+		return setup.generateNPC(this,purpose,flags);
+	}
 	
     /**
 	 * Get a value of a field for a NPC.

+ 44 - 59
sugarcube/src/playerCharacter/PlayerCharacter.ts

@@ -808,10 +808,10 @@ class PlayerCharacter implements Character{
 	//#region Drugs
 		_drugs = new setup.Drugs();
 
-		get drugsActiveEffects(){return this._drugs.activeEffects}
+		get drugsActiveEffects():{[key: string]:Effect}{return this._drugs.activeEffects}
 		get drugsActiveEffectIds(){return this._drugs.activeEffectIds}
 		drugsDeteriorate(minutes){return this._drugs.deteriorate(minutes)}
-		drugVolInc(drugId, inc){return this._drugs.volInc(drugId, inc)}
+		drugVolInc(drugId:string, inc:number){return this._drugs.volInc(drugId, inc)}
 		drugVolSet(drugId,v){return this._drugs.volSet(drugId, v)}
 		drugVol(drugId){return this._drugs.vol(drugId)}
 
@@ -1660,50 +1660,25 @@ class PlayerCharacter implements Character{
 
 	//#region Sex-Stats
 
-		_sexStatistics:SexStatistics = {
-			bj: {
-				love: [0,0],
-				friend: [0,0],
-				acquaintance: [0,0],
-				stranger: [0,0]
-			},
-			hj: {
-				love: [0,0],
-				friend: [0,0],
-				acquaintance: [0,0],
-				stranger: [0,0]
-			},
-			vaginal: {
-				love: [0,0],
-				friend: [0,0],
-				acquaintance: [0,0],
-				stranger: [0,0]
-			},
-			anal: {
-				love: [0,0],
-				friend: [0,0],
-				acquaintance: [0,0],
-				stranger: [0,0]
-			}
-		}
-
-		sexStatistic(activity:string|string[],familiarity:string|string[],awareness:('aware'|'unaware'|'both')):number{
+		_sexStatistics:SexStatistics = {};
+
+		sexStatistic(activity:ESexEncounterType|ESexEncounterType[],familiarity:ESexEncounterFamiliarity|ESexEncounterFamiliarity[],awareness:('aware'|'unaware'|'both')):number{
 			let result = 0;
 
 			if(!activity)
-				activity = Object.keys(this._sexStatistics);
+				activity = Object.keys(this._sexStatistics) as ESexEncounterType[];
 			else if(!Array.isArray(activity))
 				activity = [activity];
 
 			if(!familiarity)
-				familiarity = Object.keys(Object.values(this._sexStatistics)[0]);
+				familiarity = [ESexEncounterFamiliarity.ACQUAINTANCE,ESexEncounterFamiliarity.FRIEND,ESexEncounterFamiliarity.LOVE,ESexEncounterFamiliarity.STRANGER];
 			else if(!Array.isArray(familiarity))
 				familiarity = [familiarity];
 
 			for(const activityKey of activity){
-				const activityData:SexStatistic = this._sexStatistics[activityKey];
+				const activityData:SexStatistic = this._sexStatistics[activityKey] ?? {};
 				for(const familiarityKey of familiarity){
-					const familiarityData = activityData[familiarityKey];
+					const familiarityData = activityData[familiarityKey] ?? [0,0];
 					switch(awareness){
 						case "aware":	result += familiarityData[0]; continue;
 						case "unaware":	result += familiarityData[1]; continue;
@@ -1722,42 +1697,46 @@ class PlayerCharacter implements Character{
 		 */
 		_sexPossibleFathers:{npcId:string,time:Date}[] = [];
 
-		/*
-			Each Sex-Encounter has the following format:
-			{
-				npc: The ID of the npc Sveta had sex with. If she has sex with more than one character (e.g. threesome) an encounter has to be created for each of them.
-				time:The time it happened (Date-Object (UTC-time))
-				aware: Is Sveta aware of the sex-act? False in case of hypnosis, blackouts, etc.
-				civ: Cum in vagina
-				civa:Cum in vagina aware
-				tags: Array of tags
-			}
-		*/
-		_sexEncounters = [];
+		_sexEncounters:SexEncounter[] = [];
 
-		sexEncounterRegister(npc:any|string,type:('vaginal'|'anal'|'bj'|'hj'),familiarity:('love'|'friend'|'acquaintance'|'stranger'),aware:boolean,cumInVagina:boolean,time:Date){
+		sexEncounterRegister(npc:NPC|string,types:ESexEncounterType|ESexEncounterType[],familiarity:ESexEncounterFamiliarity,aware:boolean,time:Date){
 			if(typeof npc == 'string')
-				npc = State.variables.npcs.npc(npc) as NPC;
+				npc = State.variables.npcs.npc(npc);
 			let npcId:string;
 			if(npc){
 				npcId = npc.id;
-				npc.lastSex ??= {};
-				npc.lastSex[type] = time;
 			}else
 				npcId = '';
 
-			this._sexStatistics[type][familiarity][(aware ? 0 : 1)] += 1;
+			if(!Array.isArray(types))
+				types = [types];
+
+			const awareIndex = aware ? 0 : 1;
 
-			if(cumInVagina)
-				this._sexPossibleFathers.push({npcId:npcId,time:time});
+			for(const type of types){
+				this._sexStatistics[type] ??= {};
+				this._sexStatistics[type][familiarity] ??= [0,0];
+				this._sexStatistics[type][familiarity][awareIndex] += 1;
+				if(npc){
+					npc.lastSex ??= {};
+					npc.lastSex[type] = time;
+				}
+			}
 
+			this._sexEncounters.push({
+				npcId: npcId,
+				types: types,
+				time: time,
+				aware: aware,
+				tags: []
+			});
 		}
 
 		get isVirgin(){
-			return (this.sexStatistic('vaginal',null,'both') == 0);
+			return (this.sexStatistic(ESexEncounterType.VAGINAL,null,'both') == 0);
 		}
 		get thinksIsVirgin(){
-			return (this.sexStatistic('vaginal',null,'aware') == 0);
+			return (this.sexStatistic(ESexEncounterType.VAGINAL,null,'aware') == 0);
 		}
 	//#endregion
 
@@ -2155,10 +2134,17 @@ class PlayerCharacter implements Character{
 			return Object.keys(this.#activeEffects());
 		}
 
-		#activeEffects(fields:string[]=[]):{[key: string]:any}{
-			let result = {};
+		#activeEffects(fields:string[]=[]):{[key: string]:Effect}{
+			let result:{[key: string]:Effect} = {};
 			const time = State.variables.time;
 			
+			for(const [effectid,effect] of Object.entries(this.drugsActiveEffects)){
+				if(fields.length && !Object.keys(effect).includesAny(fields))
+					continue;
+				result[effectid] = effect;
+			}
+
+
 			for(const [effectid,effectData] of Object.entries(this._effects)){
 				if(effectData.expiration === undefined)
 					continue;
@@ -2191,7 +2177,6 @@ class PlayerCharacter implements Character{
 				result[effectid] = effect;
 			}
 
-			result = Object.assign({},this.drugsActiveEffects,result);
 			return result;
 		}
 
@@ -2307,7 +2292,7 @@ class PlayerCharacter implements Character{
 		 * @param {string} effectId
 		 * @returns {boolean}
 		 */
-		effectIsActive(effectId){
+		effectIsActive(effectId:string):boolean{
 			return (effectId in this.#activeEffects());
 		}
 

+ 1 - 1
sugarcube/src/playerCharacter/_submodules/pc_drugs.ts

@@ -1,6 +1,6 @@
 class Drugs{
 	_drugs:{[key:string]:DrugInCharacter} = {};
-	get activeEffects(){
+	get activeEffects():{[key: string]:Effect}{
 		return Object.fromEntries(this.activeEffectIds.map((effectId)=>[effectId,setup.getEffect(effectId)]));
 	}
 

+ 1 - 1
sugarcube/src/playerCharacter/personality/exhibitionism/exhibitionism.ts

@@ -3,7 +3,7 @@ setup.personalityScales.exhibitionism = {
 	start: 5,
 	interval:[0,100],
 	label:['Modesty','Exhibitionism'],
-	desc:'',
+	desc:'Some women don\'t like to show too much of their skin. Some other women like to show their features. And some women don\'t like to leave anything to the imagination. You might be reluctant to wear revealing outfits at first, but over time you will get used to doing so.',
 	image:'',
 	msg_tooHigh: 'Doing this would be too prude for your taste.',
 	msg_tooLow: 'You don\' feel daring enough to do this.',

+ 16 - 0
sugarcube/src/playerCharacter/personality/sexAbuseAverse/sexAbuseAverse.ts

@@ -0,0 +1,16 @@
+/// <reference path="../PersonalityScale.ts"/>
+
+setup.personalityScales.sexAbuseAverse = {
+	start: 100,
+	interval:[0,100],
+	label:['Victim','Self-determined'],
+	desc:'Consent is a requirement for every healthy sexual activity between two or more people. Tragically, not everyone asks or even cares for your consent. If you are unlucky enough to have this happen to you often, you might end up getting used to this.',
+	image:'',
+	msg_tooHigh: '?',
+	msg_tooLow: '?',
+	impacts:{
+	},
+	functions:{
+
+	}
+}

+ 14 - 5
sugarcube/src/playerCharacter/skills/skills.ts

@@ -107,24 +107,33 @@ setup.skills.charisma = {
 setup.skills.chess = {
     label: 'Chess',
     e2s: Skill.e2sFunction(2.5),
-    s2e: Skill.s2eFunction(2.5)
+    s2e: Skill.s2eFunction(2.5),
+    image:'pc/skills/chess.webp'
 }
 
 setup.skills.computer = {
-    label: 'Computer'
+    label: 'Computer',
+    image:'pc/skills/computer.webp'
 }
 
 setup.skills.dance = {
-    label: 'Dancing'
+    label: 'Dancing',
+    image:'pc/skills/dance.webp'
 }
 
 setup.skills.gaming = {
     label: 'Gaming',
     e2s: Skill.e2sFunction(1.5),
-    s2e: Skill.s2eFunction(1.5)
+    s2e: Skill.s2eFunction(1.5),
+    image:'pc/skills/gaming.webp'
 }
 
-
+setup.skills.gunnery = {
+    label: 'Shooting (Gun)',
+    e2s: Skill.e2sFunction(1.5),
+    s2e: Skill.s2eFunction(1.5),
+    image:'pc/skills/gunnery.webp'
+}
 
 setup.skills.iceskating = {
     label: 'Iceskating',

+ 80 - 120
sugarcube/src/quests/abduction/abduction.tw

@@ -1,45 +1,3 @@
-:: abduction_scripts[script]
-setup.npcs ??= {};
-setup.npcs["abduction_master"] = {
-	firstname:'Miroslav',
-	lastname:'Nosov',
-	usedname:'Your Captor',
-	image:'locations/shared/abduction/abductor_profile.webp',
-	gender:0,
-	thdick:'thicker than average',
-	dick:17,
-	rel: 0,
-	preference:{
-	},
-	defaults:['defaults'],
-}
-
-setup.moodlets ??= {};
-setup.moodlets.abducted={
-	title: "Abducted",
-	description:'You have been abducted.',
-	group:'victim',
-	effect: -30,
-	timeMode: 2
-}
-
-setup.moodlets.assaulted={
-	title: "Sexually Assaulted",
-	description:'Somebody has touched your privates without your consent.',
-	group:'victim',
-	effect: -50,
-	timeMode: 1,
-	duration: 1440
-}
-
-setup.moodlets.rape={
-	title: "Rape",
-	description:'Somebody has penetrated you without your consent. To overcome this traumatic experience you will need to either forgive your rapist or see a psychologist.',
-	group:'victim',
-	effect: -80,
-	timeMode: 2
-}
-
 :: abduction_event[outdoors_events]
 <<if  rand(1,10000) <= setup.crimeLikelihood('abduction',$eventReturnLocation) && !$q.questIsStarted('abduction')>>
 	<<event 1000>>
@@ -60,9 +18,10 @@ setup.moodlets.rape={
 	<</act>>
 
 :: abduction[event]
-<<npcLoad 'abduction_master'>>
+<<set _npcId='abduction_master'>>
 <<switch $location_var[$here][0]>> 
 	<<case 'abdCarTrunk'>>
+		<<addtime 37>>
 		<<image "locations/shared/abduction/trunkint1.jpg">>
 		You wake up in a very tight, dark place. You quickly realize that you're in the trunk of a moving car.
 		You try to kick the walls with your feet, but after a while you can see that it's pointless.
@@ -70,6 +29,7 @@ setup.moodlets.rape={
 			<<gt 'abduction' 'abdRoomFirstEntry'>>
 		<</act>>
 	<<case 'abdRoomFirstEntry'>>
+		<<addtime 15>>
 		<<image "locations/shared/abduction/downstairs1.jpg">>
 		The car stops and you hear the sound of someone walking outside before the trunk opens up.
 		Before your eyes adjust to the bright flow of daylight, you're hoisted up by a strong man and carried into a house.
@@ -79,15 +39,16 @@ setup.moodlets.rape={
 		<</act>>
 
 <<case 'abdRoomFirstChaining'>>
+	<<addtime 9>>
 	<<image 'locations/shared/abduction/sex/shackled#.webp' 1 4>>
-	You're thrown onto a dirty bed. <<npc>><</npc>> forcibly undresses you before shackling your wrists and ankles. He then slaps a collar around your neck before chaining you to the wall.
-	"You must have really pissed the wrong person off girl," he says.
-	<p>"What is this place? What are you going to do to me?" you ask.</p>
-	<p>"This is where girls are brought to be trained as sex slaves!"</p>
-	"... But... How... No..."
-	<p>"Shut up, slut! Usually, we torture you for fun and for as long as we want. Once you break, we sell you to the highest bidder."</p>
-	<p>"You can't do this to me! It's illegal!"</p>
-	<p>"Ha! Who do you think our best customers are? Slimy politicians, corrupt police officers, sleazy businessmen... We have our cover, so you should shut up and get used to it!"</p>
+	You're thrown onto a dirty bed. <<npc _npcId>><</npc>> forcibly undresses you before shackling your wrists and ankles. He then slaps a collar around your neck before chaining you to the wall.
+	<<if false>><<say _npcId "You must have really pissed the wrong person off girl,">><<else>><<say _npcId "Welcome to your new home">><</if>> he says.
+	<p><<say "What is this place? What are you going to do to me?">> you ask.</p>
+	<p><<say _npcId "This is where girls are brought to be trained as sex slaves!">></p>
+	<<say "... But... How... No...">>
+	<p><<say _npcId "Shut up, slut! Usually, we torture you for fun and for as long as we want. Once you break, we sell you to the highest bidder.">></p>
+	<p><<say "You can't do this to me! It's illegal!">></p>
+	<p><<say _npcId "Ha! Who do you think our best customers are? Slimy politicians, corrupt police officers, sleazy businessmen... We have our cover, so you should shut up and get used to it!">></p>
 	The man leaves without saying another word as you tearfully sob and yell for him to come back.
 
 	<<mood 'abducted'>>
@@ -106,17 +67,17 @@ setup.moodlets.rape={
 	<<image "locations/shared/abduction/downstairs2.jpg">>
 	You hear the sounds of footsteps that gradually get louder before they reach the top of the stairs.
 	<<act 'Continue'>>
-		<<gs 'abduction' 'abdSomeoneComingResult'>>
+		<<gt 'abduction' 'activityHub'>>
 	<</act>>
-<<case 'abdSomeoneComingResult'>>
+<<case 'activityHub'>>
 	<<if !$quest('abduction').examed>>
-		<<gt 'abduction' 'abdExamStart'>>
+		<<gs 'abduction' 'abdExamStart'>>
 	<<elseif $pc.legHair > 3 or $pc.pubesLength > 3>>
-		<<gt 'abduction' 'shave'>>
+		<<gs 'abduction' 'shave'>>
 	<<elseif !$pc.effectIsActive('cycleBlocked')>>
-		<<gt 'abduction' 'shots'>>
+		<<gs 'abduction' 'shots'>>
 	<<else>>
-		<<gt 'abduction' 'abdSomeoneComing2'>>
+		<<gs 'abduction' 'abdSomeoneComing2'>>
 	<</if>>
 <<case 'shots'>>
 	<<addtime 20>>
@@ -128,7 +89,7 @@ setup.moodlets.rape={
 	<<run $pc.effectAdd('stdsBlocked',_effectDuration)>>
 
 	<<act 'Continue'>>
-		<<gs 'abduction' 'abdSomeoneComingResult'>>
+		<<gt 'abduction' 'activityHub'>>
 	<</act>>
 <<case 'shave'>>
 	<<set $time.minutes += 20>>
@@ -139,14 +100,14 @@ setup.moodlets.rape={
 	<<set $pc.legHair = 0>>
 	<<set $pc.horny += 5>>
 	<<act 'Continue'>>
-		<<gs 'abduction' 'abdSomeoneComingResult'>>
+		<<gt 'abduction' 'activityHub'>>
 	<</act>>
 	
 <<case 'abdSomeoneComing2'>>
 	<<image 'locations/shared/abduction/abductor_big.webp'>>
 	<<if $quest('abduction').broken == 0>>
 		
-		You fearfully back away from <<npc null null 'the man'>><</npc>> and curl up against the wall, your body trembling in fear of what's going to happen next.
+		You fearfully back away from <<npc _npcId null 'the man'>><</npc>> and curl up against the wall, your body trembling in fear of what's going to happen next.
 		<<act 'Cower in fear'>>
 			<<gt 'abduction' 'abdRape'>>
 		<</act>>
@@ -202,17 +163,17 @@ setup.moodlets.rape={
 	<<set $time.minutes += 5>>
 	<<image "locations/shared/abduction/examroom.jpg">>
 	<p>
-		<<npc>><</npc>> comes up to you. He grabs your chain and forcibly wraps a blindfold around your head to cover your eyes.
+		<<npc _npcId>><</npc>> comes up to you. He grabs your chain and forcibly wraps a blindfold around your head to cover your eyes.
 		He leads you up the stairs as you feel a breath of fresh air that sensually caresses your bare skin.
 	</p>
 	Your blindfold is removed and you find yourself in a small room that's painted white. The light is very bright and blinds you to the point that you can barely see.
 	As your eyes adjust, you see that it's some kind of examination room. It distinctly reminds you of a gynecologist's office.
-	"Sit." the man sternly orders.
-	<<actCLA 'Resist' undefined `{willpower:['misc','resist','hard']}`>>
+	<<say _npcId "Sit.">> the man sternly orders.
+	<<act 'Resist'>>
 		<<gt 'abduction' 'abdExamResist'>>
-	<</actCLA>>
+	<</act>>
 
-	<<act 'Obey'>>
+	<<act 'Obey' undefined `{personality:{sexAbuseAverse:{max:50,impact:1}}}`>>
 		<<gt 'abduction' 'abdExamObey'>>
 	<</act>>
 <<case 'abdExamResist'>>
@@ -221,7 +182,7 @@ setup.moodlets.rape={
 	Terrified of what they'll do, you start screaming for help and clawing at your collar, trying desperately to escape.
 	However, your captor's strength, along with your tightly adjusted cuffs, make your attempt to escape futile.
 	He yanks roughly on your chain, your collar choking you as he pulls you to the ground in front of him. He slaps your face hard and leaves it stinging with a red handmark across your cheek.
-	<p>"You're only making it harder bitch!" he yells in your face before effortlessly picking you up and slamming you into the chair, winding you. He removes your shackles before tightly restraining you.</p>
+	<p><<say _npcId "You're only making it harder bitch!" he yells in your face before effortlessly picking you up and slamming you into the chair, winding you. He removes your shackles before tightly restraining you.</p>
 	He then calmly sits down in a chair in the far corner of the room.
 	<<act 'Continue'>>
 		<<gt 'abduction' 'abdExam1'>>
@@ -241,23 +202,23 @@ setup.moodlets.rape={
 	Another man enters the room dressed like a doctor, wearing a lab coat and suit with a stethoscope around his neck. He walks as if he's unconcerned about you.
 	Obviously, he doesn't speak to you, but rather to the man sitting in the chair. 
 	
-	<<if $pc.hotcat > 5>>"Wow, a nice catch indeed." the doctor exclaims.<</if>>
+	<<if $pc.hotcat > 5>><<say 'male' "Wow, a nice catch indeed.">> the doctor exclaims.<</if>>
 	The doctor puts on a pair of rubber gloves and sits down on a small chair in front of you. He looks at your spread legs and what's between them.
-	He continues to speak to the man. "She's about $pc.age years old."
-	<<if getvar("$pc.age") < 18>>
-		<p>"Geez, you like them young, don't you?"</p>
-		<p>"Who wants to fuck some old meat? The customers just love how the young ones squeal." the man replies.</p>
-		"Heh, I see..." He continues with the usual report of his findings.
+	He continues to speak to the man. <<say 'male' "She's about $pc.age years old.">>
+	<<if $pc.age < 18>>
+		<p><<say 'male' "Geez, you like them young, don't you?">></p>
+		<p><<say _npcId "Who wants to fuck some old meat? The customers just love how the young ones squeal.">> the man replies.</p>
+		<<say 'male' "I see...">> He continues with the usual report of his findings.
 	<</if>>
-	He continues to examine every inch of you. "Regarding her usage levels:"
-	<p>He shines a light in your mouth. "Her throat is <<=func('body_desc','throat').adjLong>>."</p>
-	<p>Next, he prods a finger around in your ass. "And her ass is <<=func('body_desc','anus').adjLong>>."</p>
+	He continues to examine every inch of you. <<say 'male' "Regarding her usage levels:">>
+	<p>He shines a light in your mouth. <<say 'male' `"Her throat is "+func('body_desc','throat').adjLong+"."`>></p>
+	<p>Next, he prods a finger around in your ass. <<say 'male' `"And her ass is "+func('body_desc','anus').adjLong+"."`>></p>
 	He pulls his finger out of your ass and finally reaches for your pussy.
 	<<if $pc.pcs_vag == 0>>
-		"Oh, you'll like this. Her pussy is fresh. We have a virgin here."
-		"Looks like we hit the jackpot once again dear Doctor," the man replies with a happy smile.
+		<<say 'male' "Oh, you'll like this. Her pussy is fresh. We have a virgin here.">>
+		<<say _npcId "Looks like we hit the jackpot once again dear Doctor,">> the man replies with a happy smile.
 	<<else>>
-		<p>"And her pussy is <<=func('body_desc','pussy').adj>>.</p>
+		<p><<say 'male' "And her pussy is <<=func('body_desc','pussy').adj>>.">></p>
 	<</if>>
 	<p>The doctor finally takes his hands off of you and prepares several needles filled with unknown fluids.</p>
 	<<mood 'assaulted'>>
@@ -276,7 +237,7 @@ setup.moodlets.rape={
 		<<else>>
 			"Hold still for this one.
 		<</if>>
-		It will make sure you won't bleed on <<npc null null 'your master'>><</npc>>s penis as well as making sure that you won't become pregnant."
+		It will make sure you won't bleed on <<npc _npcId undefined "your master's">><</npc>> penis as well as making sure that you won't become pregnant."
 		He inserts the needle right into your stomach. To your surprise, it's not too painful.
 		<<run $pc.effectAdd('cycleBlocked',_effectDuration)>>
 		<<run $pc.effectAdd('pregnancyBlocked',_effectDuration)>>
@@ -288,18 +249,18 @@ setup.moodlets.rape={
 	</p>
 	<p>
 	"The examination is now over."
-	The doctor leaves the room and <<npc null null 'your master'>><</npc>> puts your shackles and blindfold back on before leading you back down to the basement.
+	The doctor leaves the room and <<npc _npcId undefined 'your master'>><</npc>> puts your shackles and blindfold back on before leading you back down to the basement.
 	</p>
 	<<set $quest('abduction').examed = 1>>
-	<<actCLA 'Continue'>>
+	<<act 'Continue'>>
 		<<addtime 5>>
 		<<gt 'abduction_basement'>>
-	<</actCLA>>
+	<</act>>
 <<case 'abdBrokenGiveTools'>>
 	
 	<<set $quest('abduction').tools = 1>>
 	<<image "locations/shared/abduction/sex/slavewhoredildosbag.jpg">>
-	<<npc null null 'Your master'>><</npc>> approaches you. It looks like he's holding something big in his hands.
+	<<npc _npcId null 'Your master'>><</npc>> approaches you. It looks like he's holding something big in his hands.
 	When he steps into the light, you can see that he's holding some very large dildos.
 	"Hello, my slave. I have a gift for you."
 	You remain quiet, fearful thoughts of having these dildos shoved anywhere into your body making you feel sick.
@@ -365,7 +326,7 @@ setup.moodlets.rape={
 <<case 'abdBrokenGivePainkiller'>>
 	
 	<<image "locations/shared/abduction/pill1.jpg">>
-	<<npc null null 'Your master'>><</npc>> approaches you. "You have been a good slave so far. Good slaves are rewarded."
+	<<npc _npcId null 'Your master'>><</npc>> approaches you. "You have been a good slave so far. Good slaves are rewarded."
 	He hands you a single painkiller pill.
 	<<act 'Take and swallow it'>>
 		<<gt 'abduction' 'abdBrokenGivePainkillerYes'>>
@@ -382,7 +343,7 @@ setup.moodlets.rape={
 	You happily take the pill and swallow it immediately.
 	<<set $painkillerGive = rand(1,100)>>
 	<<if getvar("$painkillerGive") > 20 and $quest('abduction').broken >= 10>>
-		<<npc null null 'Your master'>><</npc>> nods in approval and hands you a small pack of painkillers.
+		<<npc _npcId null 'Your master'>><</npc>> nods in approval and hands you a small pack of painkillers.
 		<<run $inventory.inc('painkiller',6)>>
 	<</if>>
 	<<act 'How can I thank you, Master?'>>
@@ -391,12 +352,12 @@ setup.moodlets.rape={
 <<case 'abdBrokenGivePainkillerNo'>>
 	
 	<<video "locations/shared/abduction/sex/pill1.mp4">>
-	<p>You see anger flash across <<npc null null "your master's">><</npc>> face. "Refusing a gift? It seems like this slave needs to be reminded of her place."</p>
+	<p>You see anger flash across <<npc _npcId null "your master's">><</npc>> face. "Refusing a gift? It seems like this slave needs to be reminded of her place."</p>
 	He ties you down on top of the table and secures your head. Some devious device is attached to your nose which pulls your head backwards and forces you to open your mouth slightly.
-	<<npc null null 'Your master'>><</npc>> takes a clamp and pulls your tongue out. It tightly and painfully squeezes it. He then secures the pill on top of a dildo and pushes the tip down your throat.
+	<<npc _npcId null 'Your master'>><</npc>> takes a clamp and pulls your tongue out. It tightly and painfully squeezes it. He then secures the pill on top of a dildo and pushes the tip down your throat.
 	Your gag reflex activates, causing you to gag and choke, but he doesn't remove the dildo for as long as you try to throw up.
 	You almost pass out. Everything goes dark, and at that moment he removes it.
-	You have been forced to swallow the pill, but <<npc null null 'your master'>><</npc>> still looks very angry.
+	You have been forced to swallow the pill, but <<npc _npcId null 'your master'>><</npc>> still looks very angry.
 	<<run $pc.painInc('killer','',1)>>
 	<<set $quest('abduction').broken -= 5>>
 	<<run $pc.painInc('tongue','',5)>>
@@ -407,7 +368,7 @@ setup.moodlets.rape={
 	<</act>>
 <<case 'abdBrokenAsk'>>
 	
-	<p><<npc null null 'Your master'>><</npc>> responds. "Very good. What do you want me to do to you, slave?"</p>
+	<p><<npc _npcId null 'Your master'>><</npc>> responds. "Very good. What do you want me to do to you, slave?"</p>
 	<<act 'Please fuck my mouth Master'>>
 		<<gt 'abduction' 'abdBreak2FuckB1'>>
 	<</act>>
@@ -436,7 +397,7 @@ setup.moodlets.rape={
 	<<image "locations/shared/abduction/sex/brokena1.jpg">>
 	Your tormentor unchains you and throws you onto your dirty bed.
 	Spreading your legs wide apart, you spit on your hand and smear it on your pussy. "Come and take me, Master."
-	<p>"I like my bitches restrained!" <<npc null null 'your master'>><</npc>> says and ties your hands and feet together, securing your position.</p>
+	<p>"I like my bitches restrained!" <<npc _npcId null 'your master'>><</npc>> says and ties your hands and feet together, securing your position.</p>
 	His dick penetrates your pussy easily with the saliva doing its job.
 	<<arouse 'vaginal' 15 `['sub','bound']`>>
 	<<act 'Continue'>>
@@ -447,7 +408,7 @@ setup.moodlets.rape={
 	<<set $cumnostd = 1>>
 	<<cum 'mouth' 'abduction_master'>>
 	<<image "locations/shared/abduction/sex/brokena2.jpg">>
-	Fucking you wildly for some time, <<npc null null 'your master'>><</npc>> stops right before he orgasms.
+	Fucking you wildly for some time, <<npc _npcId null 'your master'>><</npc>> stops right before he orgasms.
 	He unties your hands and legs, then ties your hands behind your back.
 	Knowing what he expects you to do, you open your mouth wide and await his cock.
 	After some mouthfucking and gagging, he cums in your mouth.
@@ -465,10 +426,10 @@ setup.moodlets.rape={
 	<<set $cumnostd = 1>>
 	<<cum 'mouth' 'abduction_master'>>
 	<<image "locations/shared/abduction/sex/brokenb1.jpg">>
-	<<npc null null 'Your master'>><</npc>> unchains you and leads you to a device.
+	<<npc _npcId null 'Your master'>><</npc>> unchains you and leads you to a device.
 	You can see that it's meant to restrain a person in a prone position with their head at the same height as someone's crotch.
-	You want to please <<npc null null 'your master'>><</npc>>, so you lie down on it straight away and dutifully await the attaching of the restraints.
-	After <<npc null null 'your master'>><</npc>> ties you up, he walks up to your head. Your already open mouth is then roughly fucked by his member.
+	You want to please <<npc _npcId null 'your master'>><</npc>>, so you lie down on it straight away and dutifully await the attaching of the restraints.
+	After <<npc _npcId null 'your master'>><</npc>> ties you up, he walks up to your head. Your already open mouth is then roughly fucked by his member.
 	When he's about to cum, he pulls his dick out and points it towards your face. You stick your tongue out in anticipation. His cum soon splatters across your face and tongue.
 	<<arouse 'bj' 20 `['sub','bound','rough']`>>
 	<<act 'Continue'>>
@@ -480,7 +441,7 @@ setup.moodlets.rape={
 	<<image "locations/shared/abduction/sex/brokenb2.jpg">>
 	Surprisingly, his dick is not wearing out. He moves behind you and starts to penetrate your ass.
 	You relax your anus as much as you can, so he enters you quite easily. Just a small hint of pain pulses through you.
-	Fucking you furiously for some time, <<npc null null 'your master'>><</npc>> cums deep inside you.
+	Fucking you furiously for some time, <<npc _npcId null 'your master'>><</npc>> cums deep inside you.
 	<<if $quest('abduction').broken == 1>>
 		"Very good, slave. You're on the path to redeeming yourself." Finished with you, he releases your arms to secure you back in your usual location before leaving.
 	<</if>>
@@ -498,8 +459,8 @@ setup.moodlets.rape={
 	<<set $quest('abduction').rapeCount += 1>>
 	/*<<if $quest('abduction').broken < 10>>
 		<<set $pc.mood = 5>>
-	<</if>>*/
-	<<sex>><<bound 2>><<noncon 3>>
+	<</if>>
+	<<sex>><<bound 2>><<noncon 3>>*/
 	<<either>>	
 		<<either>>
 			<<image 'locations/shared/abduction/sex/mouthgagblow#.jpg'  1 4>>
@@ -509,12 +470,12 @@ setup.moodlets.rape={
 		<p>
 			Your hands are tied. A metal ring, fastened by a leather gag, is inside your mouth, keeping it pried open.
 			You have to endure a very rough mouth fuck. 
-			<<npc>><</npc>> knows no limits and gags you as much as he wants.
+			<<npc _npcId>><</npc>> knows no limits and gags you as much as he wants.
 			He does let you breathe from time to time, but for most of the experience you feel like you're about to pass out.
 			Your saliva is all over his dick and drips onto your breasts and stomach.
 		</p>
 		<<either>>
-			<<bj null 1 3 3>>
+			/*<<bj null 1 3 3>>*/
 			<p>
 				Finally he cums, filling your mouth with his sperm.
 				He makes sure not to waste a drop.
@@ -529,7 +490,7 @@ setup.moodlets.rape={
 	<<or $pc.isVirgin ? 0 : 1>>
 		<<image 'locations/shared/abduction/sex/fucktiedpussy#.jpg'  1 5>>
 		Your hands are tied, and you're bent over the bed.
-		<<fuck null `{cum:true,hard:true}` true>>
+		/*<<fuck null `{cum:true,hard:true}` true>>*/>
 		<p>
 			He then leads you back to your spot in the basement and chains you to the wall again.
 		</p>
@@ -544,9 +505,9 @@ setup.moodlets.rape={
 			<<video "locations/shared/abduction/sex/fucktiedanal1.mp4">>
 		<</either>>
 		Your hands are tied, and you're bent over the bed.
-		<<npc>><</npc>> starts to penetrate your ass without warning.
+		<<npc _npcId>><</npc>> starts to penetrate your ass without warning.
 		<!--A sharp pain shoots through your anus as your ass is neither relaxed nor lubed enough to receive a dick.-->
-		<<anal null `{cum:true,hard:true}` true>>
+		/*<<anal null `{cum:true,hard:true}` true>>*/
 		<p>
 			He then leads you back to your spot in the basement and chains you to the wall again.
 		</p>
@@ -558,11 +519,11 @@ setup.moodlets.rape={
 		
 		<<image "locations/shared/abduction/sex/fistanal#.jpg" 1 5>>
 		Your hands and feet are bound as you hang upside down with your ass in the air.
-		<<npc>><</npc>> starts trying to push his thick fist inside your anus. At least he used a bit of lubricant...
+		<<npc _npcId>><</npc>> starts trying to push his thick fist inside your anus. At least he used a bit of lubricant...
 		When your sphincter fails to resist anymore, you hear a loud pop as his fist quickly penetrates you.
 		He doesn't stop there and pushes his hand deep. You can feel your intestines expanding as he opens his fist inside you.
 		The pain is unbearable, but he doesn't care.
-		<<anal_fist null `{hard:true}` true>>
+		/*<<anal_fist null `{hard:true}` true>>*/
 		<<mood 'rape'>>
 		<<act 'Continue'>>
 			<<gt 'abduction_basement'>>
@@ -570,18 +531,18 @@ setup.moodlets.rape={
 	<<or $pc.isVirgin ? 0 : 1>>
 		<<image "locations/shared/abduction/sex/fistvaginal#.jpg" 1 5>>
 		Your hands and feet are tied with your ass raised higher than your head.
-		<<npc>><</npc>> starts pushing his thick fist deep inside your pussy. At least he used a bit of lubricant...
+		<<npc _npcId>><</npc>> starts pushing his thick fist deep inside your pussy. At least he used a bit of lubricant...
 		<p>Suddenly, you feel his fingers touch your cervix. He's doing it on purpose!</p>
 		He's pinching and pressing your cervix. You cry out loudly and try to shake him off, but you are bound tight. There's no hope of success...
 		<p>"Do you like it, slave?" He stops pushing, but you can feel a finger still brushing up against your cervix. "Should we penetrate another hole girl?"</p>
 		<p>"No! Please... stop... Just... stop..." you plead through tears.</p>
-		<<vaginal_fist null `{hard:true}`>>
+		/*<<vaginal_fist null `{hard:true}`>>*/
 		<<mood 'rape'>>
 		<<act 'Continue'>>
 			<<gt 'abduction_basement'>>
 		<</act>>
 	<</either>>
-	<</noncon>><</bound>><</sex>>
+	/*<</noncon>><</bound>><</sex>>*/
 <<case 'abdTorture'>>
 	<<set $tortureType = rand(1,4)>>
 	<<set $quest('abduction').tortureCount += 1>>
@@ -773,7 +734,7 @@ setup.moodlets.rape={
 	<</act>>
 <<case 'abdBeSold'>>
 	
-	"We have a buyer for you..." <<npc null null 'your master'>><</npc>> says with a cruel smile.
+	"We have a buyer for you..." <<npc _npcId null 'your master'>><</npc>> says with a cruel smile.
 	<<act 'I don`t want to be sold'>>
 		<<gt 'abduction' 'abdConsiderSold'>>
 	<</act>>
@@ -791,7 +752,7 @@ setup.moodlets.rape={
 	<</act>>
 <<case 'abdNotSold'>>
 	
-	"Very well. We'll see each other again soon," <<npc null null 'your master'>><</npc>> says.
+	"Very well. We'll see each other again soon," <<npc _npcId null 'your master'>><</npc>> says.
 	<<act 'Continue'>>
 		<<gt 'abduction_basement'>>
 	<</act>>
@@ -821,14 +782,14 @@ setup.moodlets.rape={
 	<<set $abdCustomerFailCount += 1>>
 	<<set $time.minutes += 5>>
 	<<video "locations/shared/abduction/sex/slavewhorefailed.mp4">>
-	<<npc null null 'Your master'>><</npc>> angrily leads you back to the basement.
+	<<npc _npcId null 'Your master'>><</npc>> angrily leads you back to the basement.
 	<<act 'Continue'>>
 		<<gt 'abduction' 'abdFailedCustomer1'>>
 	<</act>>
 <<case 'abdFailedCustomer1'>>
 	
 	<<video "locations/shared/abduction/sex/slavewhorefailed1.mp4">>
-	<<npc null null 'Your master'>><</npc>> looks very upset.
+	<<npc _npcId null 'Your master'>><</npc>> looks very upset.
 	First, he takes some ropes and ties you up. Your breasts start to turn purple from the lack of blood circulation because of how tightly fastened they are.
 	<<arouse 'foreplay' 15 `['sub','bound','maso','humiliation']`>>
 	<<act 'Continue'>>
@@ -876,7 +837,7 @@ setup.moodlets.rape={
 	Your restraints are removed, but you're led to a wall to be chained anew to a different device.
 	<p>This time, you can see everything - but you wish you couldn't.</p>
 	Electrodes are taped to your nipples, clitoris, and vagina.
-	<<npc null null 'Your master'>><</npc>> takes a few steps back and pushes a button on a remote. In that moment, an electric shock goes through your whole body, causing you to shake.
+	<<npc _npcId null 'Your master'>><</npc>> takes a few steps back and pushes a button on a remote. In that moment, an electric shock goes through your whole body, causing you to shake.
 	You moan loudly and beg for him to stop.
 	<<arouse 'foreplay' 30 `['sub','bound','maso','humiliation']`>>
 	<<act 'Continue'>>
@@ -907,7 +868,7 @@ setup.moodlets.rape={
 	"Remember this lesson slave. If you disappoint a customer again, a more severe punishment may be forced upon you."
 	"If you're found to be more trouble than you're worth, one of our more perverse customers will pay us well for the opportunity to torture you to death."
 	You just nod that you understand and remain silent.
-	<p><<npc null null 'Your master'>><</npc>> leaves without another word - and you are left hanging on the wall.</p>
+	<p><<npc _npcId null 'Your master'>><</npc>> leaves without another word - and you are left hanging on the wall.</p>
 	You are tired, everything hurts, and there seems to be no sign of when you will be removed from this terrible bondage, if at all.
 	<<act 'Continue'>>
 		<<gt 'abduction' 'abdFailedCustomerChainedBack'>>
@@ -928,7 +889,7 @@ setup.moodlets.rape={
 	<<run $pc.painInc('labia','',20)>>
 	<<run $pc.painInc('clitoris','',20)>>
 	<<video "locations/shared/abduction/sex/slavewhorefailedhook2.mp4">>
-	Trying to look behind you, you see <<npc null null 'your master'>><</npc>> bring something in his hands.
+	Trying to look behind you, you see <<npc _npcId null 'your master'>><</npc>> bring something in his hands.
 	He puts it up against your pussy and it suddenly starts to vibrate.
 	The intensity is too much for you, and instead of bringing you pleasure, it feels like a devious mix of intense pain and orgasmic pulses.
 	After a while, you piss yourself while experiencing something like a very painful orgasm.
@@ -942,7 +903,7 @@ setup.moodlets.rape={
 	<<run $pc.painInc('vaginal','',10)>>
 	<<run $pc.painInc('cervix','',20)>>
 	<<video "locations/shared/abduction/sex/slavewhorefailedhook3.mp4">>
-	Your pussy is very sensitive after the vibrator treatment, and <<npc null null 'your master'>><</npc>> knows that all too well.
+	Your pussy is very sensitive after the vibrator treatment, and <<npc _npcId null 'your master'>><</npc>> knows that all too well.
 	He slams his dick deep inside you to hit your cervix. It seems like he's doing it on purpose.
 	<p>You try to beg for mercy, but he doesn't care. He wants you to suffer - this is your punishment...</p>
 	<<arouse 'vaginal' 20 `['sub','bound','maso','humiliation','rough']`>>
@@ -971,7 +932,7 @@ setup.moodlets.rape={
 	<<run $pc.painInc('labia','',5)>>
 	<<run $pc.painInc('clitoris','',5)>>
 	<<video "locations/shared/abduction/sex/slavewhorewhip1.mp4">>
-	<<npc null null 'Your master'>><</npc>> removes your bondage and in anger pushes you on the ground before spreading your legs.
+	<<npc _npcId null 'Your master'>><</npc>> removes your bondage and in anger pushes you on the ground before spreading your legs.
 	<p>"You fucking whore! You're going to learn how to be more fucking obedient!"</p>
 	He starts to spank your pussy with his hand.
 	<<arouse 'foreplay' 10 `['sub','bound','maso','humiliation']`>>
@@ -1000,7 +961,7 @@ setup.moodlets.rape={
 	<<run $pc.painInc('asshole','',10)>>
 	<<set $pc.pcs_ass += 1>>
 	<<video "locations/shared/abduction/sex/slavewhorewhip3.mp4">>
-	As if the baton wasn''t enough, <<npc null null 'your master'>><</npc>> reaches for a long dildo attached to a stick.
+	As if the baton wasn''t enough, <<npc _npcId null 'your master'>><</npc>> reaches for a long dildo attached to a stick.
 	With one heavy thrust, he penetrates your dry ass and fixes the stick to the wall. The metal stick''s weight is enough to push your guts aside as it presses against your intestinal walls.
 	<p>He then picks up a different weapon - a leather cat-o-nine whip.</p>
 	<p>His target is the same - your now raw and heavily stinging labia and clitoris.</p>
@@ -1017,10 +978,10 @@ setup.moodlets.rape={
 	<<set $pc.pcs_ass += 1>>
 	<<video "locations/shared/abduction/sex/slavewhorewhip4.mp4">>
 	After this even rougher punishment, you are on the brink of fainting.
-	<p><<npc null null 'Your master'>><</npc>> brings another device on a stick - a vibrator with a large head.</p>
+	<p><<npc _npcId null 'Your master'>><</npc>> brings another device on a stick - a vibrator with a large head.</p>
 	He buries the head deep between your labia while touching your clitoris directly, your position being ideal for this.
 	When the device is turned on, you realize it must be on the highest setting. It almost makes you orgasm instantly.
-	<<npc null null 'Your master'>><</npc>> leaves, and you're left alone with this device teasing you as the dildo continues pushing deep into your ass. Everything aches from this inhuman position.
+	<<npc _npcId null 'Your master'>><</npc>> leaves, and you're left alone with this device teasing you as the dildo continues pushing deep into your ass. Everything aches from this inhuman position.
 	You pass in and out of consciousness while having intense orgasms mixed with a lot of pain. You tremble helplessly, the only sounds in the room being your moans and the humming of the vibrator.
 	<<arouse 'vaginal_vibe' 240 `['sub','bound','maso','humiliation']`>>
 	<<act 'Endure it'>>
@@ -1632,4 +1593,3 @@ setup.moodlets.rape={
 
 <</switch>>
 
-<</npcLoad>>

+ 41 - 0
sugarcube/src/quests/abduction/scripts.ts

@@ -0,0 +1,41 @@
+/// <reference path="../../npcs/_system/NPCAccessor.ts" />
+/// <reference path="../../playerCharacter/_submodules/mood/moodlet.ts" />
+
+setup.npcs.abduction_master = {
+	firstname:'Miroslav',
+	lastname:'Nosov',
+	usedname:'Your Captor',
+	image:'locations/shared/abduction/abductor_profile.webp',
+	gender:EGender.MALE,
+	thdick:'thicker than average',
+	dick:17,
+	rel: 0,
+	preference:{
+	},
+	defaults:['defaults'],
+}
+
+setup.moodlets.abducted=new Moodlet({
+	title: "Abducted",
+	description:'You have been abducted.',
+	groupId:'victim',
+	effect: -30,
+	timeMode: 2,
+});
+
+setup.moodlets.assaulted=new Moodlet({
+	title: "Sexually Assaulted",
+	description:'Somebody has touched your privates without your consent.',
+	groupId:'victim',
+	effect: -50,
+	timeMode: 1,
+	duration: 1440
+});
+
+setup.moodlets.rape=new Moodlet({
+	title: "Rape",
+	description:'Somebody has penetrated you without your consent. To overcome this traumatic experience you will need to either forgive your rapist or see a psychologist.',
+	groupId:'victim',
+	effect: -80,
+	timeMode: 2
+});

+ 2 - 0
sugarcube/src/settings/settings.ts

@@ -44,4 +44,6 @@ setup.settingsApply = function(settings){
 	}
 	if(settings.ui?.css)
 		importStyles(settings.ui?.css.split("\n"));
+	if(settings.maxStates)
+		Config.history.maxStates = settings.maxStates;
 }

+ 22 - 0
sugarcube/src/start/index.tw

@@ -64,6 +64,10 @@
 		<<gt 'ImageSetting'>>
 	<</act>>
 
+	<<act 'Mod Manager'>>
+		<<gt 'ModManager'>>
+	<</act>>
+
 </center>
 <!-- ! WD: Set variable to store Image needed HTML code-->
 <<set $ImageNeededPlacholder = '<center>IMAGE MISSING</center>'>>
@@ -97,3 +101,21 @@
 <p><b style="color:red;">If you see an image below your settings are correct.</b></p>
 <<image "system/1_openings/splashes/splash#.jpg" 1 14>>
 
+:: ModManager[menu]
+	<<set _modPaths = JSON.parse(localStorage.getItem('modPaths') || '[]')>>
+	<<set _modPathsDisplay = _modPaths.join('\n')>>
+
+	<<textarea "_modPathsDisplay" _modPathsDisplay>>
+
+	<<button 'Apply'>>
+		<<set _modPaths = _modPathsDisplay.split(/\r?\n|\r|\n/g)>>
+		<<set _modPaths = _modPaths.map((raw)=>raw.trim()).filter((path)=>path!='')>>
+		<<if _modPaths.length>>
+			<<run localStorage.setItem('modPaths',JSON.stringify(_modPaths))>>
+		<<else>>
+			<<run localStorage.setItem('modPaths',"[]")>>
+		<</if>>
+		<<run location.reload()>>
+	<</button>>
+
+	<<link "Back">><<goto "index">><</link>>

+ 2 - 0
sugarcube/src/start/scenario_selection.tw

@@ -15,6 +15,7 @@
 		<</link>>
 	</div>
 
+	<<if $DEBUGGING>>
 	<<actCLA 'Development starts'>>
 		<h2>Start Scenario</h2>
 		<div class="startOption linksAsDefaultButtons">
@@ -88,6 +89,7 @@
 			<</link>>
 		</div>
 	<</actCLA>>
+	<</if>>
 
 
 

+ 2 - 0
sugarcube/src/version/VersionControl.ts

@@ -15,6 +15,8 @@ class VersionControl{
 			variables.q._quests['mother_virgin'].certificateDeadline = new Date(0);
 		}
 		
+		variables.modVars ??= {};
+
 		variables.version = toVersion;
 		
 	}

+ 22 - 23
sugarcube/src/wardrobe/wardrobe.ts

@@ -4,6 +4,16 @@
 /// <reference path="../wardrobe/OutfitItem/Purse.ts" />
 /// <reference path="../wardrobe/OutfitItem/Shoes.ts" />
 
+const enum EWearableBMI{
+	NOT_APPLICABLE = -2,
+	ANY = -1,
+	TOO_LOSE = 0,
+	TOO_TIGHT = 1,
+	ALMOST_TOO_LOSE = 2,
+	ALMOST_TOO_TIGHT = 3,
+	OKAY = 4
+}
+
 setup.wardrobeSettings = {
 	bmiSizeMaxDifference: 2
 }
@@ -887,17 +897,11 @@ class Wardrobe{
 			if(itemData.h == 0)
 				result.health = false;
 			if(itemData.bmi > 0){
-				result.hips = (this.wearableBMI(itemId) != 0 && this.wearableBMI(itemId) != 1);
+				result.hips = !([EWearableBMI.TOO_LOSE,EWearableBMI.TOO_TIGHT].includes(this.wearableBMI(itemId)));
 			}
 
 		}
 
-		/*let constData = setup.itemLoadConstData(
-						identificator.type,
-						identificator.vendor,
-						identificator.index,
-						identificator.subtype);*/
-
 		if(!this.wearbleInhibition(itemId))
 			result.inhibition = false;
 		result.total = (result.owned && result.health && result.inhibition && result.hips);
@@ -913,32 +917,27 @@ class Wardrobe{
 		return result;
 	}
 
-	/**
-	 * 
-	 * @param {string} itemId 
-	 * @returns {number} -2 If concept of BMI is not aplicable, -1 if suits any BMI, 0 if too lose, 1 if too tight, 2 if close to too lose, 3 if close to too tight, 4 of okay
-	 */
-	wearableBMI(itemId){
-		let itemData = this.item(itemId);
+	wearableBMI(itemId:string):EWearableBMI{
+		const itemData = this.item(itemId);
 		if(itemData.bmi === undefined)
-			return -2;
+			return EWearableBMI.NOT_APPLICABLE;
 		if(!itemData.bmi)
-			return -1;
+			return EWearableBMI.ANY;
 		if(itemData.bmi < 0)
-			return -2;
+			return EWearableBMI.NOT_APPLICABLE;
 
-		let pcbmi = State.variables.pc.bmi;
+		const pcbmi = State.variables.pc.bmi;
 		if(itemData.bmi - pcbmi > setup.wardrobeSettings.bmiSizeMaxDifference)
-			return 1;
+			return EWearableBMI.TOO_TIGHT;
 		if(pcbmi - itemData.bmi > setup.wardrobeSettings.bmiSizeMaxDifference)
-			return 0;
+			return EWearableBMI.TOO_LOSE;
 
 		if(itemData.bmi - pcbmi > setup.wardrobeSettings.bmiSizeMaxDifference * 0.75)
-			return 3;
+			return EWearableBMI.ALMOST_TOO_TIGHT;
 		if(pcbmi - itemData.bmi > setup.wardrobeSettings.bmiSizeMaxDifference * 0.75)
-			return 2;
+			return EWearableBMI.ALMOST_TOO_LOSE;
 
-		return 4;
+		return EWearableBMI.OKAY;
 	}
 
 	//Return 0 if inhibition blocks, 1 if exciting and 2 in every other case

+ 2 - 2
sugarcube_compile.bat

@@ -8,9 +8,9 @@ rem Python -X utf8 outfits_convert.py
 rem Python -X utf8 npcs_convert.py
 
 if %PROCESSOR_ARCHITECTURE% == AMD64 (
-	CALL "%~dp0sugarcube\devTools\tweeGo\tweego_win64.exe" -o "%~dp0glife.html" "%~dp0sugarcube\src"
+	CALL "%~dp0sugarcube\devTools\tweeGo\tweego_win64.exe" --head "%~dp0sugarcube\src\head.txt" -o "%~dp0glife.html" "%~dp0sugarcube\src"
 ) else (
-	CALL "%~dp0sugarcube\devTools\tweeGo\tweego_win86.exe" -o "%~dp0glife.html" "%~dp0sugarcube\src"
+	CALL "%~dp0sugarcube\devTools\tweeGo\tweego_win86.exe" --head "%~dp0sugarcube\src\head.txt" -o "%~dp0glife.html" "%~dp0sugarcube\src"
 )
 
 Python -X utf8 sugarcube_postCompile.py

+ 35 - 5
sugarcube_postCompile.py

@@ -1,9 +1,39 @@
 #!/usr/bin/env python3
 
+import os
 import fileinput
+import re
+import sys
 
-for line in fileinput.input("glife.html", inplace=True, encoding="utf-8"):
-    #print('{} {}'.format(fileinput.filelineno(), line), end='')
-    print(line, end='')
-    if line.strip() == '<head>':
-        print('<meta name="rating" content="adult" />', end='')
+
+
+file_path_html = 'glife.html'
+deprecatedTag = "deprecated"
+
+data = ''
+
+
+with open(file_path_html, 'r') as file:
+    data = file.read()
+
+dataLengthInitial = len(data)
+
+dataWithoutDeprecated = data
+
+i = 0
+regex = r"""<tw-passagedata pid="(\d+)" name="([\s\w]+)" tags="(.*?)" (?:position="\d+,\d+" )?(?:size="\d+,\d+")?>(.*?)</tw-passagedata>"""
+for match in re.finditer(regex,data,re.S):
+    tags = match.group(3).split()
+
+    if(deprecatedTag in tags):
+        dataWithoutDeprecated = dataWithoutDeprecated.replace(match.group(0),'')
+        print('Removed:'+match.group(2))
+
+
+
+with open(file_path_html, 'w') as file:
+    file.write(dataWithoutDeprecated)
+
+dataLengthEnd = len(dataWithoutDeprecated)
+
+print(f'POSTCOMPILE DONE, REMAINING SIZE {round(dataLengthEnd/dataLengthInitial*100,1)}%')

Some files were not shown because too many files changed in this diff