diff --git a/GainStation13/code/datums/traits.dm b/GainStation13/code/datums/traits.dm index 8f4877fc8f..7196ca9423 100644 --- a/GainStation13/code/datums/traits.dm +++ b/GainStation13/code/datums/traits.dm @@ -57,3 +57,20 @@ /datum/quirk/slimespeaker/remove() var/mob/living/M = quirk_holder M?.remove_language(/datum/language/slime) + +/datum/quirk/SpawnWithWheelchair + name = "Mobility Assistance" + desc = "After your last failed fitness test, you were advised to start using a hoverchair" + +/datum/quirk/SpawnWithWheelchair/on_spawn() + if(quirk_holder.buckled) // Handle late joins being buckled to arrival shuttle chairs. + quirk_holder.buckled.unbuckle_mob(quirk_holder) + + var/turf/T = get_turf(quirk_holder) + var/obj/structure/chair/spawn_chair = locate() in T + + var/obj/vehicle/ridden/wheelchair/wheels = new(T) + if(spawn_chair) // Makes spawning on the arrivals shuttle more consistent looking + wheels.setDir(spawn_chair.dir) + + wheels.buckle_mob(quirk_holder) diff --git a/GainStation13/code/mechanics/den abductors/console.dm b/GainStation13/code/mechanics/den abductors/console.dm index 4293c5e203..a0a967a3b6 100644 --- a/GainStation13/code/mechanics/den abductors/console.dm +++ b/GainStation13/code/mechanics/den abductors/console.dm @@ -26,7 +26,7 @@ var/credits = linked_scale?.credits dat += "Gear Credits: [credits]
" - dat += "Transfer credits in exchange for supplies:
" + dat += "Transfer credits in exchange for supplies:
" for(var/goodie in subtypesof(/datum/feeders_den_goodie)) var/datum/feeders_den_goodie/temp_goodie = new goodie() dat += "[temp_goodie.name] (Cost: [temp_goodie.credit_cost])
" @@ -64,7 +64,7 @@ say("Unable to purchase more!") return FALSE - if(!Dispense(item_path, price)) + if(!Dispense(item_path, price)) return FALSE if(buy_counts[goodie_datum.name] == null) @@ -146,7 +146,7 @@ return TRUE return ..() - + /obj/structure/scale/credits name = "tracking scale" desc = "A upgraded scale that tracks to weight of all of those that have stepped on it. Using this will add credits to the feeder console" @@ -155,7 +155,7 @@ /// How much credits do we currently have? var/credits = 0 /// How many credits are we going to reward per pound gained? - var/credits_per_fatness = 0.25 + var/credits_per_fatness = 0.25 /// A list containing all of the people we've scanned and their maximum weight. var/list/scanned_people = list() /// What is the current team number? @@ -201,7 +201,7 @@ var/credit_total = max((credits_to_add - credits_to_remove), 0) if(credit_total > 0) say("[credit_total] credits have been deposited into the console.") - + credits += credit_total scanned_people[fatty] += credit_total @@ -214,6 +214,7 @@ team_number = 27 vest_mode_action = null vest_disguise_action = null + check_if_abductor = FALSE /obj/machinery/computer/camera_advanced/abductor/feeder/IsScientist(mob/living/carbon/human/H) return TRUE @@ -245,4 +246,4 @@ prepare(target,user) return TRUE - + diff --git a/GainStation13/code/mechanics/fatrousal.dm b/GainStation13/code/mechanics/fatrousal.dm index c31b6054af..2a93a8cad0 100644 --- a/GainStation13/code/mechanics/fatrousal.dm +++ b/GainStation13/code/mechanics/fatrousal.dm @@ -16,14 +16,14 @@ var/mob/living/carbon/C = quirk_holder C.hider_remove(src) -/* + /datum/quirk/fatrousal/proc/fat_hide(var/mob/living/carbon/user) if(iscarbon(quirk_holder)) var/mob/living/carbon/C = quirk_holder - return C.getArousalLoss()*35 + return C.getArousal()*35 return FALSE -*/ + ///mob/living/adjust_arousal(amount, updating_arousal=1) // if(HAS_TRAIT(src, TRAIT_FATROUSAL)) diff --git a/GainStation13/code/mobs/emote.dm b/GainStation13/code/mobs/emote.dm index 647908b79e..2fa204ac0c 100644 --- a/GainStation13/code/mobs/emote.dm +++ b/GainStation13/code/mobs/emote.dm @@ -1,7 +1,3 @@ -/datum/emote/proc/get_sound(mob/living/user) - return sound //by default just return this var. - - /datum/emote/speen key = "speen" key_third_person = "speeeeens!" @@ -31,3 +27,19 @@ playsound(user, 'GainStation13/sound/voice/speen.ogg', 50, 1, -1) . = ..() + +/datum/emote/living/cackle + key = "cackle" + key_third_person = "cackles" + message = "cackles hysterically!" + emote_type = EMOTE_AUDIBLE + muzzle_ignore = FALSE + restraint_check = FALSE + +/datum/emote/living/cackle/run_emote(mob/living/user, params) + if(ishuman(user)) + if(user.nextsoundemote >= world.time) + return + user.nextsoundemote = world.time + 7 + playsound(user, 'GainStation13/sound/voice//cackle_yeen.ogg', 50, 1, -1) + . = ..() diff --git a/GainStation13/code/modules/arousal/arousal.dm b/GainStation13/code/modules/arousal/arousal.dm new file mode 100644 index 0000000000..11b2474e0d --- /dev/null +++ b/GainStation13/code/modules/arousal/arousal.dm @@ -0,0 +1,19 @@ +//GS13 Port +/mob/living/proc/mob_climax(forced_climax = FALSE, cause = "none")//This is just so I can test this shit without being forced to add actual content to get rid of arousal. Will be a very basic proc for a while. + set name = "Masturbate" + set category = "IC" + if(canbearoused && !restrained() && !stat) + if(mb_cd_timer <= world.time) + //start the cooldown even if it fails + mb_cd_timer = world.time + mb_cd_length + if(getArousal() >= ((max_arousal / 100) * 33))//33% arousal or greater required + src.visible_message("[src] starts masturbating!", \ + "You start masturbating.") + if(do_after(src, 30, target = src)) + src.visible_message("[src] relieves [p_them()]self!", \ + "You have relieved yourself.") + SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) + setArousal(min_arousal) + else + to_chat(src, "You aren't aroused enough for that.") + diff --git a/GainStation13/code/modules/mapping/ghost_roles.dm b/GainStation13/code/modules/mapping/ghost_roles.dm index 21d5f16cc5..f37da590dd 100644 --- a/GainStation13/code/modules/mapping/ghost_roles.dm +++ b/GainStation13/code/modules/mapping/ghost_roles.dm @@ -12,6 +12,7 @@ flavour_text = "After you've sold your soul to corporate overlords, your contract obliged you to enter cryostasis. \ Finally, after God knows how long, the cryopod system have awakened you with only a single sentence of information - welcome and lure in new guests into the freshly opened GATO restaurant!" assignedrole = "Restaurant worker" + mirrorcanloadappearance = TRUE /obj/effect/mob_spawn/human/fastfoodmanager name = "Corporate cryostasis pod" @@ -27,6 +28,7 @@ flavour_text = "After you've sold your soul to corporate overlords, your contract obliged you to enter cryostasis. \ Finally, after God knows how long, the cryopod system have awakened you with only a single sentence of information - make sure to keep the best care of GATO's restaurant, currently under your management! You have a higher say over your workers, but do not abuse this power." assignedrole = "Restaurant manager" + mirrorcanloadappearance = TRUE /obj/effect/mob_spawn/human/fastfood/Initialize(mapload) . = ..() @@ -108,6 +110,7 @@ death = FALSE roundstart = FALSE mob_species = /datum/species/human + mirrorcanloadappearance = TRUE /datum/outfit/feeders_den/fanatic name = "Feeder Fanatic" @@ -152,6 +155,7 @@ death = FALSE roundstart = FALSE mob_species = /datum/species/human + mirrorcanloadappearance = TRUE /datum/outfit/feeders_den/victim name = "Den Victim" diff --git a/GainStation13/code/modules/mob/living/belly.dm b/GainStation13/code/modules/mob/living/belly.dm index 796b0407d4..6ff2363f2b 100644 --- a/GainStation13/code/modules/mob/living/belly.dm +++ b/GainStation13/code/modules/mob/living/belly.dm @@ -45,6 +45,7 @@ else color = "#[D.features["belly_color"]]" size = D.features["belly_size"] + inflatable = D.features["inflatable_belly"] toggle_visibility(D.features["belly_visibility"], FALSE) diff --git a/GainStation13/sound/voice/cackle_yeen.ogg b/GainStation13/sound/voice/cackle_yeen.ogg new file mode 100644 index 0000000000..8d76cda277 Binary files /dev/null and b/GainStation13/sound/voice/cackle_yeen.ogg differ diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm index b3b5ece36d..de25ec52e9 100644 --- a/code/__DEFINES/citadel_defines.dm +++ b/code/__DEFINES/citadel_defines.dm @@ -67,9 +67,14 @@ #define BUTT_SIZE_DEF 1 #define BUTT_SIZE_MAX 10 //butt genitals are special in that they have caps. if there's the event there's even bigger butt sprites, raise this number. -#define BELLY_SIZE_DEF 0 +#define BELLY_SIZE_DEF 1 #define BELLY_SIZE_MAX 10 +//GS13 Port - Add back Arousal +#define AROUSAL_MINIMUM_DEFAULT 0 +#define AROUSAL_MAXIMUM_DEFAULT 100 +#define AROUSAL_START_VALUE 1 + //visibility toggles defines to avoid errors typos code errors. #define GEN_VISIBLE_ALWAYS "Always visible" #define GEN_VISIBLE_NO_CLOTHES "Hidden by clothes" diff --git a/code/__DEFINES/hud.dm b/code/__DEFINES/hud.dm index 14a3b7dc49..4842a38716 100644 --- a/code/__DEFINES/hud.dm +++ b/code/__DEFINES/hud.dm @@ -98,6 +98,7 @@ #define ui_health "EAST-1:28,CENTER-1:15" #define ui_internal "EAST-1:28,CENTER+1:19"//CIT CHANGE - moves internal icon up a little bit to accommodate for the stamina meter #define ui_mood "EAST-1:28,CENTER-3:10" +#define ui_arousal "EAST-1:28,CENTER-4:8" // #define ui_spacesuit "EAST-1:28,CENTER-4:10" //Pop-up inventory diff --git a/code/__DEFINES/research/stock_parts.dm b/code/__DEFINES/research/stock_parts.dm index 457e3b632e..e493df242e 100644 --- a/code/__DEFINES/research/stock_parts.dm +++ b/code/__DEFINES/research/stock_parts.dm @@ -2,4 +2,4 @@ /// Efficiency scaling for stock part level to material usage. All code concerning lathing and production from raw material sheet should be using this. #define STANDARD_PART_LEVEL_LATHE_COEFFICIENT(level) clamp(1 - (level * 0.1), 0, 1) /// Efficiency scaling for stock part level to ore factor. All code concerning lathing and production from raw ores to raw material sheets should be using this. -#define STANDARD_PART_LEVEL_ORE_COEFFICIENT(level) clamp(1 + (level * 0.125), 1, 10) +#define STANDARD_PART_LEVEL_ORE_COEFFICIENT(level) clamp(1 + (level * 0.25), 1, 10) //GS13 EDIT, original level mult 0.125 diff --git a/code/__HELPERS/_cit_helpers.dm b/code/__HELPERS/_cit_helpers.dm index de006de90e..c885a5b996 100644 --- a/code/__HELPERS/_cit_helpers.dm +++ b/code/__HELPERS/_cit_helpers.dm @@ -144,6 +144,17 @@ GLOBAL_VAR_INIT(miscreants_allowed, FALSE) if(I.body_parts_covered & GROIN) return FALSE return TRUE +//GS13 Port - Arousal +/mob/living/carbon/proc/is_butt_exposed(var/list/L) + if(!L) + L = get_equipped_items() + for(var/obj/item/I in L) + if(I.body_parts_covered & GROIN) + if(!I.do_not_cover_butt) + return FALSE + else + return TRUE + return TRUE /mob/living/carbon/proc/is_chest_exposed(list/L) if(!L) diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index e2f76e1952..27a028d40f 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -215,6 +215,7 @@ "butt_color" = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F"), // GS13 EDIT START - BELLY "has_belly" = FALSE, + "belly_size" = BELLY_SIZE_DEF, "hide_belly" = FALSE, "inflatable_belly" = FALSE, "belly_color" = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F"), @@ -225,6 +226,7 @@ "cock_visibility" = GEN_VISIBLE_NO_UNDIES, "vag_visibility" = GEN_VISIBLE_NO_UNDIES, "butt_visibility" = GEN_VISIBLE_NO_UNDIES, + "belly_visibility" = GEN_VISIBLE_NO_UNDIES, "ipc_screen" = snowflake_ipc_antenna_list ? pick(snowflake_ipc_antenna_list) : "None", "ipc_antenna" = "None", "flavor_text" = "", diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm index 53d69fe01e..61d99e29f3 100644 --- a/code/_onclick/hud/hud.dm +++ b/code/_onclick/hud/hud.dm @@ -88,6 +88,9 @@ GLOBAL_LIST_INIT(available_ui_styles, list( var/atom/movable/screen/healthdoll var/atom/movable/screen/internals + //GS13 Port - Add back Arousal + var/atom/movable/screen/arousal + var/atom/movable/screen/wanted/wanted_lvl // subtypes can override this to force a specific UI style var/ui_style @@ -144,6 +147,7 @@ GLOBAL_LIST_INIT(available_ui_styles, list( healthdoll = null wanted_lvl = null internals = null + arousal = null lingchemdisplay = null devilsouldisplay = null lingstingdisplay = null diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm index 27989f3bb1..bea9e564f2 100644 --- a/code/_onclick/hud/human.dm +++ b/code/_onclick/hud/human.dm @@ -430,6 +430,12 @@ infodisplay += staminabuffer //END OF CIT CHANGES + //GS13 Port - adds arousal and stamina to hud + arousal = new /atom/movable/screen/arousal() + arousal.icon_state = (owner.canbearoused == 1 ? "arousal0" : "") + arousal.hud = src + infodisplay += arousal + healthdoll = new /atom/movable/screen/healthdoll() healthdoll.hud = src infodisplay += healthdoll diff --git a/code/datums/mind.dm b/code/datums/mind.dm index c05d04ede8..5c810bed2a 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -169,6 +169,8 @@ var/mob/living/L = new_character if(L.client?.prefs && L.client.prefs.auto_ooc && L.client.prefs.chat_toggles & CHAT_OOC) L.client.prefs.chat_toggles &= ~(CHAT_OOC) + L.canbearoused = L.client?.prefs?.arousable //Technically this should make taking over a character mean the body gain the new minds setting... + L.update_arousal_hud() //Removes the old icon hide_ckey = current.client?.prefs?.hide_ckey diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 0eaba60ba8..ae025b355a 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -94,6 +94,7 @@ var/datum/wires/wires = null var/icon/blood_splatter_icon + var/icon/cum_splatter_icon var/list/fingerprints var/list/fingerprintshidden var/list/blood_DNA diff --git a/code/game/machinery/computer/camera_advanced.dm b/code/game/machinery/computer/camera_advanced.dm index 5395dd6fee..fc4823cbc8 100644 --- a/code/game/machinery/computer/camera_advanced.dm +++ b/code/game/machinery/computer/camera_advanced.dm @@ -102,7 +102,7 @@ return TRUE /obj/machinery/computer/camera_advanced/abductor/can_use(mob/user) - if(!isabductor(user)) + if(check_if_abductor && !isabductor(user)) return FALSE return ..() diff --git a/code/game/machinery/quantum_pad.dm b/code/game/machinery/quantum_pad.dm index 1ae2692da9..1eeec0fd74 100644 --- a/code/game/machinery/quantum_pad.dm +++ b/code/game/machinery/quantum_pad.dm @@ -139,7 +139,7 @@ to_chat(user, "[src] is unpowered!") teleporting = FALSE return - if(!target_pad || QDELETED(target_pad) || (needs_power && (target_pad.machine_stat & NOPOWER))) // GS13 EDIT + if(!target_pad || QDELETED(target_pad) || (target_pad.needs_power && (target_pad.machine_stat & NOPOWER))) // GS13 EDIT to_chat(user, "Linked pad is not responding to ping. Teleport aborted.") teleporting = FALSE return diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index e437ac5c8b..9db3090d66 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -181,6 +181,9 @@ GLOBAL_VAR_INIT(embedpocalypse, FALSE) // if true, all items will be able to emb /// Used if we want to have a custom verb text for throwing. "John Spaceman flicks the ciggerate" for example. var/throw_verb + //GS13 Port - Hyper, for clothes that reveal your behind! butt stuff, you know how it is. + var/do_not_cover_butt = FALSE + /obj/item/Initialize(mapload) if(attack_verb) diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm index ffb48ce633..a88d250eb7 100644 --- a/code/game/objects/structures/mirror.dm +++ b/code/game/objects/structures/mirror.dm @@ -21,6 +21,7 @@ if(ishuman(user)) var/mob/living/carbon/human/H = user + H.checkloadappearance() // GS13 EDIT //see code/modules/mob/dead/new_player/preferences.dm at approx line 545 for comments! //this is largely copypasted from there. diff --git a/code/modules/antagonists/abductor/machinery/camera.dm b/code/modules/antagonists/abductor/machinery/camera.dm index 4fb6bf5645..9069130a7d 100644 --- a/code/modules/antagonists/abductor/machinery/camera.dm +++ b/code/modules/antagonists/abductor/machinery/camera.dm @@ -11,6 +11,8 @@ var/obj/machinery/abductor/console/console lock_override = TRUE + var/check_if_abductor = TRUE //GS13 EDIT + icon = 'icons/obj/abductor.dmi' icon_state = "camera" icon_keyboard = null @@ -24,7 +26,7 @@ /obj/machinery/computer/camera_advanced/abductor/Initialize(mapload) . = ..() - + if(tele_in_action) actions += new tele_in_action(src) if(tele_out_action) diff --git a/code/modules/antagonists/nukeop/nukeop.dm b/code/modules/antagonists/nukeop/nukeop.dm index 9c0abf70b5..1313d21312 100644 --- a/code/modules/antagonists/nukeop/nukeop.dm +++ b/code/modules/antagonists/nukeop/nukeop.dm @@ -56,6 +56,12 @@ if(send_to_spawnpoint) move_to_spawnpoint() + //GS13 EDIT START + var/mob/living/carbon/human/H = owner.current + H.checkloadappearance() + //GS13 EDIT END + + /datum/antagonist/nukeop/get_team() return nuke_team diff --git a/code/modules/antagonists/wizard/wizard.dm b/code/modules/antagonists/wizard/wizard.dm index 5747e5190d..65988577b7 100644 --- a/code/modules/antagonists/wizard/wizard.dm +++ b/code/modules/antagonists/wizard/wizard.dm @@ -30,6 +30,11 @@ create_objectives() if(move_to_lair) send_to_lair() + //GS13 EDIT START + var/mob/living/carbon/human/H = owner.current + H.mirrorcanloadappearance = TRUE + H.checkloadappearance() + //GS13 EDIT END . = ..() if(allow_rename) rename_wizard() diff --git a/code/modules/arousal/arousal.dm b/code/modules/arousal/arousal.dm index 4e0f37d529..d918d0cb19 100644 --- a/code/modules/arousal/arousal.dm +++ b/code/modules/arousal/arousal.dm @@ -1,15 +1,36 @@ +//GS13 Port - Oh boy this has changed /mob/living + var/arousal = 0 //How aroused the mob is. + var/min_arousal = AROUSAL_MINIMUM_DEFAULT //The lowest this mobs arousal will get. default = 0 + var/max_arousal = AROUSAL_MAXIMUM_DEFAULT //The highest this mobs arousal will get. default = 100 + var/arousal_rate = AROUSAL_START_VALUE //The base rate that arousal will increase in this mob. + var/arousal_loss_rate = AROUSAL_START_VALUE //How easily arousal can be relieved for this mob. + var/canbearoused = FALSE //Mob-level disabler for arousal. Starts off and can be enabled as features are added for different mob types. var/mb_cd_length = 5 SECONDS //5 second cooldown for masturbating because fuck spam. var/mb_cd_timer = 0 //The timer itself /mob/living/carbon/human + canbearoused = TRUE + var/saved_underwear = ""//saves their underwear so it can be toggled later var/saved_undershirt = "" var/saved_socks = "" var/hidden_underwear = FALSE var/hidden_undershirt = FALSE var/hidden_socks = FALSE - var/arousal_rate = 1 + +/mob/living/carbon/human/New() + ..() + saved_underwear = underwear + saved_undershirt = undershirt + +//Species vars +/datum/species + var/arousal_gain_rate = AROUSAL_START_VALUE //Rate at which this species becomes aroused + var/arousal_lose_rate = AROUSAL_START_VALUE //Multiplier for how easily arousal can be relieved + var/list/cum_fluids = list(/datum/reagent/consumable/semen) + var/list/milk_fluids = list(/datum/reagent/consumable/milk) + var/list/femcum_fluids = list(/datum/reagent/consumable/semen/femcum) //Mob procs /mob/living/carbon/human/verb/underwear_toggle() @@ -40,6 +61,162 @@ update_body(TRUE) +/mob/living/proc/handle_arousal() + + +/mob/living/carbon/handle_arousal() + if(canbearoused && dna) + var/datum/species/S + S = dna.species + if(S) + if(!(SSmobs.times_fired % 36)) + if(getArousal() < max_arousal) + //if(S && !(SSmobs.times_fired % 36) && getArousal() < max_arousal)//Totally stolen from breathing code. Do this every 36 ticks. + adjustArousal(arousal_rate * S.arousal_gain_rate) + if(dna.features["exhibitionist"] && client) + var/amt_nude = 0 + if(is_chest_exposed() && (getorganslot("breasts"))) + amt_nude++ + if(is_groin_exposed()) + if(getorganslot("penis")) + amt_nude++ + if(getorganslot("vagina")) + amt_nude++ + if(is_butt_exposed()) + if(getorganslot("anus")) + amt_nude++ + if(amt_nude) + var/watchers = 0 + for(var/mob/_M in view(world.view, src)) + var/mob/living/M = _M + if(!istype(M)) + continue + if(M.client && !M.stat && !M.eye_blind && (locate(src) in viewers(world.view,M))) + watchers++ + if(watchers) + adjustArousal((amt_nude * watchers) + S.arousal_gain_rate) + +/mob/living/proc/getArousal() + return arousal + +/mob/living/proc/adjustArousal(amount, updating_arousal=1) + if(status_flags & GODMODE || !canbearoused) + return FALSE + arousal = clamp(arousal + amount, min_arousal, max_arousal) + if(updating_arousal) + updatearousal() + +/mob/living/proc/setArousal(amount, updating_arousal=1) + if(status_flags & GODMODE || !canbearoused) + return FALSE + arousal = clamp(amount, min_arousal, max_arousal) + if(updating_arousal) + updatearousal() + +/mob/living/proc/getPercentAroused() + var/percentage = ((100 / max_arousal) * arousal) + return percentage + +/mob/living/proc/isPercentAroused(percentage)//returns true if the mob's arousal (measured in a percent of 100) is greater than the arg percentage. + if(!isnum(percentage) || percentage > 100 || percentage < 0) + CRASH("Provided percentage is invalid") + if(getPercentAroused() >= percentage) + return TRUE + return FALSE + +//H U D// +/mob/living/proc/updatearousal() + update_arousal_hud() + +/mob/living/carbon/updatearousal() + . = ..() + + for(var/obj/item/organ/genital/G in internal_organs) + if(istype(G)) + var/datum/sprite_accessory/S + switch(G.type) + if(/obj/item/organ/genital/penis) + S = GLOB.cock_shapes_list[G.shape] + if(/obj/item/organ/genital/testicles) + S = GLOB.balls_shapes_list[G.shape] + if(/obj/item/organ/genital/vagina) + S = GLOB.vagina_shapes_list[G.shape] + if(/obj/item/organ/genital/breasts) + S = GLOB.breasts_shapes_list[G.shape] + if(S?.alt_aroused) + G.aroused_state = isPercentAroused(G.aroused_amount) + if(getArousal() >= ((max_arousal / 100) * 33)) + G.aroused_state = TRUE + else + G.aroused_state = FALSE + G.update_appearance() +/mob/living/proc/update_arousal_hud() + return FALSE + +/datum/species/proc/update_arousal_hud(mob/living/carbon/human/H) + return FALSE + +/mob/living/carbon/human/update_arousal_hud() + if(!client || !hud_used) + return FALSE + if(dna.species.update_arousal_hud()) + return FALSE + if(!canbearoused) + hud_used.arousal.icon_state = "" + return FALSE + else + if(hud_used.arousal) + if(stat == DEAD) + hud_used.arousal.icon_state = "arousal0" + return TRUE + if(getArousal() == max_arousal) + hud_used.arousal.icon_state = "arousal100" + return TRUE + if(getArousal() >= (max_arousal / 100) * 90)//M O D U L A R , W O W + hud_used.arousal.icon_state = "arousal90" + return TRUE + if(getArousal() >= (max_arousal / 100) * 80)//M O D U L A R , W O W + hud_used.arousal.icon_state = "arousal80" + return TRUE + if(getArousal() >= (max_arousal / 100) * 70)//M O D U L A R , W O W + hud_used.arousal.icon_state = "arousal70" + return TRUE + if(getArousal() >= (max_arousal / 100) * 60)//M O D U L A R , W O W + hud_used.arousal.icon_state = "arousal60" + return TRUE + if(getArousal() >= (max_arousal / 100) * 50)//M O D U L A R , W O W + hud_used.arousal.icon_state = "arousal50" + return TRUE + if(getArousal() >= (max_arousal / 100) * 40)//M O D U L A R , W O W + hud_used.arousal.icon_state = "arousal40" + return TRUE + if(getArousal() >= (max_arousal / 100) * 30)//M O D U L A R , W O W + hud_used.arousal.icon_state = "arousal30" + return TRUE + if(getArousal() >= (max_arousal / 100) * 20)//M O D U L A R , W O W + hud_used.arousal.icon_state = "arousal10" + return TRUE + if(getArousal() >= (max_arousal / 100) * 10)//M O D U L A R , W O W + hud_used.arousal.icon_state = "arousal10" + return TRUE + else + hud_used.arousal.icon_state = "arousal0" + +//GS13 Port - Arousal menu +/atom/movable/screen/arousal + name = "arousal" + icon_state = "arousal0" + icon = 'icons/obj/genitals/hud.dmi' + screen_loc = ui_arousal + +/atom/movable/screen/arousal/Click() + if(!isliving(usr)) + return FALSE + if(isobserver(usr)) + return + var/mob/living/M = usr + if(M.canbearoused) + ui_interact(usr) /mob/living/carbon/human/proc/adjust_arousal(strength, cause = "manual toggle", aphro = FALSE,maso = FALSE) // returns all genitals that were adjust var/list/obj/item/organ/genital/genit_list = list() @@ -63,207 +240,543 @@ if(!. && !silent) to_chat(H, "Your [name] is unable to produce it's own fluids, it's missing the organs for it.") -/mob/living/carbon/human/proc/do_climax(datum/reagents/R, atom/target, obj/item/organ/genital/G, spill = TRUE) - if(!G) - return - if(!target || !R) - return - var/turfing = isturf(target) - G.generate_fluid(R) - log_message("Climaxed using [G] with [target]", LOG_EMOTE) - if(spill && R.total_volume >= 5) - R.reaction(turfing ? target : target.loc, TOUCH, 1, 0) - if(!turfing) - R.trans_to(target, R.total_volume * (spill ? G.fluid_transfer_factor : 1), log = TRUE) - G.last_orgasmed = world.time - R.clear_reagents() +//These are various procs that we'll use later, split up for readability instead of having one, huge proc. +//For all of these, we assume the arguments given are proper and have been checked beforehand. +/mob/living/carbon/human/proc/mob_masturbate(obj/item/organ/genital/G, mb_time = 30) //Masturbation, keep it gender-neutral + var/total_fluids = 0 + var/datum/reagents/fluid_source = null -/mob/living/carbon/human/proc/mob_climax_outside(obj/item/organ/genital/G, mb_time = 30) //This is used for forced orgasms and other hands-free climaxes - var/datum/reagents/fluid_source = G.climaxable(src, TRUE) - if(!fluid_source) - to_chat(src,"Your [G.name] cannot cum.") - return - if(mb_time) //as long as it's not instant, give a warning - to_chat(src,"You feel yourself about to orgasm.") - if(!do_after(src, mb_time, target = src) || !G.climaxable(src, TRUE)) + if(G.producing) //Can it produce its own fluids, such as breasts? + fluid_source = G.reagents + else + if(!G.linked_organ) + to_chat(src, "Your [G.name] is unable to produce it's own fluids, it's missing the organs for it.") return - to_chat(src,"You climax[isturf(loc) ? " onto [loc]" : ""] with your [G.name].") - do_climax(fluid_source, loc, G) + fluid_source = G.linked_organ.reagents + total_fluids = fluid_source.total_volume + if(mb_time) + src.visible_message("[src] starts to [G.masturbation_verb] [p_their()] [G.name].", \ + "You start to [G.masturbation_verb] your [G.name].", \ + "You start to [G.masturbation_verb] your [G.name].") -/mob/living/carbon/human/proc/mob_climax_partner(obj/item/organ/genital/G, mob/living/L, spillage = TRUE, mb_time = 30) //Used for climaxing with any living thing - var/datum/reagents/fluid_source = G.climaxable(src) - if(!fluid_source) - return - if(mb_time) //Skip warning if this is an instant climax. - to_chat(src,"You're about to climax with [L]!") - to_chat(L,"[src] is about to climax with you!") - if(!do_after(src, mb_time, target = src) || !in_range(src, L) || !G.climaxable(src, TRUE)) + if(do_after(src, mb_time, target = src)) + if(total_fluids > 5) + fluid_source.reaction(src.loc, TOUCH, 1, 0) + fluid_source.clear_reagents() + + src.visible_message("[src] orgasms, cumming[istype(src.loc, /turf/open/floor) ? " onto [src.loc]" : ""]!", \ + "You cum[istype(src.loc, /turf/open/floor) ? " onto [src.loc]" : ""].", \ + "You have relieved yourself.") + + + SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) + if(G.can_climax) + setArousal(min_arousal) + + +/mob/living/carbon/human/proc/mob_climax_outside(obj/item/organ/genital/G, mb_time = 30, spillage = TRUE) //This is used for forced orgasms and other hands-free climaxes + var/total_fluids = 0 + var/datum/reagents/fluid_source = null + var/unable_to_come = FALSE + + if(G.producing) //Can it produce its own fluids, such as breasts? + fluid_source = G.reagents + total_fluids = fluid_source.total_volume + else + if(!G.linked_organ) + unable_to_come = TRUE + else + fluid_source = G.linked_organ.reagents + total_fluids = fluid_source.total_volume + + if(unable_to_come) + src.visible_message("[src] shudders, their [G.name] unable to cum.", \ + "Your [G.name] cannot cum, giving no relief.", \ + "Your [G.name] cannot cum, giving no relief.") + else + total_fluids = fluid_source.total_volume + if(mb_time) //as long as it's not instant, give a warning + src.visible_message("[src] looks like they're about to cum.", \ + "You feel yourself about to orgasm.", \ + "You feel yourself about to orgasm.") + if(do_after(src, mb_time, target = src)) + if(spillage) + if(total_fluids > 5) + fluid_source.reaction(src.loc, TOUCH, 1, 0) + + fluid_source.clear_reagents() + src.visible_message("[src] orgasms[istype(src.loc, /turf/open/floor) ? ", spilling onto [src.loc]" : ""], with [p_their()] [G.name]!", \ + "You climax[istype(src.loc, /turf/open/floor) ? ", spilling onto [src.loc]" : ""] with your [G.name].", \ + "You climax using your [G.name].") + else //Else from spillage check, also note subtle text change + src.visible_message("[src] orgasms with [p_their()] [G.name]!", \ + "You climax with your [G.name].", \ + "You climax using your [G.name].") + + SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) + if(G.can_climax) + setArousal(min_arousal) + + +/mob/living/carbon/human/proc/mob_climax_partner(obj/item/organ/genital/G, mob/living/L, spillage = TRUE, impreg = FALSE,cover = FALSE,remote = FALSE, mb_time = 30) //Used for climaxing with any living thing + var/total_fluids = 0 + var/datum/reagents/fluid_source = null + + if(G.producing) //Can it produce its own fluids, such as breasts? + fluid_source = G.reagents + else + if(!G.linked_organ) + to_chat(src, "Your [G.name] is unable to produce it's own fluids, it's missing the organs for it.") return - if(spillage) - to_chat(src,"You orgasm with [L], spilling out of them, using your [G.name].") - to_chat(L,"[src] climaxes with you, overflowing and spilling, using [p_their()] [G.name]!") - else //knots and other non-spilling orgasms - to_chat(src,"You climax with [L], your [G.name] spilling nothing.") - to_chat(L,"[src] climaxes with you, [p_their()] [G.name] spilling nothing!") - SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) - do_climax(fluid_source, spillage ? loc : L, G, spillage) + fluid_source = G.linked_organ.reagents + total_fluids = fluid_source.total_volume + + if(mb_time && !remote) //Skip warning if this is an instant climax. + src.visible_message("[src] is about to climax with [L]!", \ + "You're about to climax with [L]!", \ + "You're preparing to climax with something!") + if(remote) + src.visible_message("[src] is about to climax with someone!", \ + "You're about to climax with someone!", \ + "You're preparing to climax with something!") + + if(cover)//covering the partner in cum, this overrides other options. + if(do_after(src, mb_time, target = src) && in_range(src, L)) + fluid_source.trans_to(L, total_fluids*G.fluid_transfer_factor) + total_fluids -= total_fluids*G.fluid_transfer_factor + if(total_fluids > 80) // now thats a big cum! + if(isliving(L)) + var/mutable_appearance/cumoverlaylarge = mutable_appearance('hyperstation/icons/effects/cumoverlay.dmi') + cumoverlaylarge.icon_state = "cum_large" + L.add_overlay(cumoverlaylarge) + + if(total_fluids > 5) + fluid_source.reaction(L.loc, TOUCH, 1, 0) + var/mob/living/carbon/human/H = L + if(H) + H.cumdrip_rate += rand(5,10) + fluid_source.clear_reagents() + src.visible_message("[src] climaxes over [L], using [p_their()] [G.name]!", \ + "You orgasm over [L], using your [G.name].", \ + "You have climaxed over something, using your [G.name].") + SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) + + if(isliving(L)) + var/mutable_appearance/cumoverlay = mutable_appearance('hyperstation/icons/effects/cumoverlay.dmi') + cumoverlay.icon_state = "cum_normal" + L.add_overlay(cumoverlay) + else + L.add_cum_overlay() + + setArousal(min_arousal) + if(G.can_climax) + setArousal(min_arousal) + + if(spillage && !cover) + if(do_after(src, mb_time, target = src)) + if(!in_range(src, L) && !remote) + return + fluid_source.trans_to(L, total_fluids*G.fluid_transfer_factor) + total_fluids -= total_fluids*G.fluid_transfer_factor + if(total_fluids > 5) + fluid_source.reaction(L.loc, TOUCH, 1, 0) + var/mob/living/carbon/human/H = L + if(H) + H.cumdrip_rate += rand(5,10) + fluid_source.clear_reagents() + src.visible_message("[src] climaxes with [L][spillage ? ", overflowing and spilling":""], using [p_their()] [G.name]!", \ + "You orgasm with [L][spillage ? ", spilling out of them":""], using your [G.name].", \ + "You have climaxed with someone[spillage ? ", spilling out of them":""], using your [G.name].") + SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) + SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) + + if(G.can_climax) + setArousal(min_arousal) + + else //knots, portal fleshlights, and other non-spilling orgasms + if(!cover) + if(!remote && !in_range(src, L)) + return + if(do_after(src, mb_time, target = src)) + + if(!spillage) //hyper inflation + var/obj/item/organ/genital/belly/B = L.getorganslot("belly") + if(B) + if(B.inflatable && total_fluids > 80) //requires a big cumshot to expand. + if(B.size < 3) + B.size += 1 + to_chat(L, "You feel your belly expand.") + else + to_chat(L, "You feel your belly strain.") + + fluid_source.trans_to(L, total_fluids) + total_fluids = 0 + if(!remote) + src.visible_message("[src] climaxes with [L], [p_their()] [G.name] spilling nothing!", \ + "You ejaculate with [L], your [G.name] spilling nothing.", \ + "You have climaxed inside someone, your [G.name] spilling nothing.") + else + src.visible_message("[src] climaxes with someone, using [p_their()] [G.name]!", \ + "You ejaculate with someone, using your [G.name].", \ + "You have climaxed inside someone, using your [G.name].") + to_chat(L, "You feel someone ejaculate inside you.") + + SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) + SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) + + if(G.can_climax) + setArousal(min_arousal) + + //Hyper - antag code + /*if(src.mind.special_role == ROLE_LEWD_TRAITOR) + for(var/datum/objective/obj in src.mind.objectives) + if (L.mind == obj.target) + L.mind.sexed = TRUE //sexed + to_chat(src, "You feel deep satisfaction with yourself.") + */ + //Hyper - impreg + // if(impreg) + // //Role them odds, only people with the dicks can send the chance to the person with the settings enabled at the momment. + // if(prob(L.impregchance)) + // var/obj/item/organ/genital/womb/W = L.getorganslot("womb") + // if(W) //check if they have a womb. + // if (L.breedable == 1 && W.pregnant == 0) //Dont get pregnant again, if you are pregnant. + // log_game("Debug: [L] has been impregnated by [src]") + // to_chat(L, "You feel your hormones change, and a motherly instinct take over.") //leting them know magic has happened. + // W.pregnant = 1 + // if (HAS_TRAIT(L, TRAIT_HEAT)) + // SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "heat", /datum/mood_event/heat) //well done you perv. + // REMOVE_TRAIT(L, TRAIT_HEAT, ROUNDSTART_TRAIT) //take the heat away, you satisfied it! + + // //Make breasts produce quicker. + // var/obj/item/organ/genital/breasts/B = L.getorganslot("breasts") + // if (B.fluid_mult < 0.5 && B) + // B.fluid_mult = 0.5 + /mob/living/carbon/human/proc/mob_fill_container(obj/item/organ/genital/G, obj/item/reagent_containers/container, mb_time = 30) //For beaker-filling, beware the bartender - var/datum/reagents/fluid_source = G.climaxable(src) - if(!fluid_source) - return - if(mb_time) - to_chat(src,"You start to [G.masturbation_verb] your [G.name] over [container].") - if(!do_after(src, mb_time, target = src) || !in_range(src, container) || !G.climaxable(src, TRUE)) - return - to_chat(src,"You used your [G.name] to fill [container].") - message_admins("[ADMIN_LOOKUPFLW(src)] used their [G.name] to fill [container].") - log_consent("[key_name(src)] used their [G.name] to fill [container].") - do_climax(fluid_source, container, G, FALSE) + var/total_fluids = 0 + var/datum/reagents/fluid_source = null -/mob/living/carbon/human/proc/pick_climax_genitals(silent = FALSE) - var/list/genitals_list + if(G.producing) //Can it produce its own fluids, such as breasts? + fluid_source = G.reagents + else + if(!G.linked_organ) + to_chat(src, "Your [G.name] is unable to produce it's own fluids, it's missing the organs for it.") + return + fluid_source = G.linked_organ.reagents + total_fluids = fluid_source.total_volume + + if(!container) //Something weird happened + to_chat(src, "You need a container to do this!") + return + + src.visible_message("[src] starts to [G.masturbation_verb] their [G.name] over [container].", \ + "You start to [G.masturbation_verb] your [G.name] over [container].", \ + "You start to [G.masturbation_verb] your [G.name] over something.") + if(do_after(src, mb_time, target = src) && in_range(src, container)) + fluid_source.trans_to(container, total_fluids) + src.visible_message("[src] uses [p_their()] [G.name] to fill [container]!", \ + "You used your [G.name] and fill [container] with a total of [total_fluids]u's.", \ + "You have relieved some pressure.") + SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) + container.add_cum_overlay() //your aim is bad... + if(G.can_climax) + setArousal(min_arousal) + + +/mob/living/carbon/human/proc/pick_masturbate_genitals() + var/obj/item/organ/genital/ret_organ + var/list/genitals_list = list() var/list/worn_stuff = get_equipped_items() for(var/obj/item/organ/genital/G in internal_organs) - if((G.genital_flags & CAN_CLIMAX_WITH) && G.is_exposed(worn_stuff)) //filter out what you can't masturbate with - LAZYADD(genitals_list, G) - if(LAZYLEN(genitals_list)) - var/obj/item/organ/genital/ret_organ = input(src, "with what?", "Climax", null) as null|obj in genitals_list + if(G.genital_flags & CAN_MASTURBATE_WITH) //filter out what you can't masturbate with + if(G.is_exposed(worn_stuff)) //Nude or through_clothing + if(!G.dontlist) + genitals_list += G + if(genitals_list.len) + ret_organ = input(src, "with what?", "Masturbate", null) as null|obj in genitals_list return ret_organ - else if(!silent) - to_chat(src, "You cannot climax without available genitals.") + return null //error stuff -/mob/living/carbon/human/proc/pick_partner(silent = FALSE) +/mob/living/carbon/human/proc/target_genitals(mob/living/carbon/human/T) //used for targeting others + var/obj/item/organ/genital/ret_organ + var/list/genitals_list = list() + var/list/worn_stuff = get_equipped_items() + + for(var/obj/item/organ/genital/G in T.internal_organs) + if(G.is_exposed(worn_stuff)) //Nude or through_clothing + if(!G.dontlist) + genitals_list += G + if(genitals_list.len) + ret_organ = input(src, "", "Genitals", null) as null|obj in genitals_list + return ret_organ + return null //error stuff + +/mob/living/carbon/human/proc/pick_climax_genitals() + var/obj/item/organ/genital/ret_organ + var/list/genitals_list = list() + var/list/worn_stuff = get_equipped_items() + + for(var/obj/item/organ/genital/G in internal_organs) + if(G.can_climax) //filter out what you can't masturbate with + if(G.is_exposed(worn_stuff)) //Nude or through_clothing + if(!G.dontlist) + genitals_list += G + if(genitals_list.len) + ret_organ = input(src, "with what?", "Climax", null) as null|obj in genitals_list + return ret_organ + return null //error stuff + +/mob/living/carbon/human/proc/pick_partner_overide() //used for cumming on people without genitals exposed var/list/partners = list() - if(pulling) - partners += pulling - if(pulledby) - partners += pulledby + if(src.pulling) + partners += src.pulling //Yes, even objects for now + if(src.pulledby) + partners += src.pulledby //Now we got both of them, let's check if they're proper - for(var/mob/living/L in partners) - if(!L.client || !L.mind) // can't consent, not a partner - partners -= L - if(iscarbon(L)) - var/mob/living/carbon/C = L - if(!C.exposed_genitals.len && !C.is_groin_exposed() && !C.is_chest_exposed() && C.is_mouth_covered()) //Nothing through_clothing, no proper partner. - partners -= C + for(var/I in partners) + if(isliving(I)) + else + partners -= I //No fucking objects //NOW the list should only contain correct partners if(!partners.len) - if(!silent) - to_chat(src, "You cannot do this alone.") - return //No one left. - var/mob/living/target = input(src, "With whom?", "Sexual partner", null) as null|anything in partners //pick one, default to null - if(target && in_range(src, target)) - to_chat(src,"Waiting for consent...") - var/consenting = input(target, "Do you want [src] to climax with you?","Climax mechanics","No") in list("Yes","No") - if(consenting == "Yes") - return target - else - message_admins("[ADMIN_LOOKUPFLW(src)] tried to climax with [target], but [target] did not consent.") - log_consent("[key_name(src)] tried to climax with [target], but [target] did not consent.") + return null //No one left. + return input(src, "With whom?", "Sexual partner", null) in partners //pick one, default to null -/mob/living/carbon/human/proc/pick_climax_container(silent = FALSE) +/mob/living/carbon/human/proc/pick_partner() + var/list/partners = list() + if(src.pulling) + partners += src.pulling //Yes, even objects for now + if(src.pulledby) + partners += src.pulledby + //Now we got both of them, let's check if they're proper + for(var/I in partners) + if(isliving(I)) + if(iscarbon(I)) + var/mob/living/carbon/C = I + if(!C.exposed_genitals.len) //Nothing through_clothing + if(!C.is_groin_exposed()) //No pants undone + if(!C.is_chest_exposed()) //No chest exposed + partners -= I //Then not proper, remove them + else + partners -= I //No fucking objects + //NOW the list should only contain correct partners + if(!partners.len) + return null //No one left. + return input(src, "With whom?", "Sexual partner", null) in partners //pick one, default to null + +/mob/living/carbon/human/proc/pick_climax_container() + var/obj/item/reagent_containers/SC = null var/list/containers_list = list() - for(var/obj/item/reagent_containers/C in held_items) - if(C.is_open_container() || istype(C, /obj/item/reagent_containers/food/snacks)) - containers_list += C - for(var/obj/item/reagent_containers/C in range(1, src)) - if((C.is_open_container() || istype(C, /obj/item/reagent_containers/food/snacks)) && CanReach(C)) - containers_list += C + for(var/obj/item/reagent_containers/container in held_items) + if(container.is_open_container() || istype(container, /obj/item/reagent_containers/food/snacks)) + containers_list += container if(containers_list.len) - var/obj/item/reagent_containers/SC = input(src, "Into or onto what?(Cancel for nowhere)", null) as null|obj in containers_list - if(SC && CanReach(SC)) - return SC - else if(!silent) - to_chat(src, "You cannot do this without an appropriate container.") + SC = input(src, "Into or onto what?(Cancel for nowhere)", null) as null|obj in containers_list + if(SC) + if(in_range(src, SC)) + return SC + return null //If nothing correct, give null. -/mob/living/carbon/human/proc/available_rosie_palms(silent = FALSE, list/whitelist_typepaths = list(/obj/item/dildo)) - if(restrained(TRUE)) //TRUE ignores grabs - if(!silent) - to_chat(src, "You can't do that while restrained!") - return FALSE - if(!get_num_arms() || !get_empty_held_indexes()) - if(whitelist_typepaths) - if(!islist(whitelist_typepaths)) - whitelist_typepaths = list(whitelist_typepaths) - for(var/path in whitelist_typepaths) - if(is_holding_item_of_type(path)) - return TRUE - if(!silent) - to_chat(src, "You need at least one free arm.") - return FALSE - return TRUE //Here's the main proc itself -/mob/living/carbon/human/proc/mob_climax(forced_climax=FALSE,cause = "") //Forced is instead of the other proc, makes you cum if you have the tools for it, ignoring restraints - set waitfor = FALSE +/mob/living/carbon/human/mob_climax(forced_climax=FALSE, cause = "none") //Forced is instead of the other proc, makes you cum if you have the tools for it, ignoring restraints if(mb_cd_timer > world.time) if(!forced_climax) //Don't spam the message to the victim if forced to come too fast to_chat(src, "You need to wait [DisplayTimeText((mb_cd_timer - world.time), TRUE)] before you can do that again!") return + mb_cd_timer = (world.time + mb_cd_length) - if(!client?.prefs.arousable || !has_dna()) - return - if(stat == DEAD) - if(!forced_climax) + + if(canbearoused && has_dna()) + if(stat==2) to_chat(src, "You can't do that while dead!") - return - if(forced_climax) //Something forced us to cum, this is not a masturbation thing and does not progress to the other checks - log_message("was forced to climax by [cause]",LOG_EMOTE) - for(var/obj/item/organ/genital/G in internal_organs) - if(!(G.genital_flags & CAN_CLIMAX_WITH)) //Skip things like wombs and testicles - continue - mob_climax_outside(G, mb_time = 0) //removed climax timer for sudden, forced orgasms - //Now all genitals that could climax, have. - //Since this was a forced climax, we do not need to continue with the other stuff - mb_cd_timer = world.time + mb_cd_length - return - //If we get here, then this is not a forced climax and we gotta check a few things. + return + if(forced_climax) //Something forced us to cum, this is not a masturbation thing and does not progress to the other checks + for(var/obj/item/organ/O in internal_organs) + if(istype(O, /obj/item/organ/genital)) + var/obj/item/organ/genital/G = O + if(!G.can_climax) //Skip things like wombs and testicles + continue + var/mob/living/partner + var/check_target + var/list/worn_stuff = get_equipped_items() - if(stat == UNCONSCIOUS) //No sleep-masturbation, you're unconscious. - to_chat(src, "You must be conscious to do that!") - return + if(G.is_exposed(worn_stuff)) + if(src.pulling) //Are we pulling someone? Priority target, we can't be making option menus for this, has to be quick + if(isliving(src.pulling)) //Don't fuck objects + check_target = src.pulling + if(src.pulledby && !check_target) //prioritise pulled over pulledby + if(isliving(src.pulledby)) + check_target = src.pulledby + //Now we should have a partner, or else we have to come alone + if(check_target) + if(iscarbon(check_target)) //carbons can have clothes + var/mob/living/carbon/C = check_target + if(C.exposed_genitals.len || C.is_groin_exposed() || C.is_chest_exposed()) //Are they naked enough? + partner = C + else //A cat is fine too + partner = check_target + if(partner) //Did they pass the clothing checks? + mob_climax_partner(G, partner, mb_time = 0) //Instant climax due to forced + continue //You've climaxed once with this organ, continue on + //not exposed OR if no partner was found while exposed, climax alone + mob_climax_outside(G, mb_time = 0) //removed climax timer for sudden, forced orgasms + //Now all genitals that could climax, have. + //Since this was a forced climax, we do not need to continue with the other stuff + return + //If we get here, then this is not a forced climax and we gotta check a few things. - //Ok, now we check what they want to do. - var/choice = input(src, "Select sexual activity", "Sexual activity:") as null|anything in list("Climax alone","Climax with partner", "Fill container") - if(!choice) - return + if(stat==1) //No sleep-masturbation, you're unconscious. + to_chat(src, "You must be conscious to do that!") + return + if(getArousal() < 33) //flat number instead of percentage + to_chat(src, "You aren't aroused enough for that!") + return - switch(choice) - if("Climax alone") - if(!available_rosie_palms()) - return - var/obj/item/organ/genital/picked_organ = pick_climax_genitals() - if(picked_organ && available_rosie_palms(TRUE)) - mob_climax_outside(picked_organ) - if("Climax with partner") - //We need no hands, we can be restrained and so on, so let's pick an organ - var/obj/item/organ/genital/picked_organ = pick_climax_genitals() - if(picked_organ) - var/mob/living/partner = pick_partner() //Get someone - if(partner) - var/spillage = input(src, "Would your fluids spill outside?", "Choose overflowing option", "Yes") as null|anything in list("Yes", "No") - if(spillage && in_range(src, partner)) - mob_climax_partner(picked_organ, partner, spillage == "Yes" ? TRUE : FALSE) - if("Fill container") - //We'll need hands and no restraints. - if(!available_rosie_palms(FALSE, /obj/item/reagent_containers)) - return - //We got hands, let's pick an organ - var/obj/item/organ/genital/picked_organ - picked_organ = pick_climax_genitals() //Gotta be climaxable, not just masturbation, to fill with fluids. - if(picked_organ) - //Good, got an organ, time to pick a container - var/obj/item/reagent_containers/fluid_container = pick_climax_container() - if(fluid_container && available_rosie_palms(TRUE, /obj/item/reagent_containers)) - mob_fill_container(picked_organ, fluid_container) - mb_cd_timer = world.time + mb_cd_length + //Ok, now we check what they want to do. + var/choice = input(src, "Select sexual activity", "Sexual activity:") in list("Masturbate", "Climax alone", "Climax with partner","Climax over partner", "Fill container") + + switch(choice) + + if("Masturbate") + if(restrained(TRUE)) //TRUE ignores grabs + to_chat(src, "You can't do that while restrained!") + return + var/free_hands = get_num_arms() + if(!free_hands) + to_chat(src, "You need at least one free arm.") + return + for(var/helditem in held_items)//how many hands are free + if(isobj(helditem)) + free_hands-- + if(free_hands <= 0) + to_chat(src, "You're holding too many things.") + return + //We got hands, let's pick an organ + var/obj/item/organ/genital/picked_organ + picked_organ = pick_masturbate_genitals() + if(picked_organ) + mob_masturbate(picked_organ) + return + else //They either lack organs that can masturbate, or they didn't pick one. + to_chat(src, "You cannot masturbate without choosing genitals.") + return + + if("Climax alone") + if(restrained(TRUE)) //TRUE ignores grabs + to_chat(src, "You can't do that while restrained!") + return + var/free_hands = get_num_arms() + if(!free_hands) + to_chat(src, "You need at least one free arm.") + return + for(var/helditem in held_items)//how many hands are free + if(isobj(helditem)) + free_hands-- + if(free_hands <= 0) + to_chat(src, "You're holding too many things.") + return + //We got hands, let's pick an organ + var/obj/item/organ/genital/picked_organ + picked_organ = pick_climax_genitals() + if(picked_organ) + mob_climax_outside(picked_organ) + return + else //They either lack organs that can masturbate, or they didn't pick one. + to_chat(src, "You cannot climax without choosing genitals.") + return + + if("Climax with partner") + //We need no hands, we can be restrained and so on, so let's pick an organ + var/obj/item/organ/genital/picked_organ + picked_organ = pick_climax_genitals() + if(picked_organ) + var/mob/living/partner = pick_partner() //Get someone + if(partner) + /*GS13 Port - De we need breeding? For now disable it for inital porting + var/obj/item/organ/genital/penis/P = picked_organ + if(partner.breedable == 1 && picked_organ.name == "penis") + var/impreg = input(src, "Would this action carry the risk of pregnancy?", "Choose a option", "Yes") as anything in list("Yes", "No") + if(impreg == "Yes") //If we are impregging + var/spillage = input(src, "Would your fluids spill outside?", "Choose overflowing option", "Yes") as anything in list("Yes", "No") + if(spillage == "Yes") + mob_climax_partner(picked_organ, partner, TRUE, TRUE, FALSE) + else + mob_climax_partner(picked_organ, partner, FALSE, TRUE, FALSE) + else + var/spillage = input(src, "Would your fluids spill outside?", "Choose overflowing option", "Yes") as anything in list("Yes", "No") + if(spillage == "Yes") + mob_climax_partner(picked_organ, partner, TRUE, FALSE, FALSE) + else + mob_climax_partner(picked_organ, partner, FALSE, FALSE, FALSE) //Wow, im trash at coding, I need to find a better way of coding this, ill rewrite it later.-quote + return + + else //If we arent impregging + var/spillage = input(src, "Would your fluids spill outside?", "Choose overflowing option", "Yes") as anything in list("Yes", "No") + if(spillage == "Yes") + mob_climax_partner(picked_organ, partner, TRUE, FALSE, FALSE) + else + mob_climax_partner(picked_organ, partner, FALSE, FALSE, FALSE) + return + */ + var/spillage = input(src, "Would your fluids spill outside?", "Choose overflowing option", "Yes") as anything in list("Yes", "No") + if(spillage == "Yes") + mob_climax_partner(picked_organ, partner, TRUE, FALSE, FALSE) + else + mob_climax_partner(picked_organ, partner, FALSE, FALSE, FALSE) + return + + else + to_chat(src, "You cannot do this alone.") + return + else //They either lack organs that can masturbate, or they didn't pick one. + to_chat(src, "You cannot climax without choosing genitals.") + return + if("Climax over partner") + var/obj/item/organ/genital/picked_organ + picked_organ = pick_climax_genitals() + if(picked_organ) + var/mob/living/partner = pick_partner_overide() //Get your partner, clothed or not. + if(partner) + mob_climax_partner(picked_organ, partner, FALSE, FALSE, TRUE) + else + to_chat(src, "You cannot do this alone.") + + if("Fill container") + //We'll need hands and no restraints. + if(restrained(TRUE)) //TRUE ignores grabs + to_chat(src, "You can't do that while restrained!") + return + var/free_hands = get_num_arms() + if(!free_hands) + to_chat(src, "You need at least one free arm.") + return + for(var/helditem in held_items)//how many hands are free + if(isobj(helditem)) + free_hands-- + if(free_hands <= 0) + to_chat(src, "You're holding too many things.") + return + //We got hands, let's pick an organ + var/obj/item/organ/genital/picked_organ + picked_organ = pick_climax_genitals() //Gotta be climaxable, not just masturbation, to fill with fluids. + if(picked_organ) + //Good, got an organ, time to pick a container + var/obj/item/reagent_containers/fluid_container = pick_climax_container() + if(fluid_container) + mob_fill_container(picked_organ, fluid_container) + return + else + to_chat(src, "You cannot do this without anything to fill.") + return + else //They either lack organs that can climax, or they didn't pick one. + to_chat(src, "You cannot fill anything without choosing genitals.") + return + else //Somehow another option was taken, maybe something interrupted the selection or it was cancelled + return //Just end it in that case. -/mob/living/carbon/human/verb/climax_verb() - set category = "IC" - set name = "Climax" - set desc = "Lets you choose a couple ways to ejaculate." - mob_climax() diff --git a/code/modules/arousal/genitals.dm b/code/modules/arousal/genitals.dm index e4b9f4107c..de892c050f 100644 --- a/code/modules/arousal/genitals.dm +++ b/code/modules/arousal/genitals.dm @@ -9,6 +9,7 @@ var/orgasm_verb = "cumming" //present continous var/arousal_verb = "You feel aroused" var/unarousal_verb = "You no longer feel aroused" + var/can_climax = FALSE var/fluid_transfer_factor = 0 //How much would a partner get in them if they climax using this? var/size = 2 //can vary between num or text, just used in icon_state strings var/datum/reagent/fluid_id = null @@ -16,11 +17,22 @@ var/fluid_efficiency = 1 var/fluid_rate = CUM_RATE var/fluid_mult = 1 + var/producing = FALSE var/last_orgasmed = 0 - var/aroused_state = FALSE //Boolean used in icon_state strings + var/aroused_state = FALSE //Boolean used in icon_state strings + var/aroused_amount = 50 //This is a num from 0 to 100 for arousal percentage for when to use arousal state icons. var/obj/item/organ/genital/linked_organ var/linked_organ_slot //used for linking an apparatus' organ to its other half on update_link(). var/layer_index = GENITAL_LAYER_INDEX //Order should be very important. FIRST vagina, THEN testicles, THEN penis, as this affects the order they are rendered in. + var/through_clothes = FALSE + var/internal = FALSE + var/hidden = FALSE + var/colourtint = "" + var/mode = "" + var/obj/item/equipment //for fun stuff that goes on the gentials/maybe rings down the line + var/dontlist = FALSE + var/nochange = FALSE //stops people changing visablity. + /obj/item/organ/genital/Initialize(mapload, do_update = TRUE) . = ..() @@ -33,8 +45,14 @@ linked_organ = null . = ..() +//GS13 Port - Make gentials actually produce "reagents" /obj/item/organ/genital/on_life() - return + if(QDELETED(src)) + return + if(!reagents || !owner) + return + + generate_fluid(reagents) /obj/item/organ/genital/proc/set_aroused_state(new_state,cause = "manual toggle") if(!(genital_flags & GENITAL_CAN_AROUSE)) @@ -89,17 +107,21 @@ if(owner) owner.log_message("Exposed their [src]",LOG_EMOTE) owner.exposed_genitals += src + mode = GEN_VISIBLE_ALWAYS if(GEN_VISIBLE_NO_CLOTHES) if(owner) owner.log_message("Hid their [src] under clothes only",LOG_EMOTE) + mode = GEN_VISIBLE_NO_CLOTHES if(GEN_VISIBLE_NO_UNDIES) genital_flags |= GENITAL_UNDIES_HIDDEN if(owner) owner.log_message("Hid their [src] under underwear",LOG_EMOTE) + mode = GEN_VISIBLE_NO_UNDIES if(GEN_VISIBLE_NEVER) genital_flags |= GENITAL_HIDDEN if(owner) owner.log_message("Hid their [src] completely",LOG_EMOTE) + mode = GEN_VISIBLE_NEVER if(update && owner && ishuman(owner)) //recast to use update genitals proc var/mob/living/carbon/human/H = owner diff --git a/code/modules/arousal/organs/breasts.dm b/code/modules/arousal/organs/breasts.dm index d7a8c67adb..69020da4f3 100644 --- a/code/modules/arousal/organs/breasts.dm +++ b/code/modules/arousal/organs/breasts.dm @@ -11,9 +11,11 @@ size = BREASTS_SIZE_DEF // "c". Refer to the breast_values static list below for the cups associated number values fluid_id = /datum/reagent/consumable/milk fluid_rate = MILK_RATE + producing = TRUE shape = DEF_BREASTS_SHAPE genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH|GENITAL_FUID_PRODUCTION|GENITAL_CAN_AROUSE|UPDATE_OWNER_APPEARANCE|GENITAL_UNDIES_HIDDEN masturbation_verb = "massage" + can_climax = TRUE arousal_verb = "Your breasts start feeling sensitive" unarousal_verb = "Your breasts no longer feel sensitive" orgasm_verb = "leaking" diff --git a/code/modules/arousal/organs/penis.dm b/code/modules/arousal/organs/penis.dm index e1025094c3..7e0f31ed43 100644 --- a/code/modules/arousal/organs/penis.dm +++ b/code/modules/arousal/organs/penis.dm @@ -6,6 +6,7 @@ zone = BODY_ZONE_PRECISE_GROIN slot = ORGAN_SLOT_PENIS masturbation_verb = "stroke" + can_climax = TRUE arousal_verb = "You pop a boner" unarousal_verb = "Your boner goes down" genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH|GENITAL_CAN_AROUSE|UPDATE_OWNER_APPEARANCE|GENITAL_UNDIES_HIDDEN|GENITAL_CAN_TAUR diff --git a/code/modules/arousal/organs/testicles.dm b/code/modules/arousal/organs/testicles.dm index bfb5c99a55..2fdb0fb2c2 100644 --- a/code/modules/arousal/organs/testicles.dm +++ b/code/modules/arousal/organs/testicles.dm @@ -13,7 +13,9 @@ var/size_name = "average" shape = DEF_BALLS_SHAPE fluid_id = /datum/reagent/consumable/semen + producing = TRUE masturbation_verb = "massage" + can_climax = TRUE layer_index = TESTICLES_LAYER_INDEX /obj/item/organ/genital/testicles/generate_fluid() diff --git a/code/modules/arousal/organs/vagina.dm b/code/modules/arousal/organs/vagina.dm index 5c8bbeea98..aaeb0fdf99 100644 --- a/code/modules/arousal/organs/vagina.dm +++ b/code/modules/arousal/organs/vagina.dm @@ -9,6 +9,7 @@ shape = DEF_VAGINA_SHAPE genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH|GENITAL_CAN_AROUSE|GENITAL_UNDIES_HIDDEN masturbation_verb = "finger" + can_climax = TRUE arousal_verb = "You feel wetness on your crotch" unarousal_verb = "You no longer feel wet" fluid_transfer_factor = 0.1 //Yes, some amount is exposed to you, go get your AIDS diff --git a/code/modules/awaymissions/corpse.dm b/code/modules/awaymissions/corpse.dm index 46e80b3255..041dd4be96 100644 --- a/code/modules/awaymissions/corpse.dm +++ b/code/modules/awaymissions/corpse.dm @@ -32,6 +32,7 @@ var/banType = "lavaland" var/ghost_usable = TRUE var/skip_reentry_check = FALSE //Skips the ghost role blacklist time for people who ghost/suicide/cryo + var/mirrorcanloadappearance = TRUE //GS13 EDIT ///override this to add special spawn conditions to a ghost role /obj/effect/mob_spawn/proc/allow_spawn(mob/user, silent = FALSE) @@ -139,6 +140,7 @@ M.mind.assigned_role = assignedrole special(M, name) MM.name = M.real_name + M.checkloadappearance() // GS13 EDIT if(uses > 0) uses-- if(!permanent && !uses) @@ -251,6 +253,10 @@ W.assignment = id_job W.registered_name = H.real_name W.update_label() + //GS13 EDIT START + if (mirrorcanloadappearance) + H.mirrorcanloadappearance = TRUE + //GS13 EDIT END //Instant version - use when spawning corpses during runtime /obj/effect/mob_spawn/human/corpse diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm index cf5b9fd913..cf81e47337 100644 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -132,7 +132,7 @@ GLOBAL_LIST_EMPTY(preferences_datums) var/eye_type = DEFAULT_EYES_TYPE //Eye type var/split_eye_colors = FALSE var/datum/species/pref_species = new /datum/species/human() //Mutant race - var/list/features = list("mcolor" = "FFFFFF", "mcolor2" = "FFFFFF", "mcolor3" = "FFFFFF", "tail_lizard" = "Smooth", "tail_human" = "None", "snout" = "Round", "horns" = "None", "horns_color" = "85615a", "ears" = "None", "wings" = "None", "wings_color" = "FFF", "frills" = "None", "deco_wings" = "None", "spines" = "None", "legs" = "Plantigrade", "insect_wings" = "Plain", "insect_fluff" = "None", "insect_markings" = "None", "arachnid_legs" = "Plain", "arachnid_spinneret" = "Plain", "arachnid_mandibles" = "Plain", "mam_body_markings" = list(), "mam_ears" = "None", "mam_snouts" = "None", "mam_tail" = "None", "mam_tail_animated" = "None", "xenodorsal" = "Standard", "xenohead" = "Standard", "xenotail" = "Xenomorph Tail", "taur" = "None", "genitals_use_skintone" = FALSE, "has_cock" = FALSE, "cock_shape" = DEF_COCK_SHAPE, "cock_length" = COCK_SIZE_DEF, "cock_diameter_ratio" = COCK_DIAMETER_RATIO_DEF, "cock_color" = "ffffff", "cock_taur" = FALSE, "has_balls" = FALSE, "balls_color" = "ffffff", "balls_shape" = DEF_BALLS_SHAPE, "balls_size" = BALLS_SIZE_DEF, "balls_cum_rate" = CUM_RATE, "balls_cum_mult" = CUM_RATE_MULT, "balls_efficiency" = CUM_EFFICIENCY, "has_breasts" = FALSE, "breasts_color" = "ffffff", "breasts_size" = BREASTS_SIZE_DEF, "breasts_shape" = DEF_BREASTS_SHAPE, "breasts_fluid" = /datum/reagent/consumable/milk, "breasts_producing" = FALSE, "has_vag" = FALSE, "vag_shape" = DEF_VAGINA_SHAPE, "vag_color" = "ffffff", "has_womb" = FALSE, "has_butt" = FALSE, "butt_color" = "ffffff", "butt_size" = BUTT_SIZE_DEF, "balls_visibility" = GEN_VISIBLE_NO_UNDIES, "breasts_visibility"= GEN_VISIBLE_NO_UNDIES, "cock_visibility" = GEN_VISIBLE_NO_UNDIES, "vag_visibility" = GEN_VISIBLE_NO_UNDIES, "butt_visibility" = GEN_VISIBLE_NO_UNDIES, "ipc_screen" = "Sunburst", "ipc_antenna" = "None", "flavor_text" = "", "silicon_flavor_text" = "", "ooc_notes" = "", "meat_type" = "Mammalian", "body_model" = MALE, "body_size" = RESIZE_DEFAULT_SIZE, "color_scheme" = OLD_CHARACTER_COLORING) + var/list/features = list("mcolor" = "FFFFFF", "mcolor2" = "FFFFFF", "mcolor3" = "FFFFFF", "tail_lizard" = "Smooth", "tail_human" = "None", "snout" = "Round", "horns" = "None", "horns_color" = "85615a", "ears" = "None", "wings" = "None", "wings_color" = "FFF", "frills" = "None", "deco_wings" = "None", "spines" = "None", "legs" = "Plantigrade", "insect_wings" = "Plain", "insect_fluff" = "None", "insect_markings" = "None", "arachnid_legs" = "Plain", "arachnid_spinneret" = "Plain", "arachnid_mandibles" = "Plain", "mam_body_markings" = list(), "mam_ears" = "None", "mam_snouts" = "None", "mam_tail" = "None", "mam_tail_animated" = "None", "xenodorsal" = "Standard", "xenohead" = "Standard", "xenotail" = "Xenomorph Tail", "taur" = "None", "genitals_use_skintone" = FALSE, "has_cock" = FALSE, "cock_shape" = DEF_COCK_SHAPE, "cock_length" = COCK_SIZE_DEF, "cock_diameter_ratio" = COCK_DIAMETER_RATIO_DEF, "cock_color" = "ffffff", "cock_taur" = FALSE, "has_balls" = FALSE, "balls_color" = "ffffff", "balls_shape" = DEF_BALLS_SHAPE, "balls_size" = BALLS_SIZE_DEF, "balls_cum_rate" = CUM_RATE, "balls_cum_mult" = CUM_RATE_MULT, "balls_efficiency" = CUM_EFFICIENCY, "has_breasts" = FALSE, "breasts_color" = "ffffff", "breasts_size" = BREASTS_SIZE_DEF, "breasts_shape" = DEF_BREASTS_SHAPE, "breasts_fluid" = /datum/reagent/consumable/milk, "breasts_producing" = FALSE, "has_vag" = FALSE, "vag_shape" = DEF_VAGINA_SHAPE, "vag_color" = "ffffff", "has_womb" = FALSE, "has_butt" = FALSE, "butt_color" = "ffffff", "butt_size" = BUTT_SIZE_DEF, "balls_visibility" = GEN_VISIBLE_NO_UNDIES, "breasts_visibility"= GEN_VISIBLE_NO_UNDIES, "cock_visibility" = GEN_VISIBLE_NO_UNDIES, "vag_visibility" = GEN_VISIBLE_NO_UNDIES, "butt_visibility" = GEN_VISIBLE_NO_UNDIES, "ipc_screen" = "Sunburst", "ipc_antenna" = "None", "flavor_text" = "", "silicon_flavor_text" = "", "ooc_notes" = "", "meat_type" = "Mammalian", "body_model" = MALE, "body_size" = RESIZE_DEFAULT_SIZE, "color_scheme" = OLD_CHARACTER_COLORING, "belly_size" = BELLY_SIZE_DEF, "inflatable_belly" = FALSE, "belly_visibility" = GEN_VISIBLE_NO_UNDIES) var/custom_speech_verb = "default" //if your say_mod is to be something other than your races var/custom_tongue = "default" //if your tongue is to be something other than your races @@ -845,7 +845,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) dat += "Belly Size: [features["belly_size"]]" dat += "Belly Visibility:[features["belly_visibility"]]" // GS13: tweak inflation description - //dat += "Inflation (climax with and manual belly size change in arousal menu):[features["inflatable_belly"] == 1 ? "Yes" : "No"]" + dat += "Inflation (climax with and manual belly size change in arousal menu):[features["inflatable_belly"] == 1 ? "Yes" : "No"]" + dat += "" dat += "" @@ -3050,6 +3051,8 @@ GLOBAL_LIST_EMPTY(preferences_datums) features["has_butt"] = !features["has_butt"] if("has_belly") features["has_belly"] = !features["has_belly"] + if("inflatable_belly") + features["inflatable_belly"] = !features["inflatable_belly"] if("widescreenpref") widescreenpref = !widescreenpref user.client.view_size.setDefault(getScreenSize(widescreenpref)) diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm index 488f167981..e4d86720f5 100644 --- a/code/modules/client/preferences_savefile.dm +++ b/code/modules/client/preferences_savefile.dm @@ -704,7 +704,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car var/savefile/S = new /savefile(path) if(!S) return FALSE - features = list("mcolor" = "FFFFFF", "mcolor2" = "FFFFFF", "mcolor3" = "FFFFFF", "tail_lizard" = "Smooth", "tail_human" = "None", "snout" = "Round", "horns" = "None", "horns_color" = "85615a", "ears" = "None", "wings" = "None", "wings_color" = "FFF", "frills" = "None", "deco_wings" = "None", "spines" = "None", "legs" = "Plantigrade", "insect_wings" = "Plain", "insect_fluff" = "None", "insect_markings" = "None", "arachnid_legs" = "Plain", "arachnid_spinneret" = "Plain", "arachnid_mandibles" = "Plain", "mam_body_markings" = "Plain", "mam_ears" = "None", "mam_snouts" = "None", "mam_tail" = "None", "mam_tail_animated" = "None", "xenodorsal" = "Standard", "xenohead" = "Standard", "xenotail" = "Xenomorph Tail", "taur" = "None", "genitals_use_skintone" = FALSE, "has_cock" = FALSE, "cock_shape" = DEF_COCK_SHAPE, "cock_length" = COCK_SIZE_DEF, "cock_diameter_ratio" = COCK_DIAMETER_RATIO_DEF, "cock_color" = "ffffff", "cock_taur" = FALSE, "has_balls" = FALSE, "balls_color" = "ffffff", "balls_shape" = DEF_BALLS_SHAPE, "balls_size" = BALLS_SIZE_DEF, "balls_cum_rate" = CUM_RATE, "balls_cum_mult" = CUM_RATE_MULT, "balls_efficiency" = CUM_EFFICIENCY, "has_breasts" = FALSE, "breasts_color" = "ffffff", "breasts_size" = BREASTS_SIZE_DEF, "breasts_shape" = DEF_BREASTS_SHAPE, "breasts_producing" = FALSE, "has_vag" = FALSE, "vag_shape" = DEF_VAGINA_SHAPE, "vag_color" = "ffffff", "has_womb" = FALSE, "has_butt" = FALSE, "butt_color" = "ffffff", "butt_size" = BUTT_SIZE_DEF, "balls_visibility" = GEN_VISIBLE_NO_UNDIES, "breasts_visibility"= GEN_VISIBLE_NO_UNDIES, "cock_visibility" = GEN_VISIBLE_NO_UNDIES, "vag_visibility" = GEN_VISIBLE_NO_UNDIES, "butt_visibility" = GEN_VISIBLE_NO_UNDIES, "belly_visibility" = GEN_VISIBLE_NO_UNDIES, "ipc_screen" = "Sunburst", "ipc_antenna" = "None", "flavor_text" = "", "silicon_flavor_text" = "", "ooc_notes" = "", "meat_type" = "Mammalian", "body_model" = MALE, "body_size" = RESIZE_DEFAULT_SIZE, "color_scheme" = OLD_CHARACTER_COLORING) + features = list("mcolor" = "FFFFFF", "mcolor2" = "FFFFFF", "mcolor3" = "FFFFFF", "tail_lizard" = "Smooth", "tail_human" = "None", "snout" = "Round", "horns" = "None", "horns_color" = "85615a", "ears" = "None", "wings" = "None", "wings_color" = "FFF", "frills" = "None", "deco_wings" = "None", "spines" = "None", "legs" = "Plantigrade", "insect_wings" = "Plain", "insect_fluff" = "None", "insect_markings" = "None", "arachnid_legs" = "Plain", "arachnid_spinneret" = "Plain", "arachnid_mandibles" = "Plain", "mam_body_markings" = "Plain", "mam_ears" = "None", "mam_snouts" = "None", "mam_tail" = "None", "mam_tail_animated" = "None", "xenodorsal" = "Standard", "xenohead" = "Standard", "xenotail" = "Xenomorph Tail", "taur" = "None", "genitals_use_skintone" = FALSE, "has_cock" = FALSE, "cock_shape" = DEF_COCK_SHAPE, "cock_length" = COCK_SIZE_DEF, "cock_diameter_ratio" = COCK_DIAMETER_RATIO_DEF, "cock_color" = "ffffff", "cock_taur" = FALSE, "has_balls" = FALSE, "balls_color" = "ffffff", "balls_shape" = DEF_BALLS_SHAPE, "balls_size" = BALLS_SIZE_DEF, "balls_cum_rate" = CUM_RATE, "balls_cum_mult" = CUM_RATE_MULT, "balls_efficiency" = CUM_EFFICIENCY, "has_breasts" = FALSE, "breasts_color" = "ffffff", "breasts_size" = BREASTS_SIZE_DEF, "breasts_shape" = DEF_BREASTS_SHAPE, "breasts_producing" = FALSE, "has_vag" = FALSE, "vag_shape" = DEF_VAGINA_SHAPE, "vag_color" = "ffffff", "has_womb" = FALSE, "has_butt" = FALSE, "butt_color" = "ffffff", "butt_size" = BUTT_SIZE_DEF, "balls_visibility" = GEN_VISIBLE_NO_UNDIES, "breasts_visibility"= GEN_VISIBLE_NO_UNDIES, "cock_visibility" = GEN_VISIBLE_NO_UNDIES, "vag_visibility" = GEN_VISIBLE_NO_UNDIES, "butt_visibility" = GEN_VISIBLE_NO_UNDIES, "belly_visibility" = GEN_VISIBLE_NO_UNDIES, "belly_size" = BELLY_SIZE_DEF, "inflatable_belly" = FALSE, "ipc_screen" = "Sunburst", "ipc_antenna" = "None", "flavor_text" = "", "silicon_flavor_text" = "", "ooc_notes" = "", "meat_type" = "Mammalian", "body_model" = MALE, "body_size" = RESIZE_DEFAULT_SIZE, "color_scheme" = OLD_CHARACTER_COLORING) S.cd = "/" if(!slot) diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 6723d2d4a6..5a9d3971cb 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -66,6 +66,9 @@ var/blood_state = BLOOD_STATE_NOT_BLOODY var/list/blood_smear = list(BLOOD_STATE_BLOOD = 0, BLOOD_STATE_OIL = 0, BLOOD_STATE_NOT_BLOODY = 0) + //GS13 Port - Arousal + var/cumdrip_rate = 0 //how long are we dripping jizz for? + var/name_override //For temporary visible name changes var/genital_override = FALSE //Force genitals on things incase of chems diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm index 9b8daf0384..a209aca017 100644 --- a/code/modules/mob/living/carbon/human/species.dm +++ b/code/modules/mob/living/carbon/human/species.dm @@ -546,6 +546,13 @@ GLOBAL_LIST_EMPTY(roundstart_race_names) SEND_SIGNAL(C, COMSIG_SPECIES_GAIN, src, old_species) + //GS13 Port - Add back arousal + if(NOAROUSAL in species_traits) + C.canbearoused = FALSE + else + if(C.client) + C.canbearoused = C.client?.prefs?.arousable + /datum/species/proc/update_species_slowdown(mob/living/carbon/human/H) H.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/species, TRUE, multiplicative_slowdown = speedmod) diff --git a/hyperstation/code/modules/arousal/arousalhud.dm b/hyperstation/code/modules/arousal/arousalhud.dm index c881d29cba..f4df481b63 100644 --- a/hyperstation/code/modules/arousal/arousalhud.dm +++ b/hyperstation/code/modules/arousal/arousalhud.dm @@ -3,7 +3,7 @@ //if you wanna use this on your own server go ahead, but alittle credit would always be nice! -quotefox //This still uses alot of cits arousal system! -/obj/screen/arousal/ui_interact(mob/user) +/atom/movable/screen/arousal/ui_interact(mob/user) . = ..() var/dat = {"Genitals

"} @@ -12,10 +12,9 @@ if(!G.nochange) if(!G.dontlist) // GS13: Fix spelling - dat += "[G.mode == "hidden" ? "[G.name] (Hidden)" : (G.mode == "clothes" ? "[G.name] (Hidden by Clothes)" : (G.mode == "visible" ? "[G.name] (Visible)" : "[G.name] (Visible)"))]
" + dat += "[G.mode == GEN_VISIBLE_NEVER ? "[G.name] (Hidden)" : (G.mode == GEN_VISIBLE_NO_UNDIES ? "[G.name] (Hidden by Undies)" : (G.mode == GEN_VISIBLE_NO_CLOTHES ? "[G.name] (Hidden by Clothes)" : (G.mode == GEN_VISIBLE_ALWAYS ? "[G.name] (Visible)" : "[G.name] (Visible)")))]
" dat += {"
Contexual Options

"} - var/obj/item/organ/genital/penis/P = user.getorganslot("penis") //Options dat += "Masturbate" dat += "(Stimulate a sexual organ with your hands.)
" @@ -65,22 +64,13 @@ dat += "Climax with [user.pulling]" dat += {"(Orgasm with another person.)
"} - var/mob/living/carbon/human/H = user.pulling - if(H.breedable && P && H) - dat += "Impregnate [U.pulling] ([clamp(U.impregchance,0,100)]%)" - dat += "(Climax inside another person, and attempt to knock them up.)
" else dat += "Climax over" dat += "(Requires a partner)
" dat += "Climax with" dat += "(Requires a partner)
" - //old code needs to be cleaned - if(P) - if(P.condom == 1) - dat += "Remove condom (penis)
" - if(P.sounding == 1) - dat += "Remove sounding rod (penis)
" + for(var/obj/item/organ/genital/G in U.internal_organs) if(G.equipment) //they have equipment dat += "Remove [G.equipment.name] ([G.name])
" @@ -94,7 +84,6 @@ var/datum/browser/popup = new(user, "arousal", "Arousal Panel") popup.set_content(dat) - popup.set_title_image(user.browse_rsc_icon(icon, icon_state), 500,600) popup.open() @@ -102,7 +91,7 @@ -/obj/screen/arousal/Topic(href, href_list) +/atom/movable/screen/arousal/Topic(href, href_list) . = ..() //Sanity checks. if(..()) return @@ -121,36 +110,36 @@ if(href_list["hidepenis"]) var/obj/item/organ/genital/penis/P = usr.getorganslot("penis") - var/picked_visibility = input(usr, "Choose visibility", "Expose/Hide genitals", "Hidden by clothes") in list("Always visible", "Hidden by clothes", "Always hidden") + var/picked_visibility = input(usr, "Choose visibility", "Expose/Hide genitals", "Hidden by clothes") in list("Always visible", "Hidden by Undies", "Hidden by clothes", "Always hidden") P.toggle_visibility(picked_visibility) if(href_list["hidevagina"]) var/obj/item/organ/genital/vagina/V = usr.getorganslot("vagina") - var/picked_visibility = input(usr, "Choose visibility", "Expose/Hide genitals", "Hidden by clothes") in list("Always visible", "Hidden by clothes", "Always hidden") + var/picked_visibility = input(usr, "Choose visibility", "Expose/Hide genitals", "Hidden by clothes") in list("Always visible", "Hidden by Undies", "Hidden by clothes", "Always hidden") V.toggle_visibility(picked_visibility) if(href_list["hidebreasts"]) var/obj/item/organ/genital/breasts/B = usr.getorganslot(ORGAN_SLOT_BREASTS) - var/picked_visibility = input(usr, "Choose visibility", "Expose/Hide genitals", "Hidden by clothes") in list("Always visible", "Hidden by clothes", "Always hidden") + var/picked_visibility = input(usr, "Choose visibility", "Expose/Hide genitals", "Hidden by clothes") in list("Always visible", "Hidden by Undies", "Hidden by clothes", "Always hidden") B.toggle_visibility(picked_visibility) if(href_list["hidebelly"]) var/obj/item/organ/genital/belly/E = usr.getorganslot("belly") - var/picked_visibility = input(usr, "Choose visibility", "Expose/Hide genitals", "Hidden by clothes") in list("Always visible", "Hidden by clothes", "Always hidden") + var/picked_visibility = input(usr, "Choose visibility", "Expose/Hide genitals", "Hidden by clothes") in list("Always visible", "Hidden by Undies", "Hidden by clothes", "Always hidden") E.toggle_visibility(picked_visibility) - if(href_list["hideanus"]) + if(href_list["hidebutt"]) var/obj/item/organ/genital/butt/A = usr.getorganslot(ORGAN_SLOT_BUTT) - var/picked_visibility = input(usr, "Choose visibility", "Expose/Hide genitals", "Hidden by clothes") in list("Always visible", "Hidden by clothes", "Always hidden") + var/picked_visibility = input(usr, "Choose visibility", "Expose/Hide genitals", "Hidden by clothes") in list("Always visible", "Hidden by Undies", "Hidden by clothes", "Always hidden") A.toggle_visibility(picked_visibility) if(href_list["hidetesticles"]) var/obj/item/organ/genital/testicles/T = usr.getorganslot("testicles") - var/picked_visibility = input(usr, "Choose visibility", "Expose/Hide genitals", "Hidden by clothes") in list("Always visible", "Hidden by clothes", "Always hidden") + var/picked_visibility = input(usr, "Choose visibility", "Expose/Hide genitals", "Hidden by clothes") in list("Always visible", "Hidden by Undies", "Hidden by clothes", "Always hidden") T.toggle_visibility(picked_visibility) if(href_list["masturbate"]) - if (H.arousalloss >= (H.max_arousal / 100) * 33) //requires 33% arousal. + if (H.arousal >= (H.max_arousal / 100) * 33) //requires 33% arousal. H.solomasturbate() return else @@ -158,7 +147,7 @@ return if(href_list["container"]) - if (H.arousalloss >= (H.max_arousal / 100) * 33) //requires 33% arousal. + if (H.arousal >= (H.max_arousal / 100) * 33) //requires 33% arousal. H.cumcontainer() return else @@ -166,7 +155,7 @@ return if(href_list["clothesplosion"]) - if (H.arousalloss >= (H.max_arousal / 100) * 33) //Requires 33% arousal. + if (H.arousal >= (H.max_arousal / 100) * 33) //Requires 33% arousal. H.clothesplosion() return else @@ -174,7 +163,7 @@ return if(href_list["climax"]) - if (H.arousalloss >= (H.max_arousal / 100) * 33) //requires 33% arousal. + if (H.arousal >= (H.max_arousal / 100) * 33) //requires 33% arousal. H.climaxalone(FALSE) return else @@ -182,7 +171,7 @@ return if(href_list["climaxover"]) - if (H.arousalloss >= (H.max_arousal / 100) * 33) //requires 33% arousal. + if (H.arousal >= (H.max_arousal / 100) * 33) //requires 33% arousal. H.climaxover(usr.pulling) return else @@ -190,7 +179,7 @@ return if(href_list["climaxwith"]) - if (H.arousalloss >= (H.max_arousal / 100) * 33) //requires 33% arousal. + if (H.arousal >= (H.max_arousal / 100) * 33) //requires 33% arousal. H.climaxwith(usr.pulling) return else @@ -198,7 +187,7 @@ return if(href_list["impreg"]) - if (H.arousalloss >= (H.max_arousal / 100) * 33) //requires 33% arousal. + if (H.arousal >= (H.max_arousal / 100) * 33) //requires 33% arousal. H.impregwith(usr.pulling) return else @@ -248,13 +237,6 @@ else to_chat(usr, "Your belly is already at the maximum size! ") - - if(href_list["removecondom"]) - H.menuremovecondom() - - if(href_list["removesound"]) - H.menuremovesounding() - if(href_list["removeequipmentpenis"]) var/obj/item/organ/genital/penis/O = usr.getorganslot("penis") var/obj/item/I = O.equipment @@ -302,7 +284,7 @@ src.ui_interact(usr) -obj/screen/arousal/proc/kiss() +/atom/movable/screen/arousal/proc/kiss() if(usr.restrained(TRUE)) to_chat(usr, "You can't do that while restrained!") return @@ -310,7 +292,7 @@ obj/screen/arousal/proc/kiss() if (H) H.kisstarget(H.pulling) -obj/screen/arousal/proc/feed() +/atom/movable/screen/arousal/proc/feed() if(usr.restrained(TRUE)) to_chat(usr, "You can't do that while restrained!") return @@ -318,7 +300,7 @@ obj/screen/arousal/proc/feed() if (H) H.genitalfeed(H.pulling) -obj/screen/arousal/proc/feedfrom() +/atom/movable/screen/arousal/proc/feedfrom() if(usr.restrained(TRUE)) to_chat(usr, "You can't do that while restrained!") return @@ -326,7 +308,7 @@ obj/screen/arousal/proc/feedfrom() if (H) H.genitalfeedfrom(H.pulling) -obj/screen/arousal/proc/feedyourself() +/atom/movable/screen/arousal/proc/feedyourself() if(usr.restrained(TRUE)) to_chat(usr, "You can't do that while restrained!") return @@ -334,47 +316,6 @@ obj/screen/arousal/proc/feedyourself() if (H) H.genitalfeedyourself() - -/mob/living/carbon/human/proc/menuremovecondom() - - if(restrained(TRUE)) - to_chat(src, "You can't do that while restrained!") - return - var/free_hands = get_num_arms() - if(!free_hands) - to_chat(src, "You need at least one free arm.") - return - var/obj/item/organ/genital/penis/P = getorganslot("penis") - if(!P.condom) - to_chat(src, "You don't have a condom on!") - return - if(P.condom) - to_chat(src, "You tug the condom off the end of your penis!") - removecondom() - src.ui_interact(usr) //reopen dialog - return - return - -/mob/living/carbon/human/proc/menuremovesounding() - - if(restrained(TRUE)) - to_chat(src, "You can't do that while restrained!") - return - var/free_hands = get_num_arms() - if(!free_hands) - to_chat(src, "You need at least one free arm.") - return - var/obj/item/organ/genital/penis/P = getorganslot("penis") - if(!P.sounding) - to_chat(src, "You don't have a rod inside!") - return - if(P.sounding) - to_chat(src, "You pull the rod off from the tip of your penis!") - removesounding() - src.ui_interact(usr) //reopen dialog - return - return - /mob/living/carbon/human/proc/solomasturbate() if(restrained(TRUE)) to_chat(src, "You can't do that while restrained!") @@ -437,10 +378,8 @@ obj/screen/arousal/proc/feedyourself() var/mob/living/partner = L if(partner) src << browse(null, "window=arousal") //alls fine, we can close the window now. - var/obj/item/organ/genital/penis/P = picked_organ var/spillage = "No" //default to no, just incase player has items on to prevent climax - if(!P.condom == 1&&!P.sounding == 1) //you cant climax with a condom on or sounding in. - spillage = input(src, "Would your fluids spill outside?", "Choose overflowing option", "Yes") as anything in list("Yes", "No") + spillage = input(src, "Would your fluids spill outside?", "Choose overflowing option", "Yes") as anything in list("Yes", "No") if(spillage == "Yes") mob_climax_partner(picked_organ, partner, TRUE, FALSE, FALSE) else @@ -463,13 +402,6 @@ obj/screen/arousal/proc/feedyourself() src << browse(null, "window=arousal") //alls fine, we can close the window now. var/mob/living/partner = L if(partner) - var/obj/item/organ/genital/penis/P = picked_organ - if(P.condom == 1) - to_chat(src, "You cannot do this action with a condom on.") - return - if(P.sounding == 1) - to_chat(src, "You cannot do this action with a sounding in.") - return mob_climax_partner(picked_organ, partner, FALSE, FALSE, TRUE) else to_chat(src, "You cannot do this alone.") @@ -494,6 +426,7 @@ obj/screen/arousal/proc/feedyourself() /mob/living/carbon/human/proc/impregwith(mob/living/T) + /*GS13 Port - Do we even do breeding in legacy? var/mob/living/carbon/human/L = pick_partner() var/obj/item/organ/genital/picked_organ picked_organ = src.getorganslot("penis") //Impregnation must be done with a penis. @@ -504,13 +437,6 @@ obj/screen/arousal/proc/feedyourself() to_chat(src, "Your partner cannot be impregnated.")//some fuckary happening, you shouldnt even get to this point tbh. return var/obj/item/organ/genital/penis/P = picked_organ - //you cant impreg with a condom on or sounding in. - if(P.condom == 1) - to_chat(src, "You cannot do this action with a condom on.") - return - if(P.sounding == 1) - to_chat(src, "You cannot do this action with a sounding in.") - return src << browse(null, "window=arousal") //alls fine, we can close the window now. //Keeping this for messy fun var/spillage = input(src, "Would your fluids spill outside?", "Choose overflowing option", "Yes") as anything in list("Yes", "No") @@ -524,6 +450,8 @@ obj/screen/arousal/proc/feedyourself() else //no penis :( to_chat(src, "You cannot impregnate without a penis.") return + */ + return /mob/living/carbon/human/proc/cumcontainer(mob/living/T) //We'll need hands and no restraints. @@ -580,14 +508,6 @@ obj/screen/arousal/proc/feedyourself() picked_organ = pick_climax_genitals() //Gotta be climaxable, not just masturbation, to fill with fluids. if(picked_organ) //Good, got an organ, time to pick a container - if(picked_organ.name == "penis")//if the select organ is a penis - var/obj/item/organ/genital/penis/P = src.getorganslot("penis") - if(P.condom) //if the penis is condomed - to_chat(src, "You cannot feed someone when there is a condom over your [picked_organ.name].") - return - if(P.sounding) //if the penis is sounded - to_chat(src, "You cannot feed someone when there is a rod inside your [picked_organ.name].") - return if(picked_organ.producing) //Can it produce its own fluids, such as breasts? fluid_source = picked_organ.reagents else @@ -605,7 +525,7 @@ obj/screen/arousal/proc/feedyourself() "You used your [picked_organ.name] to feed [L.name] a total of [total_fluids]u's.") SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) if(picked_organ.can_climax) - setArousalLoss(min_arousal) + setArousal(min_arousal) else //They either lack organs that can climax, or they didn't pick one. to_chat(src, "You cannot fill anything without choosing exposed genitals.") @@ -633,14 +553,6 @@ obj/screen/arousal/proc/feedyourself() if(picked_organ) //Good, got an organ, time to pick a container - if(picked_organ.name == "penis")//if the select organ is a penis - var/obj/item/organ/genital/penis/P = L.getorganslot("penis") - if(P.condom) //if the penis is condomed - to_chat(src, "You cannot feed from [picked_organ.name] when there is a condom over it.") - return - if(P.sounding) //if the penis is sounded - to_chat(src, "You cannot feed from [picked_organ.name] when there is a rod inside it.") - return if(picked_organ.producing) //Can it produce its own fluids, such as breasts? fluid_source = picked_organ.reagents else @@ -658,7 +570,7 @@ obj/screen/arousal/proc/feedyourself() "You used [L.name]'s [picked_organ.name] to feed with a total of [total_fluids]u's.") SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) if(picked_organ.can_climax) - L.setArousalLoss(min_arousal) + L.setArousal(min_arousal) else //They either lack organs that can climax, or they didn't pick one. to_chat(src, "You cannot fill anything without choosing exposed genitals.") @@ -672,14 +584,6 @@ obj/screen/arousal/proc/feedyourself() picked_organ = pick_climax_genitals() //Gotta be climaxable, not just masturbation, to fill with fluids. if(picked_organ) //Good, got an organ, time to pick a container - if(picked_organ.name == "penis")//if the select organ is a penis - var/obj/item/organ/genital/penis/P = src.getorganslot("penis") - if(P.condom) //if the penis is condomed - to_chat(src, "You cannot feed yourself when there is a condom over your [picked_organ.name].") - return - if(P.sounding) //if the penis is sounded - to_chat(src, "You cannot feed yourself when there is a rod inside your [picked_organ.name].") - return if(picked_organ.producing) //Can it produce its own fluids, such as breasts? fluid_source = picked_organ.reagents else @@ -697,7 +601,7 @@ obj/screen/arousal/proc/feedyourself() "You used your [picked_organ.name] to feed yourself a total of [total_fluids]u's.") SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) if(picked_organ.can_climax) - setArousalLoss(min_arousal) + setArousal(min_arousal) else //They either lack organs that can climax, or they didn't pick one. to_chat(src, "You cannot fill anything without choosing exposed genitals.") diff --git a/hyperstation/code/modules/mob/mob_helpers.dm b/hyperstation/code/modules/mob/mob_helpers.dm index 50edbc330e..3aadbe3916 100644 --- a/hyperstation/code/modules/mob/mob_helpers.dm +++ b/hyperstation/code/modules/mob/mob_helpers.dm @@ -1,11 +1,14 @@ mob/proc/checkloadappearance() var/mob/living/carbon/human/H = src + if(!istype(H)) + return FALSE + //This will be where the person gets to select their appearance instead of the random character - if (world.time <= (H.time_initialized + 900) && H.mirrorcanloadappearance == TRUE) + if (H.mirrorcanloadappearance == TRUE) SEND_SOUND(H, 'sound/misc/server-ready.ogg') to_chat(H, "This ghost role allows you to select your loaded character's appearance. Make sure you have your ID in your ID slot, if you have one.") - if(alert(H, "Would you like to load your currently loaded character's appearance?", "This can only be done up until 90s after you spawn.", "Yes", "No") == "Yes" && world.time <= (H.time_initialized + 900)) - if(alert(H, "You should only load a character that has not currently died in the round. Do you accept this?", "Warning", "Yes", "No") == "Yes" && world.time <= (H.time_initialized + 900)) + if(alert(H, "Would you like to load your currently loaded character's appearance?", "This can only be done up until 90s after you spawn.", "Yes", "No") == "Yes") + if(alert(H, "You should only load a character that has not currently died in the round. Do you accept this?", "Warning", "Yes", "No") == "Yes") H.client?.prefs?.copy_to(H) if (H.custom_body_size) //Do they have a custom size set? H.resize(H.custom_body_size) @@ -27,3 +30,6 @@ mob/proc/checkloadappearance() else to_chat(H, "You either took too long or chose not to change. Alrighty. Remember, you have 90 seconds from spawn to get to a mirror and still do it if you wish.") return + +/mob/living/carbon/human + var/mirrorcanloadappearance = FALSE //Can the mob load their true appearance with a mirror? diff --git a/hyperstation/code/modules/resize/resizing.dm b/hyperstation/code/modules/resize/resizing.dm index 3d6a7859aa..20c2d834d6 100644 --- a/hyperstation/code/modules/resize/resizing.dm +++ b/hyperstation/code/modules/resize/resizing.dm @@ -214,12 +214,12 @@ /* if(HAS_TRAIT(src, TRAIT_MICROPHILE)) src.adjust_arousal(8) - if (src.getArousalLoss() >= 100 && ishuman(tmob) && tmob.has_dna()) + if (src.getArousal() >= 100 && ishuman(tmob) && tmob.has_dna()) src.mob_climax(forced_climax=TRUE) if(HAS_TRAIT(tmob, TRAIT_MACROPHILE)) tmob.adjust_arousal(10) - if (tmob.getArousalLoss() >= 100 && ishuman(tmob) && tmob.has_dna()) + if (tmob.getArousal() >= 100 && ishuman(tmob) && tmob.has_dna()) tmob.mob_climax(forced_climax=TRUE) return TRUE @@ -244,12 +244,12 @@ /* if(HAS_TRAIT(src, TRAIT_MICROPHILE)) src.adjust_arousal((get_effective_size()/tmob.get_effective_size()*3)) - if (src.getArousalLoss() >= 100 && ishuman(tmob) && tmob.has_dna()) + if (src.getArousal() >= 100 && ishuman(tmob) && tmob.has_dna()) src.mob_climax(forced_climax=TRUE) if(HAS_TRAIT(tmob, TRAIT_MACROPHILE)) tmob.adjust_arousal((get_effective_size()/tmob.get_effective_size()*3)) - if (tmob.getArousalLoss() >= 100 && ishuman(tmob) && tmob.has_dna()) + if (tmob.getArousal() >= 100 && ishuman(tmob) && tmob.has_dna()) tmob.mob_climax(forced_climax=TRUE) commenting out for now */ diff --git a/hyperstation/code/obj/condom.dm b/hyperstation/code/obj/condom.dm index 663f5beac5..cf30e23be2 100644 --- a/hyperstation/code/obj/condom.dm +++ b/hyperstation/code/obj/condom.dm @@ -125,4 +125,4 @@ obj/item/condom/update_icon() C.update_icon() to_chat(src, "The condom bubbles outwards and fills with your cum.") SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "orgasm", /datum/mood_event/orgasm) - setArousalLoss(0) + setArousal(0) diff --git a/hyperstation/code/obj/fleshlight.dm b/hyperstation/code/obj/fleshlight.dm index 413267713e..593477fc6a 100644 --- a/hyperstation/code/obj/fleshlight.dm +++ b/hyperstation/code/obj/fleshlight.dm @@ -11,7 +11,7 @@ item_state = "fleshlight" w_class = WEIGHT_CLASS_SMALL var/sleevecolor = "#ffcbd4" //pink - price = 8 + custom_price = PRICE_CHEAP var/mutable_appearance/sleeve var/inuse = 0 @@ -62,8 +62,8 @@ C.emote("moan") C.do_jitter_animation() - C.adjust_arousal(20) //make the target more aroused. - if (C.getArousalLoss() >= 100 && ishuman(C) && C.has_dna()) + C.adjustArousal(20) //make the target more aroused. + if (C.getArousal() >= 100 && ishuman(C) && C.has_dna()) C.mob_climax(forced_climax=TRUE) //make them cum if they are over the edge. return @@ -88,7 +88,7 @@ var/partnercolor = "#ffcbd4" var/partnerbase = "normal" var/partnerorgan = "portal_vag" - price = 20 + custom_price = PRICE_EXPENSIVE var/mutable_appearance/sleeve var/mutable_appearance/organ var/inuse = 0 @@ -161,26 +161,24 @@ C.emote("moan") if(prob(30)) //30% chance to make your partner moan. M.emote("moan") - C.adjust_arousal(20) - M.adjust_arousal(20) + C.adjustArousal(20) + M.adjustArousal(20) M.do_jitter_animation() //make your partner shake too! - if (M.getArousalLoss() >= 100 && ishuman(M) && prob(5))//Why not have a probability to cum when someone's getting nailed with max arousal?~ + if (M.getArousal() >= 100 && ishuman(M) && prob(5))//Why not have a probability to cum when someone's getting nailed with max arousal?~ if(G.is_exposed()) //Oh yea, if vagina is not exposed, the climax will not cause a spill M.mob_climax_outside(G, spillage = TRUE) else M.mob_climax_outside(G, spillage = FALSE) - if (C.getArousalLoss() >= 100 && ishuman(C) && C.has_dna()) + if (C.getArousal() >= 100 && ishuman(C) && C.has_dna()) var/mob/living/carbon/human/O = C - if( (P.condom == 1) || (P.sounding == 1)) //If coundomed and/or sounded, do not fire impreg chance + //Else, fire impreg chance + if(G.name == "vagina") //no more spontaneous impregnations through the butt! + O.mob_climax_partner(P, M, FALSE, TRUE, FALSE, TRUE) + else O.mob_climax_partner(P, M, FALSE, FALSE, FALSE, TRUE) - else //Else, fire impreg chance - if(G.name == "vagina") //no more spontaneous impregnations through the butt! - O.mob_climax_partner(P, M, FALSE, TRUE, FALSE, TRUE) - else - O.mob_climax_partner(P, M, FALSE, FALSE, FALSE, TRUE) if(option == "Lick") to_chat(M, "You feel a tongue lick you through the portal against your [G.name].") @@ -190,7 +188,6 @@ M.adjust_arousal(5) return - ..() /obj/item/portallight/proc/updatesleeve() //get their looks and vagina colour! @@ -317,7 +314,7 @@ icon = 'hyperstation/icons/obj/fleshlight.dmi' desc = "A small silver box with Silver Love Co embossed." icon_state = "box" - price = 15 + custom_price = PRICE_NORMAL // portal fleshlight box /obj/item/storage/box/portallight/PopulateContents() @@ -372,7 +369,7 @@ // C.do_jitter_animation() // C.adjust_arousal(20) //make the target more aroused. -// if (C.getArousalLoss() >= 100 && ishuman(C) && C.has_dna()) +// if (C.getArousal() >= 100 && ishuman(C) && C.has_dna()) // C.mob_climax(forced_climax=TRUE) //make them cum if they are over the edge. // return diff --git a/hyperstation/code/obj/vibrator.dm b/hyperstation/code/obj/vibrator.dm index 91aeeb47e4..5f6b7d5fd5 100644 --- a/hyperstation/code/obj/vibrator.dm +++ b/hyperstation/code/obj/vibrator.dm @@ -132,13 +132,13 @@ Code: if(2) //med, can make you cum to_chat(U, "You feel intense pleasure surge through your [G.name]") U.do_jitter_animation() - if (U.getArousalLoss() >= 100 && ishuman(U) && U.has_dna()) + if (U.getArousal() >= 100 && ishuman(U) && U.has_dna()) U.mob_climax(forced_climax=TRUE) if(3) //high, makes you stun to_chat(U, "You feel overpowering pleasure surge through your [G.name]") U.Jitter(3) U.Stun(30) - if (U.getArousalLoss() >= 100 && ishuman(U) && U.has_dna()) + if (U.getArousal() >= 100 && ishuman(U) && U.has_dna()) U.mob_climax(forced_climax=TRUE) if(prob(50)) U.emote("moan") diff --git a/modular_citadel/code/modules/mob/living/carbon/human/life.dm b/modular_citadel/code/modules/mob/living/carbon/human/life.dm new file mode 100644 index 0000000000..ff7cc569a7 --- /dev/null +++ b/modular_citadel/code/modules/mob/living/carbon/human/life.dm @@ -0,0 +1,6 @@ +//GS13 Port - arousal +/mob/living/carbon/human/Life() + //citadel code + if(stat != DEAD) + handle_arousal() + . = ..() diff --git a/sound/lewd/champ_fingering.ogg b/sound/lewd/champ_fingering.ogg new file mode 100644 index 0000000000..7e540c9703 Binary files /dev/null and b/sound/lewd/champ_fingering.ogg differ diff --git a/sound/lewd/latex.ogg b/sound/lewd/latex.ogg new file mode 100644 index 0000000000..d9a602244e Binary files /dev/null and b/sound/lewd/latex.ogg differ diff --git a/sound/lewd/slaps.ogg b/sound/lewd/slaps.ogg new file mode 100644 index 0000000000..78cf4ecaae Binary files /dev/null and b/sound/lewd/slaps.ogg differ diff --git a/sound/lewd/vibrate.ogg b/sound/lewd/vibrate.ogg new file mode 100644 index 0000000000..87eb1a4a1d Binary files /dev/null and b/sound/lewd/vibrate.ogg differ diff --git a/tgstation.dme b/tgstation.dme index 217a2b2daa..6472c5205a 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -3968,7 +3968,9 @@ #include "GainStation13\code\mechanics\den abductors\purchaseble_goodies.dm" #include "GainStation13\code\mobs\cakegolem.dm" #include "GainStation13\code\mobs\chocoslime.dm" +#include "GainStation13\code\mobs\emote.dm" #include "GainStation13\code\mobs\races\caloritegolem.dm" +#include "GainStation13\code\modules\arousal\arousal.dm" #include "GainStation13\code\modules\cargo\packs.dm" #include "GainStation13\code\modules\client\border_control.dm" #include "GainStation13\code\modules\client\preferences\preferences.dm" @@ -4053,11 +4055,14 @@ #include "GainStation13\icons\obj\vairous_weapons.dm" #include "GainStation13\icons\obj\structure\beds.dm" #include "GainStation13\icons\obj\structure\flora.dm" +#include "hyperstation\code\datums\mood_events\events.dm" #include "hyperstation\code\game\objects\railings.dm" #include "hyperstation\code\game\objects\structures\bench.dm" #include "hyperstation\code\game\objects\structures\sauna_oven.dm" +#include "hyperstation\code\modules\arousal\arousalhud.dm" #include "hyperstation\code\modules\clothing\sizeaccessories.dm" #include "hyperstation\code\modules\food_and_drinks\recipes\drinks_recipes.dm" +#include "hyperstation\code\modules\mob\mob_helpers.dm" #include "hyperstation\code\modules\mob\living\status_indicators.dm" #include "hyperstation\code\modules\reagents\chemistry\reagents\drink_reagents.dm" #include "hyperstation\code\modules\reagents\chemistry\reagents\food_reagents.dm" @@ -4068,6 +4073,7 @@ #include "hyperstation\code\modules\surgery\organs\augments_arms.dm" #include "hyperstation\code\obj\ashtray.dm" #include "hyperstation\code\obj\decal.dm" +#include "hyperstation\code\obj\fleshlight.dm" #include "hyperstation\code\obj\kinkyclothes.dm" #include "hyperstation\code\obj\sizeitems.dm" #include "hyperstation\code\obj\stargate_clothing.dm" @@ -4148,6 +4154,7 @@ #include "modular_citadel\code\modules\mob\living\carbon\reindex_screams.dm" #include "modular_citadel\code\modules\mob\living\carbon\human\human.dm" #include "modular_citadel\code\modules\mob\living\carbon\human\human_defense.dm" +#include "modular_citadel\code\modules\mob\living\carbon\human\life.dm" #include "modular_citadel\code\modules\projectiles\ammunition\caseless.dm" #include "modular_citadel\code\modules\projectiles\ammunition\ballistic\smg\smg.dm" #include "modular_citadel\code\modules\projectiles\boxes_magazines\ammo_boxes.dm"