diff --git a/_metadata b/_metadata index 5f4a96d9..1152fa89 100644 --- a/_metadata +++ b/_metadata @@ -1,6 +1,6 @@ { "name": "lox_sexbound", - "version": "1.2_h1", + "version": "1.2_r1", "author": "Erina Sugino", "description": "^orange;Sexbound Reborn^reset; is the continuation of the old Sexbound API by Locuturus and Co., enabling sexual interactions in Starbound. It was forked from SxB version 5.12.1.\n\n\n\n^red;»^reset; CREDITS:\n\n^orange;Erina Sugino - Developer & Creator^reset;\n^blue;https://ko-fi.com/erinasugino^reset;\n\n^orange;* Locuturus and Co. - Original Author^reset;\n^blue;https://www.loverslab.com/files/file/4337-sexbound/^reset;\n\n^orange;* Sir Bumpleton - Lustbound Creator^reset;\n^blue;https://www.loverslab.com/files/file/14030-lustbound/^reset;\n\n^orange;* Red3dred - Contributor^reset;\n^blue;https://www.patreon.com/user?u=27199103^reset;\n\n^orange;* Rylasasin - Contributor^reset;\n^blue;^reset;\n\n^orange;XspeedPL - Contributor^reset;\n^blue;^reset;\n\n^orange;Hyperjuni - Contributor^reset;\n^blue;^reset;\n\n\n\n^red;IF YOU HAVE THIS MOD FROM STEAM, YOU HAVE AN UNAUTHORIZED STOLEN COPY.^reset;", "friendlyName": "Sexbound Reborn", diff --git a/artwork/humanoid/twoactors-centered.animation b/artwork/humanoid/twoactors-centered.animation index 8ebaaf3c..16bf73a1 100644 --- a/artwork/humanoid/twoactors-centered.animation +++ b/artwork/humanoid/twoactors-centered.animation @@ -868,10 +868,18 @@ "actors": { "idle_laying": {}, "idle": {}, - "position1": {}, - "position1-climax": {}, - "position1-postclimax": {}, - "position1-reset": {}, + "position1": { + "properties": {"zLevel": 15} + }, + "position1-climax": { + "properties": {"zLevel": 15} + }, + "position1-postclimax": { + "properties": {"zLevel": 15} + }, + "position1-reset": { + "properties": {"zLevel": 15} + }, "position2": {}, "position2-climax": {}, "position2-postclimax": {}, @@ -900,10 +908,18 @@ "position4_2-climax": {}, "position4_2-postclimax": {}, "position4_2-reset": {}, - "position5": {}, - "position5-climax": {}, - "position5-postclimax": {}, - "position5-reset": {}, + "position5": { + "properties": {"zLevel": 15} + }, + "position5-climax": { + "properties": {"zLevel": 15} + }, + "position5-postclimax": { + "properties": {"zLevel": 15} + }, + "position5-reset": { + "properties": {"zLevel": 15} + }, "position6": {}, "position6-climax": {}, "position6-postclimax": {}, diff --git a/artwork/humanoid/twoactors.animation b/artwork/humanoid/twoactors.animation index a17dc874..d880046a 100644 --- a/artwork/humanoid/twoactors.animation +++ b/artwork/humanoid/twoactors.animation @@ -1193,10 +1193,18 @@ "actors": { "idle_laying": {}, "idle": {}, - "position1": {}, - "position1-climax": {}, - "position1-postclimax": {}, - "position1-reset": {}, + "position1": { + "properties": {"zLevel": 15} + }, + "position1-climax": { + "properties": {"zLevel": 15} + }, + "position1-postclimax": { + "properties": {"zLevel": 15} + }, + "position1-reset": { + "properties": {"zLevel": 15} + }, "position2": {}, "position2-climax": {}, "position2-postclimax": {}, @@ -1225,10 +1233,18 @@ "position4_2-climax": {}, "position4_2-postclimax": {}, "position4_2-reset": {}, - "position5": {}, - "position5-climax": {}, - "position5-postclimax": {}, - "position5-reset": {}, + "position5": { + "properties": {"zLevel": 15} + }, + "position5-climax": { + "properties": {"zLevel": 15} + }, + "position5-postclimax": { + "properties": {"zLevel": 15} + }, + "position5-reset": { + "properties": {"zLevel": 15} + }, "position6": {}, "position6-climax": {}, "position6-postclimax": {}, diff --git a/dialog/sexbound/en/notifications.config b/dialog/sexbound/en/notifications.config index 11e99f05..3cd4e749 100644 --- a/dialog/sexbound/en/notifications.config +++ b/dialog/sexbound/en/notifications.config @@ -66,6 +66,10 @@ "sterilize": { "true": "You have been successfully sterilized. Fertilization is now impossible.", "false": "Your sterilization has been successfully reverted. Be mindful about fertilization." + }, + "infertility": { + "true": "You have become infertile. I hope you weren't banking on kids.", + "false": "You are no longer infertile. Careful now, unless you want to be a parent." } } } \ No newline at end of file diff --git a/interface/sexbound/customizer/customizer.config b/interface/sexbound/customizer/customizer.config index 597a740d..3f4d34b3 100644 --- a/interface/sexbound/customizer/customizer.config +++ b/interface/sexbound/customizer/customizer.config @@ -153,6 +153,43 @@ "hAnchor" : "left", "width" : 50, "value" : "^shadow;1000", + "color" : [255, 255, 255] + }, + "infertileLabel" : { + "fontSize": 10, + "type": "label", + "position": [20, 148], + "hAnchor": "left", + "vAnchor": "top", + "width": 210, + "value": "^shadow;You currently ^orange;are not^reset;^shadow; infertile.", + "wrapWidth": 210, + "color": [255, 255, 255] + }, + "infertileConfirm": { + "type": "button", + "base": "/interface/sexbound/customizer/smallbutton.png", + "hover": "/interface/sexbound/customizer/smallbutton-hover.png", + "pressed": "/interface/sexbound/customizer/smallbutton-hover.png", + "disabledImage": "/interface/sexbound/customizer/smallbutton-disabled.png", + "pressedOffset": [1,-1], + "caption": "Change", + "fontColor": [255, 255, 255], + "textAlign": "center", + "position": [240, 137] + }, + "infertilePriceIcon": { + "type" : "image", + "file" : "/interface/sexbound/customizer/icons/sexbux.png", + "position" : [300, 139] + }, + "infertilePrice": { + "type" : "label", + "fontSize" : 8, + "position" : [310, 139], + "hAnchor" : "left", + "width" : 50, + "value" : "^shadow;2000", "color" : [255, 255, 255] } } @@ -357,7 +394,8 @@ "subGenderSelector.up", "subGenderSelector.down", "subGenderConfirm", - "sterilizeConfirm" + "sterilizeConfirm", + "infertileConfirm" ], "scripts" : [ diff --git a/interface/sexbound/customizer/customizergeneral.lua b/interface/sexbound/customizer/customizergeneral.lua index d50d1538..e3e62b41 100644 --- a/interface/sexbound/customizer/customizergeneral.lua +++ b/interface/sexbound/customizer/customizergeneral.lua @@ -11,7 +11,8 @@ function Customizer.General:new(parent) currentSubGender = "None", currentSubGenderIndex = 1, subGenderList = {}, - sterilized = false + sterilized = false, + infertile = false }, Customizer.General_mt) end @@ -32,6 +33,11 @@ function Customizer.General:init() self.sterilized = self._parent.config.sterilized if self.sterilized == nil then self.sterilized = false end if self.sterilized then widget.setText("generalTab.sterilizeLabel", "^shadow;You currently ^orange;are^reset;^shadow; sterilized.") end + + self.infertile = self._parent.config.infertile + if self.infertile == nil then self.infertile = false end + if self.infertile then widget.setText("generalTab.infertileLabel", "^shadow;You currently ^orange;are^reset;^shadow; infertile.") + else widget.setButtonEnabled("generalTab.infertileConfirm", false) end end function Customizer.General:handleMessage(message) @@ -126,8 +132,8 @@ end function Customizer.General:sterilize() local res = player.consumeCurrency("sexbux", 1000) if not res then - widget.playSound("/sfx/interface/clickon_error.ogg") - return false + widget.playSound("/sfx/interface/clickon_error.ogg") + return false end if self.sterilized then @@ -138,4 +144,22 @@ function Customizer.General:sterilize() world.sendEntityMessage(player.id(), "Sexbound:Status:AddStatus", "sterilized") end self.sterilized = not self.sterilized +end + +function Customizer.General:makeFertile() + if not self.infertile then + widget.playSound("/sfx/interface/clickon_error.ogg") + return false + end + + local res = player.consumeCurrency("sexbux", 2000) + if not res then + widget.playSound("/sfx/interface/clickon_error.ogg") + return false + end + + widget.setText("generalTab.infertileLabel", "^shadow;You currently ^orange;are not^reset;^shadow; infertile.") + world.sendEntityMessage(player.id(), "Sexbound:Status:RemoveStatus", "infertile") + + self.infertile = false end \ No newline at end of file diff --git a/objects/sextoylegendary/sexbound_tentacleplant_v2/sexbound_tentacleplant_v2.object b/objects/sextoylegendary/sexbound_tentacleplant_v2/sexbound_tentacleplant_v2.object index 579b8d7a..6fa00aa6 100644 --- a/objects/sextoylegendary/sexbound_tentacleplant_v2/sexbound_tentacleplant_v2.object +++ b/objects/sextoylegendary/sexbound_tentacleplant_v2/sexbound_tentacleplant_v2.object @@ -1,303 +1,348 @@ { - "objectName" : "sexbound_tentacleplant_v2", - "shortdescription" : "Juvenile Tentacle Plant", - "description" : "Plant it down for it to mature with it's true colors.", - "shortdescriptionNew" : "Rooted Tentacle Plant", - "descriptionNew" : "A docile tentacle plant that knows when to heck.", - "colonyTags" : ["sexbound", "sex", "jungle", "odd"], - "category" : "other", - "rarity" : "Legendary", - "race" : "generic", - "printable" : false, - "price" : 25000, - "level" : 0, - - "itemTags" : ["sexbound", "sex"], - - "apexDescription" : "Nothing weird about this plant.", - "avianDescription" : "Maybe I should become what happens next.", - "floranDescription" : "Floran happy to see nature have some fun with us.", - "glitchDescription" : "Annoyed. This plant occasionally tangles with my circuitry.", - "humanDescription" : "I already know where this is going...", - "hylotlDescription" : "It feels like an octopus, yet so much more gentle.", - "novakidDescription" : "That ain't no buckin' bruncko!", - - "retainObjectParametersInItem" : true, - "cleanObject" : true, - "hueshiftValue" : 0, - - "sitStatusEffects" : ["sexbound_sex"], - - "interactive" : true, - - "objectType" : "loungeable", - "sitFlipDirection" : false, - "sitPosition" : [0, 20], - "sitOrientation" : "lay", - "sitAngle" : 0, - - "smashable" : false, - - "inventoryIcon" : "tentacleplanticon.png", - "orientations" : [ - { - "dualImage" : "tentacleplant.png:idle.1", + "objectName" : "sexbound_tentacleplant_v2", + "shortdescription" : "Juvenile Tentacle Plant", + "description" : "Plant it down for it to mature with it's true colors.", + "shortdescriptionNew" : "Rooted Tentacle Plant", + "descriptionNew" : "A docile tentacle plant that knows when to heck.", + "colonyTags" : ["sexbound", "sex", "jungle", "odd"], + "category" : "other", + "rarity" : "Legendary", + "race" : "generic", + "printable" : false, + "price" : 25000, + "level" : 0, - "imagePosition" : [-24, 0], - "frames" : 1, - "animationCycle" : 1, + "itemTags" : ["sexbound", "sex"], - "spaceScan" : 0.1, - "anchors" : [ "bottom" ] - } - ], - - "scripts" : ["/objects/sextoylegendary/sexbound_tentacleplant_v2/tentacleplant.lua"], - - "animation" : "/artwork/humanoid/twoactors.animation", - - "sexboundConfig" : { - "requiredVersion" : ">=3.x.x", - - "modName" : "Tentacle Plant", - - "position" : { - "sex" : [ "butterfly", "cowgirl_tentacleplant", "fellatio" ] - }, - "idlePosition": "idle_toy", - - "sex" : { - "allowSwitchRoles" : false - }, - - "sitPositions" : [ [0, 20], [0, 20] ] - }, - - "animationCustom" : { - "animatedParts" : { - "stateTypes" : { - "actors" : { - "states" : { - "idle" : { - "frames" : 2 - } - } - } - }, - - "parts" : { - "actor1-climax-male-spawn" : { - "partStates" : { - "actors" : { - "position4-climax" : { - "properties" : { - "offset" : [2.750, 1.250] - } - }, - "position5-climax" : { - "properties" : { - "offset" : [3.125, 1.250] - } - }, - "position5-postclimax" : { - "properties" : { - "offset" : [3.125, 1.250] - } - }, - "position6-climax" : { - "properties" : { - "offset" : [3.50, 1.250] - } - } - } - } - }, - - "actor1" : { - "partStates" : { - "actors" : { - "position4" : { - "properties" : { - "offset" : [-3.375, 0] - } - }, - "position4-climax" : { - "properties" : { - "offset" : [-3.375, 0] - } - }, - "position4-postclimax" : { - "properties" : { - "offset" : [-3.375, 0] - } - }, - "position4-reset" : { - "properties" : { - "offset" : [-3.375, 0] - } - }, - "position5" : { - "properties" : { - "offset" : [-2.25, 0] - } - }, - "position5-climax" : { - "properties" : { - "offset" : [-2.25, 0] - } - }, - "position5-postclimax" : { - "properties" : { - "offset" : [-2.25, 0] - } - }, - "position5-reset" : { - "properties" : { - "offset" : [-2.25, 0] - } - }, - "position6" : { - "properties" : { - "offset" : [-2.25, 0] - } - }, - "position6-climax" : { - "properties" : { - "offset" : [-2.25, 0] - } - }, - "position6-postclimax" : { - "properties" : { - "offset" : [-2.25, 0] - } - }, - "position6-reset" : { - "properties" : { - "offset" : [-2.25, 0] - } - } - } - } - }, - - "actor2" : { - "partStates" : { - "actors" : { - "position4" : { - "properties" : { - "offset" : [-3.5, 0.5] - } - }, - "position4-climax" : { - "properties" : { - "offset" : [-3.5, 0.5] - } - }, - "position4-postclimax" : { - "properties" : { - "offset" : [-3.5, 0.5] - } - }, - "position4-reset" : { - "properties" : { - "offset" : [-3.5, 0.5] - } - }, - "position5" : { - "frameProperties" : { - "offset" : [[-2.625, -0.125], [-2.625, -0.125], [-2.625, -0.125], [-2.75, 0], [-2.75, 0], [-2.75, 0], [-2.75, 0.125], [-2.75, 0.125], [-2.75, 0.125], [-2.75, 0.125], [-2.75, 0.125], [-2.75, 0], [-2.75, 0]] - } - }, - "position5-climax" : { - "frameProperties" : { - "offset" : [[-2.625, -0.125], [-2.625, -0.125], [-2.75, 0], [-2.75, 0.125], [-2.75, 0]] - } - }, - "position5-postclimax" : { - "frameProperties" : { - "offset" : [[-2.625, -0.125], [-2.625, -0.125], [-2.625, -0.125], [-2.75, 0], [-2.75, 0], [-2.75, 0], [-2.75, 0.125], [-2.75, 0.125], [-2.75, 0.125], [-2.75, 0.125], [-2.75, 0.125], [-2.75, 0], [-2.75, 0]] - } - }, - "position5-reset" : { - "frameProperties" : { - "offset" : [[-2.625, -0.125], [-2.625, -0.125], [-2.75, 0], [-2.75, 0.125], [-2.75, 0]] - } - }, - "position6" : { - "properties" : { - "offset" : [-1.625, 0] - } - }, - "position6-climax" : { - "properties" : { - "offset" : [-1.625, 0] - } - }, - "position6-postclimax" : { - "properties" : { - "offset" : [-1.625, 0] - } - }, - "position6-reset" : { - "properties" : { - "offset" : [-1.625, 0] - } - } - } - } - }, - "actor1-arm-front": { - "properties": { - "zLevel": 43 - } + "apexDescription" : "Nothing weird about this plant.", + "avianDescription" : "Maybe I should become what happens next.", + "floranDescription" : "Floran happy to see nature have some fun with us.", + "glitchDescription" : "Annoyed. This plant occasionally tangles with my circuitry.", + "humanDescription" : "I already know where this is going...", + "hylotlDescription" : "It feels like an octopus, yet so much more gentle.", + "novakidDescription" : "That ain't no buckin' bruncko!", + + "retainObjectParametersInItem" : true, + "cleanObject" : true, + "hueshiftValue" : 0, + + "sitStatusEffects" : ["sexbound_sex"], + + "interactive" : true, + + "objectType" : "loungeable", + "sitFlipDirection" : false, + "sitPosition" : [0, 20], + "sitOrientation" : "lay", + "sitAngle" : 0, + + "smashable" : false, + + "inventoryIcon" : "tentacleplanticon.png", + "orientations" : [ + { + "dualImage" : "tentacleplant.png:idle.1", + + "imagePosition" : [-24, 0], + "frames" : 1, + "animationCycle" : 1, + + "spaceScan" : 0.1, + "anchors" : [ "bottom" ] + } + ], + + "scripts" : ["/objects/sextoylegendary/sexbound_tentacleplant_v2/tentacleplant.lua"], + + "animation" : "/artwork/humanoid/twoactors.animation", + + "sexboundConfig" : { + "requiredVersion" : ">=3.x.x", + "modName" : "Tentacle Plant", + "position" : { + "sex" : [ "butterfly", "cowgirl_tentacleplant", "fellatio" ] + }, + "idlePosition": "idle_toy", + "sex" : { + "allowSwitchRoles" : false }, - "actor2-groin" : { - "partStates" : { - "actors" : { - "position4" : { - "frameProperties" : { - "zLevel" : [42,42,42,42,42] - } - }, - "position4-climax" : { - "frameProperties" : { - "zLevel" : [42] - } - }, - "position4-postclimax" : { - "frameProperties" : { - "zLevel" : [42,42,42,42,42,42,42,42,42,42,42,42,42] - } - }, - "position4-reset" : { - "frameProperties" : { - "zLevel" : [42] - } - }, - "position5" : { - "frameProperties" : { - "zLevel" : [42,42,42,42,42] - } - }, - "position5-climax" : { - "frameProperties" : { - "zLevel" : [42] - } - }, - "position5-postclimax" : { - "frameProperties" : { - "zLevel" : [42,42,42,42,42,42,42,42,42,42,42,42,42] - } - }, - "position5-reset" : { - "frameProperties" : { - "zLevel" : [42] - } - } - } - } - } - } - } - } -} \ No newline at end of file + "sitPositions" : [ [0, 20], [0, 20] ] + }, + + "animationCustom" : { + "animatedParts" : { + "stateTypes" : { + "actors" : { + "states" : { + "idle" : { + "frames" : 2 + } + } + } + }, + + "parts" : { + "actor1-climax-male-spawn" : { + "partStates" : { + "actors" : { + "position4-climax" : { + "properties" : { + "offset" : [2.750, 1.250] + } + }, + "position5-climax" : { + "properties" : { + "offset" : [3.125, 1.250] + } + }, + "position5-postclimax" : { + "properties" : { + "offset" : [3.125, 1.250] + } + }, + "position6-climax" : { + "properties" : { + "offset" : [3.50, 1.250] + } + } + } + } + }, + + "actor1" : { + "partStates" : { + "actors" : { + "position4" : { + "properties" : { + "offset" : [-3.375, 0] + } + }, + "position4-climax" : { + "properties" : { + "offset" : [-3.375, 0] + } + }, + "position4-postclimax" : { + "properties" : { + "offset" : [-3.375, 0] + } + }, + "position4-reset" : { + "properties" : { + "offset" : [-3.375, 0] + } + }, + "position5" : { + "properties" : { + "offset" : [-2.25, 0] + } + }, + "position5-climax" : { + "properties" : { + "offset" : [-2.25, 0] + } + }, + "position5-postclimax" : { + "properties" : { + "offset" : [-2.25, 0] + } + }, + "position5-reset" : { + "properties" : { + "offset" : [-2.25, 0] + } + }, + "position6" : { + "properties" : { + "offset" : [-2.25, 0] + } + }, + "position6-climax" : { + "properties" : { + "offset" : [-2.25, 0] + } + }, + "position6-postclimax" : { + "properties" : { + "offset" : [-2.25, 0] + } + }, + "position6-reset" : { + "properties" : { + "offset" : [-2.25, 0] + } + } + } + } + }, + + "actor2" : { + "partStates" : { + "actors" : { + "position4" : { + "properties" : { + "offset" : [-3.5, 0.5] + } + }, + "position4-climax" : { + "properties" : { + "offset" : [-3.5, 0.5] + } + }, + "position4-postclimax" : { + "properties" : { + "offset" : [-3.5, 0.5] + } + }, + "position4-reset" : { + "properties" : { + "offset" : [-3.5, 0.5] + } + }, + "position5" : { + "frameProperties" : { + "offset" : [[-2.625, -0.125], [-2.625, -0.125], [-2.625, -0.125], [-2.75, 0], [-2.75, 0], [-2.75, 0], [-2.75, 0.125], [-2.75, 0.125], [-2.75, 0.125], [-2.75, 0.125], [-2.75, 0.125], [-2.75, 0], [-2.75, 0]] + } + }, + "position5-climax" : { + "frameProperties" : { + "offset" : [[-2.625, -0.125], [-2.625, -0.125], [-2.75, 0], [-2.75, 0.125], [-2.75, 0]] + } + }, + "position5-postclimax" : { + "frameProperties" : { + "offset" : [[-2.625, -0.125], [-2.625, -0.125], [-2.625, -0.125], [-2.75, 0], [-2.75, 0], [-2.75, 0], [-2.75, 0.125], [-2.75, 0.125], [-2.75, 0.125], [-2.75, 0.125], [-2.75, 0.125], [-2.75, 0], [-2.75, 0]] + } + }, + "position5-reset" : { + "frameProperties" : { + "offset" : [[-2.625, -0.125], [-2.625, -0.125], [-2.75, 0], [-2.75, 0.125], [-2.75, 0]] + } + }, + "position6" : { + "properties" : { + "offset" : [-1.625, 0] + } + }, + "position6-climax" : { + "properties" : { + "offset" : [-1.625, 0] + } + }, + "position6-postclimax" : { + "properties" : { + "offset" : [-1.625, 0] + } + }, + "position6-reset" : { + "properties" : { + "offset" : [-1.625, 0] + } + } + } + } + }, + + "actor1-arm-front": { + "properties": { + "zLevel": 61 + } + }, + + "actor2-tail": { + "partStates" : { + "actors" : { + "position4" : { + "frameProperties" : { + "zLevel" : [14,14,14,14,14] + } + }, + "position4-climax" : { + "frameProperties" : { + "zLevel" : [14] + } + }, + "position4-postclimax" : { + "frameProperties" : { + "zLevel" : [14,14,14,14,14,14,14,14,14,14,14,14,14] + } + }, + "position4-reset" : { + "frameProperties" : { + "zLevel" : [14] + } + }, + "position5" : { + "frameProperties" : { + "zLevel" : [14,14,14,14,14] + } + }, + "position5-climax" : { + "frameProperties" : { + "zLevel" : [14] + } + }, + "position5-postclimax" : { + "frameProperties" : { + "zLevel" : [14,14,14,14,14,14,14,14,14,14,14,14,14] + } + }, + "position5-reset" : { + "frameProperties" : { + "zLevel" : [14] + } + } + } + } + }, + + "actor2-groin" : { + "partStates" : { + "actors" : { + "position4" : { + "frameProperties" : { + "zLevel" : [42,42,42,42,42] + } + }, + "position4-climax" : { + "frameProperties" : { + "zLevel" : [42] + } + }, + "position4-postclimax" : { + "frameProperties" : { + "zLevel" : [42,42,42,42,42,42,42,42,42,42,42,42,42] + } + }, + "position4-reset" : { + "frameProperties" : { + "zLevel" : [42] + } + }, + "position5" : { + "frameProperties" : { + "zLevel" : [42,42,42,42,42] + } + }, + "position5-climax" : { + "frameProperties" : { + "zLevel" : [42] + } + }, + "position5-postclimax" : { + "frameProperties" : { + "zLevel" : [42,42,42,42,42,42,42,42,42,42,42,42,42] + } + }, + "position5-reset" : { + "frameProperties" : { + "zLevel" : [42] + } + } + } + } + } + } + } + } +} diff --git a/positions/twoactors/reverse_cowgirl/reverse_cowgirl.config b/positions/twoactors/reverse_cowgirl/reverse_cowgirl.config index 84c3ed72..1fd78a49 100644 --- a/positions/twoactors/reverse_cowgirl/reverse_cowgirl.config +++ b/positions/twoactors/reverse_cowgirl/reverse_cowgirl.config @@ -15,15 +15,15 @@ "interactionType": ["direct",null,null,null], "dialog" : { - "default" : "/dialog/sexbound//positions/revers_cowgirl/defaultcowgirlfull.config", - "apex" : "/dialog/sexbound//positions/revers_cowgirl/apexcowgirl.config", - "avian" : "/dialog/sexbound//positions/revers_cowgirl/aviancowgirl.config", - "fenerox" : "/dialog/sexbound//positions/revers_cowgirl/feneroxcowgirl.config", - "floran" : "/dialog/sexbound//positions/revers_cowgirl/florancowgirl.config", - "glitch" : "/dialog/sexbound//positions/revers_cowgirl/glitchcowgirl.config", - "human" : "/dialog/sexbound//positions/revers_cowgirl/humancowgirl.config", - "hylotl" : "/dialog/sexbound//positions/revers_cowgirl/hylotlcowgirl.config", - "novakid" : "/dialog/sexbound//positions/revers_cowgirl/novakidcowgirl.config" + "default" : "/dialog/sexbound//positions/reversecowgirl/defaultcowgirlfull.config", + "apex" : "/dialog/sexbound//positions/reversecowgirl/apexcowgirl.config", + "avian" : "/dialog/sexbound//positions/reversecowgirl/aviancowgirl.config", + "fenerox" : "/dialog/sexbound//positions/reversecowgirl/feneroxcowgirl.config", + "floran" : "/dialog/sexbound//positions/reversecowgirl/florancowgirl.config", + "glitch" : "/dialog/sexbound//positions/reversecowgirl/glitchcowgirl.config", + "human" : "/dialog/sexbound//positions/reversecowgirl/humancowgirl.config", + "hylotl" : "/dialog/sexbound//positions/reversecowgirl/hylotlcowgirl.config", + "novakid" : "/dialog/sexbound//positions/reversecowgirl/novakidcowgirl.config" }, "containerOverlay" : [ diff --git a/projectiles/sexbound/climax/dripping.projectile b/projectiles/sexbound/climax/dripping.projectile new file mode 100644 index 00000000..d7b04f3f --- /dev/null +++ b/projectiles/sexbound/climax/dripping.projectile @@ -0,0 +1,19 @@ +{ + "projectileName": "dripping", + "image": "climax.png", + "physics": "climax", + "animationCycle": 1, + "frameNumber": 1, + "speed": 5, + "damagePoly": [ + [-0.25, -0.25], + [0.25, -0.25], + [0.25, 0.25], + [-0.25, 0.25] + ], + "damageKind": "hidden", + "onlyHitTerrain": true, + "hydrophobic": true, + + "scripts": ["/projectiles/sexbound/climax/climaxprojectile.lua"] +} diff --git a/scripts/sexbound/lib/sexbound.lua b/scripts/sexbound/lib/sexbound.lua index d3594d3f..b7a5990a 100644 --- a/scripts/sexbound/lib/sexbound.lua +++ b/scripts/sexbound/lib/sexbound.lua @@ -43,7 +43,8 @@ function Sexbound.new(maxActors) _timers = {}, _globalActorId = 0, _uiSyncTokens = {positions=0}, - _containsPlayer = false + _containsPlayer = false, + _sexMusicListeners = {} }, Sexbound_mt) -- Store UUID of the entity running this instance of Sexbound. @@ -270,6 +271,8 @@ function Sexbound:uninit() animator.setAnimationState("props", "none", true) animator.setAnimationState("actors", "none", true) + + self:forceStopSexMusic() --Stop sex music for all still listening actors return result1 and result2 end @@ -394,6 +397,8 @@ end --- Uninitializes each instance of Actor in the actors table. function Sexbound:uninitActors() + if not self._actors[1] then return true end -- No need to uninit anything if noone was here to begin with. Reduces log spam. + self:getLog():info("Uniniting Actors.") Sexbound.Messenger.get("main"):broadcast(self, "Sexbound:PrepareRemoveActor", {}, true) @@ -408,6 +413,10 @@ function Sexbound:uninitActors() self._actors = {} self._actorsOrdered = {} + + self._positions:filterPositions() --Reset positions as this bypasses normal "actor leaves" check and we need to be in idle for when someone else joins + self._currentOrderId = 1 + self._currentOrderIndex = "" return true end @@ -619,25 +628,6 @@ end function Sexbound:helper_reassignAllRoles() if #self._actors == 0 then return end local sexConfig = self:getConfig().sex or {} - - --[[if sexConfig.allowSwitchRoles and self:getActorCount() == 2 then - -- Switch actors when actor 1 is female and actor 2 is male when actor 1 is not wearing a strapon. - if not self._actors[1]:getStatus():hasStatus("equipped_strapon") and self._actors[1]:getGender() == "female" and - (self._actors[2]:getGender() == "male" or self._actors[2]:getSubGender() == "futanari") then - self:switchActorRoles() - - -- An actor wearing a strapon should be switched to be actor 1. - elseif self._actors[2]:getStatus():hasStatus("equipped_strapon") then - self:switchActorRoles() - end - end - - -- Check if any actor needs to have its role forced - self:forEachActor(function(index, actor) - if actor:getForceRole() > 0 and actor:getForceRole() ~= index then - self:helper_forceActorRole(actor, index) - end - end)]] local curIndices, curPerms = self._positions:getCurrentPosition():getAvailableRoles() if curPerms[self._currentOrderId] then @@ -1182,12 +1172,32 @@ function Sexbound:startSexMusicForEntity(entityId) local songList = self._config.sex.sexMusicPool or {} local song = util.randomChoice(songList) world.sendEntityMessage(entityId, "playAltMusic", {song}, 1) + + -- Cache who is currently listening, but only once, so we can forcibly end the music on uninit + for _,id in ipairs(self._sexMusicListeners) do + if id == entityId then return end + end + + table.insert(self._sexMusicListeners, entityId) end function Sexbound:stopSexMusicForEntity(entityId) if self._config.noMusic then return end world.sendEntityMessage(entityId, "playAltMusic", {""}, 1) --Try to play a different, non existent song to reset progress of current song world.sendEntityMessage(entityId, "stopAltMusic", 1) + + -- Remove from cache + for i,id in ipairs(self._sexMusicListeners) do + if id == entityId then table.remove(self._sexMusicListeners, i) return end + end +end + +function Sexbound:forceStopSexMusic() + if self._config.noMusic then return end + for _,id in ipairs(self._sexMusicListeners) do + world.sendEntityMessage(id, "playAltMusic", {""}, 1) --Try to play a different, non existent song to reset progress of current song + world.sendEntityMessage(id, "stopAltMusic", 1) + end end function Sexbound:checkNodeCompatibility(args) diff --git a/scripts/sexbound/lib/sexbound/positions.lua b/scripts/sexbound/lib/sexbound/positions.lua index bb5f5e26..0d1bbde8 100644 --- a/scripts/sexbound/lib/sexbound/positions.lua +++ b/scripts/sexbound/lib/sexbound/positions.lua @@ -321,7 +321,7 @@ end --- Returns a reference to the Current Position. function Sexbound.Positions:getCurrentPosition() if self._index == -1 then return self._idlePosition end - return self._availablePositions[self._index] + return self._availablePositions[self._index] or self._idlePosition end function Sexbound.Positions:getParent() diff --git a/scripts/sexbound/override/common.lua b/scripts/sexbound/override/common.lua index 5033c9b1..d9e8f914 100644 --- a/scripts/sexbound/override/common.lua +++ b/scripts/sexbound/override/common.lua @@ -115,6 +115,7 @@ function Sexbound.Common:fetchCoreIdentity() self._speciesType = speciesConfig.sxbSpeciesType or nil self._usesHeat = (speciesConfig.sxbUseHeat or false) and (self._config.sex.enableHeatMechanic or false) + self._heatDuration = speciesConfig.sxbHeatDuration or 1800 end function Sexbound.Common:buildBodyTraits(gender) diff --git a/scripts/sexbound/override/player.lua b/scripts/sexbound/override/player.lua index 5deb6c78..0be0bfa9 100644 --- a/scripts/sexbound/override/player.lua +++ b/scripts/sexbound/override/player.lua @@ -72,7 +72,8 @@ function Sexbound.Player.new() _startItemsList = {"sexbound1-codex", "sexboundcustomizer"}, _loungeId = nil, _states = {"defaultState", "havingSexState"}, - _isSterilized = false + _isSterilized = false, + _isInfertile = false }, Sexbound.Player_mt) self:init(self, "player") @@ -123,6 +124,7 @@ function Sexbound.Player.new() self._stateMachine = self:helper_loadStateMachine() self._isSterilized = self._status:hasStatus("sterilized") + self._isInfertile = self._status:hasStatus("infertile") self._hasInited = true self:updateTraitEffects() @@ -136,6 +138,8 @@ function Sexbound.Player.new() -- Setup event listeners to notify player about changes to the sterilization status self._status:addEventListener("add", function(data) self:notifySterilizationChange(data) end) self._status:addEventListener("remove", function(data) self:notifySterilizationChange(data) end) + self._status:addEventListener("add", function(data) self:notifyInfertileChange(data) end) + self._status:addEventListener("remove", function(data) self:notifyInfertileChange(data) end) return self end @@ -213,10 +217,6 @@ function Sexbound.Player:showCustomizerUI(args) if "function" ~= type(player.interact) then return end xpcall(function() local _loadedConfig = root.assetJson("/interface/sexbound/customizer/customizer.config") - --_loadedConfig.config.statistics = self:getStatistics():getStatistics() - --_loadedConfig.config.currentGender = self._subGender._currentGender - --_loadedConfig.config.subGenders = self._subGender:getAllSubGenders() - --_loadedConfig.config.sterilized = self._status:hasStatus("sterilized") player.interact("ScriptPane", _loadedConfig, player.id()) end, function(err) sb.logError("Unable to load Sexbound Customizer UI config.") @@ -230,6 +230,7 @@ function Sexbound.Player:handleGetCutomizerData(args) _loadedConfig.currentGender = self._subGender._currentGender _loadedConfig.subGenders = self._subGender:getAllSubGenders() _loadedConfig.sterilized = self._status:hasStatus("sterilized") + _loadedConfig.infertile = self._status:hasStatus("infertile") return _loadedConfig end @@ -307,6 +308,29 @@ function Sexbound.Player:notifySterilizationChange(data) if sterilized then status.removeEphemeralEffect("sexbound_custom_ovulating") end -- Remove ovulation cycle effect when sterilized end +function Sexbound.Player:notifyInfertileChange(data) + if data.name ~= "infertile" then return end + + local notifications = self:getNotifications() or {} + notifications = notifications.events or {} + notifications = notifications.infertility or {} + + local infertile = data.query == "add" + infertile = tostring(infertile) + + local text = notifications[infertile] + if text then + world.sendEntityMessage(entity.id(), "queueRadioMessage", { + messageId = "sexbound_infertility", + unique = false, + text = text + }) + end + + self._isInfertile = infertile + if infertile then status.removeEphemeralEffect("sexbound_custom_ovulating") end -- Remove ovulation cycle effect when infertile +end + function Sexbound.Player:handleSyncStorage(newData) newData = self:fixPregnancyData(newData) storage = util.mergeTable(storage, newData or {}) diff --git a/scripts/sexbound/override/player/arousal.lua b/scripts/sexbound/override/player/arousal.lua index 41ee8c32..97328696 100644 --- a/scripts/sexbound/override/player/arousal.lua +++ b/scripts/sexbound/override/player/arousal.lua @@ -42,7 +42,7 @@ function Sexbound.Player.Arousal:update(dt) storage.sexbound.heatCycle = heatTimer if heatTimer <= 0 then -- Trigger heat - status.addEphemeralEffect("sexbound_arousal_heat") + status.addEphemeralEffect("sexbound_arousal_heat", self._parent._heatDuration or 1800) end end else diff --git a/scripts/sexbound/override/player/pregnant.lua b/scripts/sexbound/override/player/pregnant.lua index 772ca7f4..4d9b6977 100644 --- a/scripts/sexbound/override/player/pregnant.lua +++ b/scripts/sexbound/override/player/pregnant.lua @@ -80,7 +80,7 @@ function Sexbound.Player.Pregnant:updatePeriodCycle(dt) if not enabled then return end -- Player cannot ovulate in the first place - ignore - if not self:canOvulate() or self:getParent()._isSterilized then return end + if not self:canOvulate() or self:getParent()._isSterilized or self:getParent()._isInfertile then return end local ovulating = status.statusProperty("sexbound_custom_ovulating", false) -- Currently active ovulation effect - ignore diff --git a/scripts/sexbound/plugins/climax/climax.lua b/scripts/sexbound/plugins/climax/climax.lua index bd01fb70..02baab6e 100644 --- a/scripts/sexbound/plugins/climax/climax.lua +++ b/scripts/sexbound/plugins/climax/climax.lua @@ -5,6 +5,7 @@ if not SXB_RUN_TESTS then require("/scripts/sexbound/lib/sexbound/actor/plugin.lua") require("/scripts/sexbound/plugins/climax/scriptedclimax/scenario1.lua") + require("/scripts/sexbound/plugins/climax/inflation.lua") end Sexbound.Actor.Climax = Sexbound.Actor.Plugin:new() @@ -23,7 +24,7 @@ function Sexbound.Actor.Climax:new(parent, config) _scenarios = {}, _soundEffects = {}, _timer = {}, - _inflation = 0, + _inflation = {}, _dripTimer = 0 }, Sexbound.Actor.Climax_mt) @@ -48,6 +49,10 @@ function Sexbound.Actor.Climax:new(parent, config) _self:loadSoundEffects() end + if _self._config.enableInflation then + _self._inflation = Inflation:new(_self, _self._config) + end + -- Load scripted climax scenarios table.insert(_self._scenarios, Sexbound.ScriptedClimax.Scenario1:new(_self)) @@ -404,7 +409,11 @@ function Sexbound.Actor.Climax:shoot(...) world.sendEntityMessage(_actor:getEntityId(), "Sexbound:Climax:Feed") end if (interaction == "direct" or interaction == "toy_dick") and self._config.enableInflation then - Sexbound.Messenger.get('main'):send(self, _actor, "Sexbound:Climax:Inflate", self:getInflationRate()) + local genital = self._parent:getGenitalType() + local liquid = self._config.projectileLiquid[self._parent:getSpecies()] or self._config.projectileLiquid["default"] + liquid = liquid[genital] + Sexbound.Messenger.get('main'):send(self, _actor, "Sexbound:Climax:Inflate", self._inflation:generateLoad(liquid, self:getInflationRate())) + end end end @@ -488,15 +497,21 @@ function Sexbound.Actor.Climax:spawnItem(...) end --- Increases level of inflation -function Sexbound.Actor.Climax:inflate(amount) - amount = amount or 0.1 - local oldAmount = self._inflation - local actor = self._parent - self._inflation = self._inflation + amount - self:getLog():debug("Actor "..actor:getActorNumber().." gotten inflation request. New value: "..self._inflation) - if oldAmount < self:getInflationThreshold() and self._inflation >= self:getInflationThreshold() then +function Sexbound.Actor.Climax:inflate(inflationLoad) + -- Regenerate received inflation load (fills in potential invalid values) + inflationLoad = self._inflation:generateLoad(inflationLoad.liquid, inflationLoad.quantity) + + -- Add new inflation load + local oldAmount = self._inflation:getTotalInflation() + self._inflation:addLoad(inflationLoad) + local newAmount = self._inflation:getTotalInflation() + + -- Handle case where total inflation passed the treshold + if oldAmount < self:getInflationThreshold() and newAmount >= self:getInflationThreshold() then + local actor = self._parent actor:resetParts(actor:getAnimationState(), actor:getSpecies(), actor:getGender(), actor:resetDirectives(actor:getActorNumber())) - self:getLog():debug("Actor "..actor:getActorNumber().." passing threshold - reseting actor to show inflated belly sprite.") + self:getLog():debug("Actor "..actor:getActorNumber().." ("..actor:getName()..") passed inflation threshold; ".. + "reseting actor to show inflated belly sprite.") end end @@ -505,22 +520,62 @@ function Sexbound.Actor.Climax:inflationDrip(dt) self._dripTimer = math.max(0, self._dripTimer - dt) if self._dripTimer == 0 then - local oldAmount = self._inflation + local oldAmount = self._inflation:getTotalInflation() if oldAmount > 0 then local actor = self._parent - self._inflation = math.max(0, self._inflation - util.randomInRange(self:getDripRate()) * dt) - self:getLog():debug("Actor "..actor:getActorNumber().." dripping. New amount: "..self._inflation) - if oldAmount >= self:getInflationThreshold() and self._inflation < self:getInflationThreshold() then - actor:resetParts(actor:getAnimationState(), actor:getSpecies(), actor:getGender(), actor:resetDirectives(actor:getActorNumber())) - self:getLog():debug("Actor "..actor:getActorNumber().." passing threshold - reseting actor to hide inflated belly sprite.") - end - + self:getLog():debug("Actor "..actor:getActorNumber().." ("..actor:getName()..") dripping.") + + -- Remove drip quantity from inflation + local dripQuantity = math.min(util.randomInRange(self:getDripRate()) * dt, self._inflation:getTotalInflation()) + local removedLiquids = self._inflation:removeQuantity(dripQuantity) + local newAmount = self._inflation:getTotalInflation() + + -- Spawn particles if enabled if self._config.enableClimaxParticles then animator.burstParticleEmitter("insemination-drip" .. actor:getActorNumber()) end + + -- Spawn liquid projectiles if enabled + if self._config.enableSpawnLiquids and removedLiquids then + local projectileName = "dripping" + local spawnPosition = actor:getClimaxSpawnPosition() or {0.0, 0.0} + local sourceEntityId = actor:getEntityId() + local spawnDirection = {0, -1} + local trackSourceEntity = false + local handler = {} + + -- Generate liquid spawn action for projectile + local actionOnReap = {} + local actionCount = 0 + for liquid, quantity in pairs(removedLiquids) do + self:getLog():debug("Actor "..actor:getActorNumber().." dripping. Spawning "..quantity.." "..liquid..".") + if liquid then + actionCount = actionCount + 1 + actionOnReap[actionCount] = { + action = "liquid", + liquid = liquid, + quantity = quantity + } + end + end + + -- Spawn projectile if at least one action was generated + if actionCount > 0 then + self:getLog():debug("Actor "..actor:getActorNumber().." dripping. Creating projectile.") + handler.actionOnReap = actionOnReap + world.spawnProjectile(projectileName, spawnPosition, sourceEntityId, spawnDirection, trackSourceEntity, handler) + end + end + + -- Handle case where total inflation lowered under the treshold + if oldAmount >= self:getInflationThreshold() and newAmount < self:getInflationThreshold() then + actor:resetParts(actor:getAnimationState(), actor:getSpecies(), actor:getGender(), actor:resetDirectives(actor:getActorNumber())) + self:getLog():debug("Actor "..actor:getActorNumber().." ("..actor:getName()..") passed inflation threshold; ".. + "reseting actor to hide inflated belly sprite.") + end end - self._dripTimer = math.min(2, 1 / self._inflation ^ self:getDripSpeed()) + self._dripTimer = math.min(2, 1 / self._inflation:getTotalInflation() ^ self:getDripSpeed()) end end @@ -642,7 +697,7 @@ end --- Returns the current inflation level offsetted by pregnancy function Sexbound.Actor.Climax:getAdjustedInflation() - local val = self._inflation + local val = self._inflation:getTotalInflation() if self:getParent():isVisiblyPregnant() then val = val + self:getInflationThreshold() end @@ -656,7 +711,7 @@ end --- Returns whether or not this actor is currently inflated function Sexbound.Actor.Climax:isInflated() - return self._inflation >= self:getInflationThreshold() + return self._inflation:getTotalInflation() >= self:getInflationThreshold() end --- Returns a sound effect by specifed name or the table of sound effects. diff --git a/scripts/sexbound/plugins/climax/inflation.lua b/scripts/sexbound/plugins/climax/inflation.lua new file mode 100644 index 00000000..de369223 --- /dev/null +++ b/scripts/sexbound/plugins/climax/inflation.lua @@ -0,0 +1,137 @@ +Inflation = {} +Inflation_mt = { + __index = Inflation +} + +function Inflation:new(parent, config) + local _self = setmetatable({ + _logPrefix = "INFL", + _parent = parent, + _config = config, + _actor = {}, + _log = {}, + _defaultLiquidId = config.projectileLiquid["default"]["male"] or "semen", + _loads = {}, + _loadCount = 0, + _totalInflation = 0 + }, Inflation_mt) + + _self._log = Sexbound.Log:new(_self._logPrefix, _self._parent:getRoot():getConfig()) + _self._actor = _self._parent._parent + _self:getLog():info("Inited Inflation Tracker for ".._self:getActorLogPrefix()) + + return _self +end + +function Inflation:addLoad(inflationLoad) + inflationLoad = { + liquid = inflationLoad.liquid or self._defaultLiquidId, + quantity = inflationLoad.quantity or 0 + } + if inflationLoad.quantity <= 0 then return end + + self:getLog():debug(self:getActorLogPrefix().." received inflation load. ".. + "Liquid: ["..inflationLoad.liquid.."] ".. + "Quantity: ["..inflationLoad.quantity.."]") + + -- Add to the last load if it has the same liquid id + if self._loadCount > 0 and self._loads[self._loadCount].liquid == inflationLoad.liquid then + local currentQuantity = self._loads[self._loadCount].quantity + local mergedQuantity = currentQuantity + inflationLoad.quantity + self._loads[self._loadCount].quantity = mergedQuantity + + self:getLog():debug(self:getActorLogPrefix().." same liquid as previous; merging loads. ".. + "Previous load quantity: ["..currentQuantity.."] ".. + "Merged quantity: ["..mergedQuantity.."]") + + else + self:getLog():debug(self:getActorLogPrefix().." liquid is different from previous load; adding new load.") + + self._loadCount = self._loadCount + 1 + self._loads[self._loadCount] = inflationLoad + end + + self._totalInflation = self._totalInflation + inflationLoad.quantity + + self:getLog():debug(self:getActorLogPrefix().." has ["..self:getloadCount().."] inflation loads. ".. + "Total inflation: [".. self:getTotalInflation().."]") +end + +function Inflation:removeQuantity(quantity) + if self._totalInflation <= 0 or self._loadCount <= 0 then return end + + local toRemove = quantity or 0 + local removedLiquids = {} + while toRemove > 0 and self._loadCount > 0 do + local lastLoadQuantity = self._loads[self._loadCount].quantity + self:getLog():debug(self:getActorLogPrefix().." removing ["..toRemove.."] to total inflation.") + self:getLog():debug(self:getActorLogPrefix().." load #"..self._loadCount.." contributes ["..lastLoadQuantity.."] to total inflation.") + + if toRemove < lastLoadQuantity then + self:getLog():debug(self:getActorLogPrefix().." removing ["..toRemove.."] from load #"..self._loadCount) + + -- Add to removed liquid quantity + local currentlyRemoved = removedLiquids[self._loads[self._loadCount].liquid] or 0 + removedLiquids[self._loads[self._loadCount].liquid] = currentlyRemoved + toRemove + + -- Remove entire quantity from previous load + self._loads[self._loadCount].quantity = lastLoadQuantity - toRemove + self._totalInflation = self._totalInflation - toRemove + toRemove = 0 + + self:getLog():debug(self:getActorLogPrefix().." load #"..self._loadCount.." contributes ["..self._loads[self._loadCount].quantity.."] to total inflation.") + else + self:getLog():debug(self:getActorLogPrefix().." removing load #"..self._loadCount) + + -- Add to removed liquid quantity + local currentlyRemoved = removedLiquids[self._loads[self._loadCount].liquid] or 0 + removedLiquids[self._loads[self._loadCount].liquid] = currentlyRemoved + self._loads[self._loadCount].quantity + + -- Remove previous load + self._loads[self._loadCount] = nil + self._loadCount = math.max(0, self._loadCount - 1) + self._totalInflation = math.max(0, self._totalInflation - lastLoadQuantity) + + -- Update quantity to remove + toRemove = toRemove - lastLoadQuantity + end + end + + self:getLog():debug(self:getActorLogPrefix().." has ["..self:getloadCount().."] inflation loads. ".. + "Total inflation: [".. self:getTotalInflation().."]") + + return removedLiquids +end + +function Inflation:clear() + for i=0, self._loadCount do self._loads[i] = nil end + self._loadCount = 0 + self._totalInflation = 0 +end + +function Inflation:getTotalInflation() + return self._totalInflation +end + +function Inflation:getloadCount() + return self._loadCount +end + +function Inflation:generateLoad(liquid, quantity) + return { + liquid = liquid or self._defaultLiquidId, + quantity = quantity or 0.1 + } +end + +function Inflation:getLog() + return self._log +end + +function Inflation:getActor() + return self._actor +end + +function Inflation:getActorLogPrefix() + return "Actor "..self:getActor():getActorNumber().." ("..self:getActor():getName()..")" +end \ No newline at end of file diff --git a/scripts/sexbound/plugins/pregnant/baby.lua b/scripts/sexbound/plugins/pregnant/baby.lua index 2e15bf6b..a2e7fa03 100644 --- a/scripts/sexbound/plugins/pregnant/baby.lua +++ b/scripts/sexbound/plugins/pregnant/baby.lua @@ -151,7 +151,7 @@ function Baby:create(mother, father) color[i] = Sexbound.Util.rgbaToHex6(r) end - return color + return Sexbound.Util.messageEncode(color) --Encode color data cause Starbound sucks ass with Lua <-> JSON conversion end baby.bodyColor = generateColor(motherBodyIndex, fatherBodyIndex, bodyColorPool, bodyAllowBlending, bodyColorLambda, "bodyColor") @@ -399,18 +399,30 @@ function Baby:_convertBabyConfigToSpawnableNPC(babyConfig, babyName) local altColorAsFacialMaskSubColor = not not speciesConfig.altColorAsFacialMaskSubColor if babyConfig.bodyColor then + local c = babyConfig.bodyColor + local ci, cv = next(c) + local cl = string.len(tostring(ci)) + if cl == 7 or cl == 9 then c = Sexbound.Util.decodeMessage(c) end -- If color code is 7 (RGB+X) or 9 (RGBA+X) long, decode bodyColorPalette = "?replace" - for k,v in pairs(babyConfig.bodyColor) do bodyColorPalette = bodyColorPalette..";"..k.."="..v end + for k,v in pairs(c) do bodyColorPalette = bodyColorPalette..";"..k.."="..v end end if babyConfig.hairColor then + local c = babyConfig.hairColor + local ci, cv = next(c) + local cl = string.len(tostring(ci)) + if cl == 7 or cl == 9 then c = Sexbound.Util.decodeMessage(c) end -- If color code is 7 (RGB+X) or 9 (RGBA+X) long, decode hairColorPalette = "?replace" - for k,v in pairs(babyConfig.hairColor) do hairColorPalette = hairColorPalette..";"..k.."="..v end + for k,v in pairs(c) do hairColorPalette = hairColorPalette..";"..k.."="..v end end if babyConfig.undyColor then + local c = babyConfig.undyColor + local ci, cv = next(c) + local cl = string.len(tostring(ci)) + if cl == 7 or cl == 9 then c = Sexbound.Util.decodeMessage(c) end -- If color code is 7 (RGB+X) or 9 (RGBA+X) long, decode undyColorPalette = "?replace" - for k,v in pairs(babyConfig.undyColor) do undyColorPalette = undyColorPalette..";"..k.."="..v end + for k,v in pairs(c) do undyColorPalette = undyColorPalette..";"..k.."="..v end end -- Build directives like Starbound does diff --git a/scripts/sexbound/plugins/pregnant/pregnant.lua b/scripts/sexbound/plugins/pregnant/pregnant.lua index 8243800b..15fd2278 100644 --- a/scripts/sexbound/plugins/pregnant/pregnant.lua +++ b/scripts/sexbound/plugins/pregnant/pregnant.lua @@ -395,7 +395,18 @@ function Sexbound.Actor.Pregnant:thisActorHasEnoughFertility(otherActor) local sxbFertility = self:getParent():getIdentity().sxbFertility local fertility = sxbFertility or self:getFertility() - if status:hasOneOf({"sexbound_aroused_strong", "sexbound_aroused_heat"}) then fertility = fertility * 1.1 end -- Strong arousal buff and in heat buff give 10% higher base fertility + -- Apply fertility buff from current arousal/heat level based on config + local arousalBuff = 1 + if ((self._config.arousal.heat or {}).fertilityBonus or 0) > 0 and status:hasStatus("sexbound_aroused_heat") then -- Heat max priority + arousalBuff = self._config.arousal.heat.fertilityBonus + elseif ((self._config.arousal.heatWeak or {}).fertilityBonus or 0) > 0 and status:hasStatus("sexbound_aroused_heat_weak") then -- Heat weak should be exclusive to heat. Heat > arousal + arousalBuff = self._config.arousal.heatWeak.fertilityBonus + elseif ((self._config.arousal.strong or {}).fertilityBonus or 0) > 0 and status:hasStatus("sexbound_aroused_strong") then -- Strong arousal > arousal + arousalBuff = self._config.arousal.strong.fertilityBonus + elseif ((self._config.arousal.weak or {}).fertilityBonus or 0) > 0 and status:hasStatus("sexbound_aroused") then + arousalBuff = self._config.arousal.weak.fertilityBonus + end + fertility = fertility * arousalBuff local bonusCount = self:getCurrentInseminations(otherActor) local bonusMax = self:getConfig().fertilityBonusMax or 0.6 @@ -671,6 +682,8 @@ function Sexbound.Actor.Pregnant:fetchRemoteConfig(mainConfig) self._config.immersionLevel = mainConfig.immersionLevel or 1 self._config.subGenderList = mainConfig.sex.subGenderList or {} self._config.subGenderChance = mainConfig.sex.subGenderChance or 0.01 + + self._config.arousal = mainConfig.arousal or {} end function Sexbound.Actor.Pregnant:handleInsemination(otherActor) @@ -750,7 +763,7 @@ function Sexbound.Actor.Pregnant:getPregnancyStage() elseif isPlayer == true then tempResult = 1 - (b.birthWorldTime / b.fullBirthWorldTime) -- Player world time calculation: reverse percentage of countdown else - tempResult = (world.day() + world.timeOfDay() - baby.fullBirthWorldTime) / (baby.birthWorldTime - baby.fullBirthWorldTime) -- Non-Player world time calculation: percentage diff time sinc start to total timespan + tempResult = (world.day() + world.timeOfDay() - b.fullBirthWorldTime) / (b.birthWorldTime - b.fullBirthWorldTime) -- Non-Player world time calculation: percentage diff time sinc start to total timespan end if tempResult > result then result = tempResult end end diff --git a/sexbound-changelog.json b/sexbound-changelog.json index 16ab5516..e33ff05a 100644 --- a/sexbound-changelog.json +++ b/sexbound-changelog.json @@ -1,4 +1,11 @@ { + "1.2_r1": [ + "» 1.2 Revision 1 «", + "- Added option to make an infertile character fertile again to customizer", + "- Fixed pregnancies for e.g. Sergal", + "- Fixed sex music not stopping when node gets destroyed", + "- More layer fixes, e.g. for the tentacleplant" + ], "1.2" : [ "» BIG TALK «", "- Completely reworked Sextalk. It's better, trust me", @@ -24,7 +31,7 @@ ], "1.1" : [ "» FOUNDING FAMILY «", - "- Integrated Lustbound Base", + "- Integrated \"Lustbound Base\"", "- Reworked pregnancies - cross-species, multi-babies, incest, color genetics, true kids, ...", "- Reworked NPC behavior - smarter arousal, special dialog for families, no perma-stuck pathfinding", "- Optional cumflation logic", diff --git a/sexbound.config b/sexbound.config index 487b3df3..cd9da428 100644 --- a/sexbound.config +++ b/sexbound.config @@ -1,5 +1,5 @@ { - "version": "1.2_h1", + "version": "1.2_r1", /** * A link to a reliable download / update web page for Sexbound. @@ -538,5 +538,49 @@ }, "allowIncest": true + }, + + /** + * Behaviour of the arousal/heat effects + * "playMoans" defines if the given effect should play occasional moans + * "moanChance" defines the chance a moan is played every interval of "moanFrequency" as percent (0-1) + * "moanFrequency" defines the time between two possible moans in seconds. 0 = off. + * "speedDebuff" defines a multiplier to how strong a potential speed debuff applied by the effect can be. 0 = off. + * "strengthDebuff" defines a multiplier to how strong a potential strength debuff applied by the effect can be. 0 = off. + * "fertilityBonus" defines a bonus given to the player's fertility with this effect, as percent multiplier. 0 = none + */ + "arousal": { + "weak": { + "playMoans": false, + "moanChance": 0.1, + "moanFrequency": 10, + "speedDebuff": 1, + "strengthDebuff": 1, + "fertilityBonus": 0 + }, + "strong": { + "playMoans": false, + "moanChance": 0.1, + "moanFrequency": 10, + "speedDebuff": 1, + "strengthDebuff": 1, + "fertilityBonus": 1.1 + }, + "heat": { + "playMoans": true, + "moanChance": 0.1, + "moanFrequency": 10, + "speedDebuff": 1, + "strengthDebuff": 1, + "fertilityBonus": 1.1 + }, + "heatWeak": { + "playMoans": true, + "moanChance": 0.1, + "moanFrequency": 10, + "speedDebuff": 1, + "strengthDebuff": 1, + "fertilityBonus": 0 + } } } diff --git a/stats/effects/sexbound_arousal/sexbound_arousal.lua b/stats/effects/sexbound_arousal/sexbound_arousal.lua new file mode 100644 index 00000000..3c64f5f6 --- /dev/null +++ b/stats/effects/sexbound_arousal/sexbound_arousal.lua @@ -0,0 +1,84 @@ +function fetchConfig() + self._config = {} + r,err = pcall(function() + local config = root.assetJson("/sexbound.config") + if config and config.arousal then config = config.arousal + self._config = config[self._effect] or {playMoans = false, moanChance = 0.1, moanFrequency = 10, speedDebuff = 1, strengthDebuff = 1, fertilityBonus = 0} + else sb.logError("Arousal effect could not fetch arousal config!") return end + end) + if not r then + sb.logError("Arousal effect could not fetch main config!") + return + end +end + +function fetchSpeciesConfig() + local species = world.entitySpecies(entity.id()) + self._speciesConfig = (species and config.getParameter(species)) or config.getParameter("default", {}) +end + +function setupEffects() + if (self._speciesConfig.strength or 0) ~= 0 and (self._config.strengthDebuff or 0) ~= 0 then + effect.addStatModifierGroup({ + { stat = "powerMultiplier", effectiveMultiplier = self._speciesConfig.strength * self._config.strengthDebuff } + }) + end +end + +function setupTimers() + self._timers = {} + self._doSpeed = 0 + + if (self._speciesConfig.speed or 0) ~= 0 and (self._speciesConfig.speedInterval or 0) > 0 and (self._speciesConfig.speedChance or 0) > 0 and (self._config.speedDebuff or 0) ~= 0 then + table.insert(self._timers, {action = "speed", value = self._speciesConfig.speed * self._config.speedDebuff, chance = self._speciesConfig.speedChance, timeMax = self._speciesConfig.speedInterval, timeCur = self._speciesConfig.speedDebuff}) + end + + if self._config.playMoans and (self._config.moanChance or 0) > 0 and (self._config.moanFrequency or 0) > 0 then + self._fetchMoans = true + table.insert(self._timers, {action = "moan", chance = self._config.moanChance, timeMax = self._config.moanFrequency, timeCur = self._config.moanFrequency}) + end +end + +function update(dt) { + promises:update() + + if not self._fetchMoans then + promises:add(world.sendEntityMessage(entity.id(), "Sexbound:Arousal:GetMoans"), function(moans) + self._moanSfx = moans or {} + if self._moanSfx.soundEffects then animator.setSoundPool("moan", self._moanSfx.soundEffects) end + end) + self._fetchMoans = false + end + + for _,t in ipairs(self._timers) do + t.timeCur = t.timeCur - dt + if t.timeCur <= 0 then + t.timeCur = t.timeMax + handleTimer(t) + end + end + + if self._doSpeed and self._doSpeed ~= 0 then + mcontroller.controlModifiers({ + speedModifier = self._doSpeed + }) + end +} + +function handleTimer(timer) + local a = timer.action + local v = timer.value + local c = timer.chance + local r = math.random() + + if a == "speed" then + if r <= c then self_doSpeed = v else self._doSpeed = 0 end + elseif a == "moan" then + if r <= c then + local pitch = self._moanSfx.pitch or 1.0 + if type(pitch) == "table" then pitch = pitch[1] + (math.random() * (pitch[2] - pitch[1])) end + animator.setSoundPitch("moan", pitch) + animator.playSound("moan") + end + end +end \ No newline at end of file diff --git a/stats/effects/sexbound_arousal_heat/sexbound_arousal_heat.animation b/stats/effects/sexbound_arousal/sexbound_arousal_debuff1/sexbound_arousal_debuff1.animation similarity index 100% rename from stats/effects/sexbound_arousal_heat/sexbound_arousal_heat.animation rename to stats/effects/sexbound_arousal/sexbound_arousal_debuff1/sexbound_arousal_debuff1.animation diff --git a/stats/effects/sexbound_arousal_debuff1/sexbound_arousal_debuff1.lua b/stats/effects/sexbound_arousal/sexbound_arousal_debuff1/sexbound_arousal_debuff1.lua similarity index 65% rename from stats/effects/sexbound_arousal_debuff1/sexbound_arousal_debuff1.lua rename to stats/effects/sexbound_arousal/sexbound_arousal_debuff1/sexbound_arousal_debuff1.lua index 97a6d876..eeddde80 100644 --- a/stats/effects/sexbound_arousal_debuff1/sexbound_arousal_debuff1.lua +++ b/stats/effects/sexbound_arousal/sexbound_arousal_debuff1/sexbound_arousal_debuff1.lua @@ -1,7 +1,17 @@ +require "/scripts/messageutil.lua" +require "/stats/effects/sexbound_arousal/sexbound_arousal.lua" + function init() + self._effect = "heat" + local entityId = entity.id() status.setStatusProperty("sexbound_aroused", true) world.sendEntityMessage(entityId, "Sexbound:Pregnant:AddStatus", "sexbound_aroused") + + fetchConfig() + fetchSpeciesConfig() + setupEffects() + setupTimers() end function uninit() diff --git a/stats/effects/sexbound_arousal/sexbound_arousal_debuff1/sexbound_arousal_debuff1.statuseffect b/stats/effects/sexbound_arousal/sexbound_arousal_debuff1/sexbound_arousal_debuff1.statuseffect new file mode 100644 index 00000000..48b202fb --- /dev/null +++ b/stats/effects/sexbound_arousal/sexbound_arousal_debuff1/sexbound_arousal_debuff1.statuseffect @@ -0,0 +1,10 @@ +{ + "name" : "sexbound_arousal_debuff1", + "blockingStat" : "sexboundImmunity", + "defaultDuration" : 999, + "effectConfig" : {"default": {"strength": 0, "speed": 0, "speedInterval": 0, "speedChance": 0}}, + "icon" : "/interface/statuses/arousal1.png", + "label" : "Horny", + "scripts" : [ "sexbound_arousal_debuff1.lua" ], + "animationConfig" : "sexbound_arousal_debuff1.animation" +} diff --git a/stats/effects/sexbound_arousal_heat_weak/sexbound_arousal_heat_weak.animation b/stats/effects/sexbound_arousal/sexbound_arousal_debuff2/sexbound_arousal_debuff2.animation similarity index 100% rename from stats/effects/sexbound_arousal_heat_weak/sexbound_arousal_heat_weak.animation rename to stats/effects/sexbound_arousal/sexbound_arousal_debuff2/sexbound_arousal_debuff2.animation diff --git a/stats/effects/sexbound_arousal/sexbound_arousal_debuff2/sexbound_arousal_debuff2.lua b/stats/effects/sexbound_arousal/sexbound_arousal_debuff2/sexbound_arousal_debuff2.lua new file mode 100644 index 00000000..4377515f --- /dev/null +++ b/stats/effects/sexbound_arousal/sexbound_arousal_debuff2/sexbound_arousal_debuff2.lua @@ -0,0 +1,21 @@ +require "/scripts/messageutil.lua" +require "/stats/effects/sexbound_arousal/sexbound_arousal.lua" + +function init() + self._effect = "heat" + + local entityId = entity.id() + status.setStatusProperty("sexbound_aroused_strong", true) + world.sendEntityMessage(entityId, "Sexbound:Pregnant:AddStatus", "sexbound_aroused_strong") + + fetchConfig() + fetchSpeciesConfig() + setupEffects() + setupTimers() +end + +function uninit() + local entityId = entity.id() + status.setStatusProperty("sexbound_aroused_strong", false) + world.sendEntityMessage(entityId, "Sexbound:Pregnant:RemoveStatus", "sexbound_aroused_strong") +end diff --git a/stats/effects/sexbound_arousal/sexbound_arousal_debuff2/sexbound_arousal_debuff2.statuseffect b/stats/effects/sexbound_arousal/sexbound_arousal_debuff2/sexbound_arousal_debuff2.statuseffect new file mode 100644 index 00000000..b4c02861 --- /dev/null +++ b/stats/effects/sexbound_arousal/sexbound_arousal_debuff2/sexbound_arousal_debuff2.statuseffect @@ -0,0 +1,10 @@ +{ + "name" : "sexbound_arousal_debuff2", + "blockingStat" : "sexboundImmunity", + "defaultDuration" : 999, + "effectConfig" : {"default": {"strength": 0.9, "speed": 0.9, "speedInterval": 10, "speedChance": 0.1}}, + "icon" : "/interface/statuses/arousal2.png", + "label" : "Pent up", + "scripts" : [ "sexbound_arousal_debuff2.lua" ], + "animationConfig" : "sexbound_arousal_debuff2.animation" +} diff --git a/stats/effects/sexbound_arousal/sexbound_arousal_heat/sexbound_arousal_heat.animation b/stats/effects/sexbound_arousal/sexbound_arousal_heat/sexbound_arousal_heat.animation new file mode 100644 index 00000000..ff10b1fb --- /dev/null +++ b/stats/effects/sexbound_arousal/sexbound_arousal_heat/sexbound_arousal_heat.animation @@ -0,0 +1,5 @@ +{ + "sounds" : { + "moan": [] + } +} diff --git a/stats/effects/sexbound_arousal/sexbound_arousal_heat/sexbound_arousal_heat.lua b/stats/effects/sexbound_arousal/sexbound_arousal_heat/sexbound_arousal_heat.lua new file mode 100644 index 00000000..43333cc3 --- /dev/null +++ b/stats/effects/sexbound_arousal/sexbound_arousal_heat/sexbound_arousal_heat.lua @@ -0,0 +1,21 @@ +require "/scripts/messageutil.lua" +require "/stats/effects/sexbound_arousal/sexbound_arousal.lua" + +function init() + self._effect = "heat" + + local entityId = entity.id() + status.setStatusProperty("sexbound_aroused_heat", true) + world.sendEntityMessage(entityId, "Sexbound:Pregnant:AddStatus", "sexbound_aroused_heat") + + fetchConfig() + fetchSpeciesConfig() + setupEffects() + setupTimers() +end + +function uninit() + local entityId = entity.id() + status.setStatusProperty("sexbound_aroused_heat", false) + world.sendEntityMessage(entityId, "Sexbound:Pregnant:RemoveStatus", "sexbound_aroused_heat") +end diff --git a/stats/effects/sexbound_arousal_heat/sexbound_arousal_heat.statuseffect b/stats/effects/sexbound_arousal/sexbound_arousal_heat/sexbound_arousal_heat.statuseffect similarity index 74% rename from stats/effects/sexbound_arousal_heat/sexbound_arousal_heat.statuseffect rename to stats/effects/sexbound_arousal/sexbound_arousal_heat/sexbound_arousal_heat.statuseffect index 2fdcb360..f5f1f040 100644 --- a/stats/effects/sexbound_arousal_heat/sexbound_arousal_heat.statuseffect +++ b/stats/effects/sexbound_arousal/sexbound_arousal_heat/sexbound_arousal_heat.statuseffect @@ -2,7 +2,7 @@ "name" : "sexbound_arousal_heat", "blockingStat" : "sexboundImmunity", "defaultDuration" : 1800, - "effectConfig" : {}, + "effectConfig" : {"default": {"strength": 0.9, "speed": 0.9, "speedInterval": 10, "speedChance": 0.15}}, "icon" : "/interface/statuses/heat.png", "label" : "In Heat", "scripts" : [ "sexbound_arousal_heat.lua" ], diff --git a/stats/effects/sexbound_arousal/sexbound_arousal_heat_weak/sexbound_arousal_heat_weak.animation b/stats/effects/sexbound_arousal/sexbound_arousal_heat_weak/sexbound_arousal_heat_weak.animation new file mode 100644 index 00000000..ff10b1fb --- /dev/null +++ b/stats/effects/sexbound_arousal/sexbound_arousal_heat_weak/sexbound_arousal_heat_weak.animation @@ -0,0 +1,5 @@ +{ + "sounds" : { + "moan": [] + } +} diff --git a/stats/effects/sexbound_arousal/sexbound_arousal_heat_weak/sexbound_arousal_heat_weak.lua b/stats/effects/sexbound_arousal/sexbound_arousal_heat_weak/sexbound_arousal_heat_weak.lua new file mode 100644 index 00000000..687e01c1 --- /dev/null +++ b/stats/effects/sexbound_arousal/sexbound_arousal_heat_weak/sexbound_arousal_heat_weak.lua @@ -0,0 +1,21 @@ +require "/scripts/messageutil.lua" +require "/stats/effects/sexbound_arousal/sexbound_arousal.lua" + +function init() + self._effect = "heatWeak" + + local entityId = entity.id() + status.setStatusProperty("sexbound_aroused_heat_weak", true) + world.sendEntityMessage(entityId, "Sexbound:Pregnant:AddStatus", "sexbound_aroused_heat_weak") + + fetchConfig() + fetchSpeciesConfig() + setupEffects() + setupTimers() +end + +function uninit() + local entityId = entity.id() + status.setStatusProperty("sexbound_aroused_heat_weak", false) + world.sendEntityMessage(entityId, "Sexbound:Pregnant:RemoveStatus", "sexbound_aroused_heat_weak") +end diff --git a/stats/effects/sexbound_arousal_heat_weak/sexbound_arousal_heat_weak.statuseffect b/stats/effects/sexbound_arousal/sexbound_arousal_heat_weak/sexbound_arousal_heat_weak.statuseffect similarity index 75% rename from stats/effects/sexbound_arousal_heat_weak/sexbound_arousal_heat_weak.statuseffect rename to stats/effects/sexbound_arousal/sexbound_arousal_heat_weak/sexbound_arousal_heat_weak.statuseffect index ac2c3a7a..fa5e7c59 100644 --- a/stats/effects/sexbound_arousal_heat_weak/sexbound_arousal_heat_weak.statuseffect +++ b/stats/effects/sexbound_arousal/sexbound_arousal_heat_weak/sexbound_arousal_heat_weak.statuseffect @@ -2,7 +2,7 @@ "name" : "sexbound_arousal_heat_weak", "blockingStat" : "sexboundImmunity", "defaultDuration" : 900, - "effectConfig" : {}, + "effectConfig" : {"default": {"strength": 0.95, "speed": 0.95, "speedInterval": 10, "speedChance": 0.1}}, "icon" : "/interface/statuses/heat_weak.png", "label" : "In Heat (Medicated)", "scripts" : [ "sexbound_arousal_heat_weak.lua" ], diff --git a/stats/effects/sexbound_arousal_debuff1/sexbound_arousal_debuff1.statuseffect b/stats/effects/sexbound_arousal_debuff1/sexbound_arousal_debuff1.statuseffect deleted file mode 100644 index fbbe8f33..00000000 --- a/stats/effects/sexbound_arousal_debuff1/sexbound_arousal_debuff1.statuseffect +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name" : "sexbound_arousal_debuff1", - "blockingStat" : "sexboundImmunity", - "defaultDuration" : 999, - "effectConfig" : {}, - "icon" : "/interface/statuses/arousal1.png", - "label" : "Horny", - "scripts" : [ "sexbound_arousal_debuff1.lua" ] -} diff --git a/stats/effects/sexbound_arousal_debuff2/sexbound_arousal_debuff2.lua b/stats/effects/sexbound_arousal_debuff2/sexbound_arousal_debuff2.lua deleted file mode 100644 index 7c2ec890..00000000 --- a/stats/effects/sexbound_arousal_debuff2/sexbound_arousal_debuff2.lua +++ /dev/null @@ -1,31 +0,0 @@ -function init() - local entityId = entity.id() - status.setStatusProperty("sexbound_aroused_strong", true) - world.sendEntityMessage(entityId, "Sexbound:Pregnant:AddStatus", "sexbound_aroused_strong") - - effect.addStatModifierGroup({ - { stat = "powerMultiplier", effectiveMultiplier = 0.9 } - }) - - self._effectTimer = 0 - self._doEffect = false -end - -function update(dt) - self._effectTimer = self._effectTimer - dt - if self._effectTimer <= 0 then - if math.random() <= 0.1 then self._doEffect = true else self._doEffect = false end - self._effectTimer = 10 - end - if self._doEffect then - mcontroller.controlModifiers({ - speedModifier = 0.9 - }) - end -end - -function uninit() - local entityId = entity.id() - status.setStatusProperty("sexbound_aroused_strong", false) - world.sendEntityMessage(entityId, "Sexbound:Pregnant:RemoveStatus", "sexbound_aroused_strong") -end diff --git a/stats/effects/sexbound_arousal_debuff2/sexbound_arousal_debuff2.statuseffect b/stats/effects/sexbound_arousal_debuff2/sexbound_arousal_debuff2.statuseffect deleted file mode 100644 index a83ae60c..00000000 --- a/stats/effects/sexbound_arousal_debuff2/sexbound_arousal_debuff2.statuseffect +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name" : "sexbound_arousal_debuff2", - "blockingStat" : "sexboundImmunity", - "defaultDuration" : 999, - "effectConfig" : {}, - "icon" : "/interface/statuses/arousal2.png", - "label" : "Pent up", - "scripts" : [ "sexbound_arousal_debuff2.lua" ] -} diff --git a/stats/effects/sexbound_arousal_heat/sexbound_arousal_heat.lua b/stats/effects/sexbound_arousal_heat/sexbound_arousal_heat.lua deleted file mode 100644 index a7825856..00000000 --- a/stats/effects/sexbound_arousal_heat/sexbound_arousal_heat.lua +++ /dev/null @@ -1,50 +0,0 @@ -require "/scripts/messageutil.lua" - -function init() - local entityId = entity.id() - status.setStatusProperty("sexbound_aroused_heat", true) - world.sendEntityMessage(entityId, "Sexbound:Pregnant:AddStatus", "sexbound_aroused_heat") - - effect.addStatModifierGroup({ - { stat = "powerMultiplier", effectiveMultiplier = 0.9 } - }) - - self._effectTimer = 0 - self._doEffect = false - self._moanSfx = {} - self._triedToFetch = false -end - -function update(dt) - promises:update() - if not self._triedToFetch then - promises:add(world.sendEntityMessage(entity.id(), "Sexbound:Arousal:GetMoans"), function(moans) - self._moanSfx = moans or {} - if self._moanSfx.soundEffects then animator.setSoundPool("moan", self._moanSfx.soundEffects) end - end) - self._triedToFetch = true - end - self._effectTimer = self._effectTimer - dt - if self._effectTimer <= 0 then - local rng = math.random() - if rng <= 0.1 then - self._doEffect = true - local pitch = self._moanSfx.pitch or 1.0 - if type(pitch) == "table" then pitch = pitch[1] + (math.random() * (pitch[2] - pitch[1])) end - animator.setSoundPitch("moan", pitch) - animator.playSound("moan") - else self._doEffect = false end - self._effectTimer = 10 - end - if self._doEffect then - mcontroller.controlModifiers({ - speedModifier = 0.9 - }) - end -end - -function uninit() - local entityId = entity.id() - status.setStatusProperty("sexbound_aroused_heat", false) - world.sendEntityMessage(entityId, "Sexbound:Pregnant:RemoveStatus", "sexbound_aroused_heat") -end diff --git a/stats/effects/sexbound_arousal_heat_weak/sexbound_arousal_heat_weak.lua b/stats/effects/sexbound_arousal_heat_weak/sexbound_arousal_heat_weak.lua deleted file mode 100644 index 94ab43de..00000000 --- a/stats/effects/sexbound_arousal_heat_weak/sexbound_arousal_heat_weak.lua +++ /dev/null @@ -1,40 +0,0 @@ -require "/scripts/messageutil.lua" - -function init() - local entityId = entity.id() - status.setStatusProperty("sexbound_aroused_heat_weak", true) - world.sendEntityMessage(entityId, "Sexbound:Pregnant:AddStatus", "sexbound_aroused_heat_weak") - - effect.addStatModifierGroup({ - { stat = "powerMultiplier", effectiveMultiplier = 0.95 } - }) - - self._effectTimer = 0 - self._moanSfx = {} - self._triedToFetch = false -end - -function update(dt) - promises:update() - promises:add(world.sendEntityMessage(entity.id(), "Sexbound:Arousal:GetMoans"), function(moans) - self._moanSfx = moans or {} - if self._moanSfx.soundEffects then animator.setSoundPool("moan", self._moanSfx.soundEffects) end - end) - self._effectTimer = self._effectTimer - dt - if self._effectTimer <= 0 then - local rng = math.random() - if rng <= 0.05 then - local pitch = self._moanSfx.pitch or 1.0 - if type(pitch) == "table" then pitch = pitch[1] + (math.random() * (pitch[2] - pitch[1])) end - animator.setSoundPitch("moan", pitch) - animator.playSound("moan") - end - self._effectTimer = 10 - end -end - -function uninit() - local entityId = entity.id() - status.setStatusProperty("sexbound_aroused_heat_weak", false) - world.sendEntityMessage(entityId, "Sexbound:Pregnant:RemoveStatus", "sexbound_aroused_heat_weak") -end