diff --git a/_maps/RandomRuins/StationRuins/Box/Engine/engine_singulo.dmm b/_maps/RandomRuins/StationRuins/Box/Engine/engine_singulo.dmm index 76cb8bb9db..402cfc73cf 100644 --- a/_maps/RandomRuins/StationRuins/Box/Engine/engine_singulo.dmm +++ b/_maps/RandomRuins/StationRuins/Box/Engine/engine_singulo.dmm @@ -735,7 +735,7 @@ /obj/machinery/atmospherics/components/unary/outlet_injector{ dir = 1 }, -/turf/open/space/basic, +/turf/open/floor/plating/airless, /area/engine/engineering) "Si" = ( /obj/structure/cable/yellow{ diff --git a/_maps/RandomRuins/StationRuins/Box/Engine/engine_tesla.dmm b/_maps/RandomRuins/StationRuins/Box/Engine/engine_tesla.dmm index 7f55d69b17..af2ba1ffd7 100644 --- a/_maps/RandomRuins/StationRuins/Box/Engine/engine_tesla.dmm +++ b/_maps/RandomRuins/StationRuins/Box/Engine/engine_tesla.dmm @@ -240,7 +240,7 @@ /obj/machinery/atmospherics/components/unary/outlet_injector{ dir = 1 }, -/turf/open/space/basic, +/turf/open/floor/plating/airless, /area/engine/engineering) "nR" = ( /obj/structure/cable{ @@ -905,14 +905,6 @@ }, /turf/open/space/basic, /area/space/nearstation) -"VR" = ( -/obj/structure/lattice/catwalk, -/obj/machinery/camera/emp_proof{ - c_tag = "Tesla Engine Northeast"; - network = list("ss13","engine") - }, -/turf/open/space/basic, -/area/space/nearstation) "Wf" = ( /obj/effect/turf_decal/stripes/line{ dir = 9 @@ -1728,7 +1720,7 @@ dz dz FP FP -VR +FP dz dz Yl diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index 3353d1b15b..7b25d174e5 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -81645,6 +81645,19 @@ /obj/machinery/door/firedoor, /turf/open/floor/plating, /area/crew_quarters/cryopod) +"eQf" = ( +/obj/machinery/computer/shuttle/mining/common{ + dir = 1 + }, +/obj/structure/window/reinforced, +/obj/structure/window/reinforced{ + dir = 8 + }, +/obj/structure/window/reinforced{ + dir = 4 + }, +/turf/open/floor/plating, +/area/hallway/primary/port) "eZe" = ( /obj/structure/cable/yellow{ icon_state = "1-2" @@ -98511,7 +98524,7 @@ bgA biz bkb blZ -bnM +eQf bqf bqf bqf diff --git a/code/__DEFINES/citadel_defines.dm b/code/__DEFINES/citadel_defines.dm index 2b19610040..56d5c63833 100644 --- a/code/__DEFINES/citadel_defines.dm +++ b/code/__DEFINES/citadel_defines.dm @@ -34,6 +34,7 @@ #define CAN_MASTURBATE_WITH (1<<5) #define MASTURBATE_LINKED_ORGAN (1<<6) //used to pass our mission to the linked organ #define CAN_CLIMAX_WITH (1<<7) +#define GENITAL_CAN_AROUSE (1<<8) #define COCK_SIZE_MIN 1 #define COCK_SIZE_MAX 20 diff --git a/code/__DEFINES/maths.dm b/code/__DEFINES/maths.dm index ad93dd2d54..939f6698cb 100644 --- a/code/__DEFINES/maths.dm +++ b/code/__DEFINES/maths.dm @@ -199,4 +199,6 @@ #define LORENTZ_CUMULATIVE_DISTRIBUTION(x, y, s) ( (1/PI)*TORADIANS(arctan((x-y)/s)) + 1/2 ) #define RULE_OF_THREE(a, b, x) ((a*x)/b) -// ) \ No newline at end of file +// ) + +#define MANHATTAN_DISTANCE(a, b) (abs(a.x - b.x) + abs(a.y - b.y)) \ No newline at end of file diff --git a/code/__HELPERS/_cit_helpers.dm b/code/__HELPERS/_cit_helpers.dm index c0acf4c5a5..1bde770045 100644 --- a/code/__HELPERS/_cit_helpers.dm +++ b/code/__HELPERS/_cit_helpers.dm @@ -57,14 +57,11 @@ GLOBAL_LIST_EMPTY(ipc_antennas_list) //Genitals and Arousal Lists GLOBAL_LIST_EMPTY(genitals_list) -GLOBAL_LIST_EMPTY(cock_shapes_list)//global_lists.dm for the list initializations //Now also _DATASTRUCTURES globals.dm -GLOBAL_LIST_EMPTY(cock_shapes_icons) //Associated list for names->icon_states for cockshapes. +GLOBAL_LIST_EMPTY(cock_shapes_list) GLOBAL_LIST_EMPTY(gentlemans_organ_names) GLOBAL_LIST_EMPTY(balls_shapes_list) -GLOBAL_LIST_EMPTY(balls_shapes_icons) GLOBAL_LIST_EMPTY(breasts_size_list) GLOBAL_LIST_EMPTY(breasts_shapes_list) -GLOBAL_LIST_EMPTY(breasts_shapes_icons) GLOBAL_LIST_EMPTY(vagina_shapes_list) GLOBAL_LIST_INIT(cum_into_containers_list, list(/obj/item/reagent_containers/food/snacks/pie)) //Yer fuggin snowflake name list jfc GLOBAL_LIST_INIT(dick_nouns, list("dick","cock","member","shaft")) diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index ff9d1bec4c..7045767f98 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -51,26 +51,15 @@ init_sprite_accessory_subtypes(/datum/sprite_accessory/antenna, GLOB.ipc_antennas_list, roundstart = TRUE) //genitals init_sprite_accessory_subtypes(/datum/sprite_accessory/penis, GLOB.cock_shapes_list) - for(var/K in GLOB.cock_shapes_list) - var/datum/sprite_accessory/penis/value = GLOB.cock_shapes_list[K] - GLOB.cock_shapes_icons[K] = value.icon_state - init_sprite_accessory_subtypes(/datum/sprite_accessory/vagina, GLOB.vagina_shapes_list) init_sprite_accessory_subtypes(/datum/sprite_accessory/breasts, GLOB.breasts_shapes_list) + init_sprite_accessory_subtypes(/datum/sprite_accessory/testicles, GLOB.balls_shapes_list) GLOB.breasts_size_list = list ("a", "b", "c", "d", "e") //We need the list to choose from initialized, but it's no longer a sprite_accessory thing. GLOB.gentlemans_organ_names = list("phallus", "willy", "dick", "prick", "member", "tool", "gentleman's organ", "cock", "wang", "knob", "dong", "joystick", "pecker", "johnson", "weenie", "tadger", "schlong", "thirsty ferret", "baloney pony", "schlanger", "Mutton dagger", "old blind bob","Hanging Johnny", "fishing rod", "Tally whacker", "polly rocket", "One eyed trouser trout", "Ding dong", "ankle spanker", "Pork sword", "engine cranker", "Harry hot dog", "Davy Crockett", "Kidney cracker", "Heat seeking moisture missile", "Giggle stick", "love whistle", "Tube steak", "Uncle Dick", "Purple helmet warrior") - for(var/K in GLOB.breasts_shapes_list) - var/datum/sprite_accessory/breasts/value = GLOB.breasts_shapes_list[K] - GLOB.breasts_shapes_icons[K] = value.icon_state - - init_sprite_accessory_subtypes(/datum/sprite_accessory/testicles, GLOB.balls_shapes_list) - for(var/K in GLOB.balls_shapes_list) - var/datum/sprite_accessory/testicles/value = GLOB.balls_shapes_list[K] - GLOB.balls_shapes_icons[K] = value.icon_state for(var/gpath in subtypesof(/obj/item/organ/genital)) var/obj/item/organ/genital/G = gpath diff --git a/code/__HELPERS/vector.dm b/code/__HELPERS/vector.dm new file mode 100644 index 0000000000..80295bde0e --- /dev/null +++ b/code/__HELPERS/vector.dm @@ -0,0 +1,57 @@ +// Basic geometry things. + +/datum/vector/ + var/x = 0 + var/y = 0 + +/datum/vector/New(var/x, var/y) + src.x = x + src.y = y + +/datum/vector/proc/duplicate() + return new /datum/vector(x, y) + +/datum/vector/proc/euclidian_norm() + return sqrt(x*x + y*y) + +/datum/vector/proc/squared_norm() + return x*x + y*y + +/datum/vector/proc/normalize() + var/norm = euclidian_norm() + x = x/norm + y = y/norm + return src + +/datum/vector/proc/chebyshev_norm() + return max(abs(x), abs(y)) + +/datum/vector/proc/chebyshev_normalize() + var/norm = chebyshev_norm() + x = x/norm + y = y/norm + return src + +/datum/vector/proc/is_integer() + return ISINTEGER(x) && ISINTEGER(y) + +/atom/movable/proc/vector_translate(var/datum/vector/V, var/delay) + var/turf/T = get_turf(src) + var/turf/destination = locate(T.x + V.x, T.y + V.y, z) + var/datum/vector/V_norm = V.duplicate() + V_norm.chebyshev_normalize() + if (!V_norm.is_integer()) + return + var/turf/destination_temp + while (destination_temp != destination) + destination_temp = locate(T.x + V_norm.x, T.y + V_norm.y, z) + forceMove(destination_temp) + T = get_turf(src) + sleep(delay + world.tick_lag) // Shortest possible time to sleep + +/atom/proc/get_translated_turf(var/datum/vector/V) + var/turf/T = get_turf(src) + return locate(T.x + V.x, T.y + V.y, z) + +/proc/atoms2vector(var/atom/A, var/atom/B) + return new /datum/vector((B.x - A.x), (B.y - A.y)) // Vector from A -> B \ No newline at end of file diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 971a9f837b..f48aa632de 100755 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -488,7 +488,7 @@ SUBSYSTEM_DEF(ticker) if("SCORE") SSvote.initiate_vote("map","server",hideresults=TRUE,votesystem = MAJORITY_JUDGEMENT_VOTING) // fallback - SSvote.initiate_vote("map","server",hideresults=TRUE,votesystem = MAJORITY_JUDGEMENT_VOTING) + SSvote.initiate_vote("map","server",hideresults=TRUE) /datum/controller/subsystem/ticker/proc/HasRoundStarted() return current_state >= GAME_STATE_PLAYING diff --git a/code/datums/action.dm b/code/datums/action.dm index 54c719a6d5..04d9c706ed 100644 --- a/code/datums/action.dm +++ b/code/datums/action.dm @@ -820,3 +820,11 @@ target.layer = old_layer target.plane = old_plane current_button.appearance_cache = target.appearance + +/proc/get_action_of_type(mob/M, var/action_type) + if(!M.actions || !ispath(action_type, /datum/action)) + return + for(var/datum/action/A in M.actions) + if(istype(A, action_type)) + return A + return \ No newline at end of file diff --git a/code/game/objects/items/devices/geiger_counter.dm b/code/game/objects/items/devices/geiger_counter.dm index ce0e492393..2af449df24 100644 --- a/code/game/objects/items/devices/geiger_counter.dm +++ b/code/game/objects/items/devices/geiger_counter.dm @@ -38,6 +38,7 @@ /obj/item/geiger_counter/Destroy() STOP_PROCESSING(SSobj, src) + QDEL_NULL(soundloop) return ..() /obj/item/geiger_counter/process() diff --git a/code/modules/antagonists/cult/ritual.dm b/code/modules/antagonists/cult/ritual.dm index ba2a96289d..e92f562db3 100644 --- a/code/modules/antagonists/cult/ritual.dm +++ b/code/modules/antagonists/cult/ritual.dm @@ -116,7 +116,7 @@ This file contains the cult dagger and rune list code if(user.blood_volume) user.apply_damage(initial(rune_to_scribe.scribe_damage), BRUTE, pick(BODY_ZONE_L_ARM, BODY_ZONE_R_ARM)) var/scribe_mod = initial(rune_to_scribe.scribe_delay) - if(istype(get_turf(user), /turf/open/floor/engine/cult)) + if(istype(get_turf(user), /turf/open/floor/engine/cult) && !(ispath(rune_to_scribe, /obj/effect/rune/narsie))) scribe_mod *= 0.5 if(!do_after(user, scribe_mod, target = get_turf(user))) for(var/V in shields) diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm index 539b5ce57a..1e8cce32c0 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm @@ -251,6 +251,7 @@ /obj/machinery/atmospherics/components/unary/cryo_cell/close_machine(mob/living/carbon/user) if((isnull(user) || istype(user)) && state_open && !panel_open) ..(user) + reagent_transfer = 0 return occupant /obj/machinery/atmospherics/components/unary/cryo_cell/container_resist(mob/living/user) diff --git a/code/modules/cargo/bounties/reagent.dm b/code/modules/cargo/bounties/reagent.dm index ca76c80df7..391b4ff464 100644 --- a/code/modules/cargo/bounties/reagent.dm +++ b/code/modules/cargo/bounties/reagent.dm @@ -105,6 +105,7 @@ datum/bounty/reagent/complex_drink/New() /datum/reagent/consumable/ethanol/hearty_punch,\ /datum/reagent/consumable/ethanol/manhattan_proj,\ /datum/reagent/consumable/ethanol/narsour,\ + /datum/reagent/consumable/ethanol/cogchamp,\ /datum/reagent/consumable/ethanol/neurotoxin,\ /datum/reagent/consumable/ethanol/patron,\ /datum/reagent/consumable/ethanol/quadruple_sec,\ diff --git a/code/modules/food_and_drinks/drinks/drinks.dm b/code/modules/food_and_drinks/drinks/drinks.dm index 26ac20cf07..7bd5e66430 100644 --- a/code/modules/food_and_drinks/drinks/drinks.dm +++ b/code/modules/food_and_drinks/drinks/drinks.dm @@ -107,9 +107,9 @@ smash(hit_atom, throwingdatum?.thrower, TRUE) /obj/item/reagent_containers/food/drinks/proc/smash(atom/target, mob/thrower, ranged = FALSE) - if(!isGlass) + if(!isGlass && !istype(src, /obj/item/reagent_containers/food/drinks/bottle)) //I don't like this but I also don't want to rework drink container hierarchy return - if(QDELING(src) || !target) //Invalid loc + if(QDELING(src) || (ranged && !target)) return if(bartender_check(target) && ranged) return @@ -126,12 +126,69 @@ B.transform = M B.pixel_x = rand(-12, 12) B.pixel_y = rand(-12, 12) - if(prob(33)) - new/obj/item/shard(drop_location()) - playsound(src, "shatter", 70, 1) + if(isGlass) + playsound(src, "shatter", 70, 1) + if(prob(33)) + new/obj/item/shard(drop_location()) + else + B.force = 0 + B.throwforce = 0 + B.desc = "A carton with the bottom half burst open. Might give you a papercut." transfer_fingerprints_to(B) qdel(src) +/obj/item/reagent_containers/food/drinks/MouseDrop(atom/over, atom/src_location, atom/over_location, src_control, over_control, params) + var/mob/user = usr + . = ..() + if (!istype(src_location) || !istype(over_location)) + return + if (!user || user.incapacitated() || !user.Adjacent(src)) + return + if (!(locate(/obj/structure/table) in src_location) || !(locate(/obj/structure/table) in over_location)) + return + + //Are we an expert slider? + var/datum/action/innate/D = get_action_of_type(user, /datum/action/innate/drink_fling) + if(!D?.active) + if (!src_location.Adjacent(over_location)) // Regular users can only do short slides. + return + if (prob(10)) + user.visible_message("\The [user] tries to slide \the [src] down the table, but fails miserably.", "You fail to slide \the [src] down the table!") + smash(over_location, user, FALSE) + return + user.visible_message("\The [user] slides \the [src] down the table.", "You slide \the [src] down the table!") + forceMove(over_location) + return + var/distance = MANHATTAN_DISTANCE(over_location, src) + if (distance >= 8 || distance == 0) // More than a full screen to go, or trying to slide to the same tile + return + + // Geometrically checking if we're on a straight line. + var/datum/vector/V = atoms2vector(src, over_location) + var/datum/vector/V_norm = V.duplicate() + V_norm.normalize() + if (!V_norm.is_integer()) + return // Only a cardinal vector (north, south, east, west) can pass this test + + // Checks if there's tables on the path. + var/turf/dest = get_translated_turf(V) + var/turf/temp_turf = src_location + + do + temp_turf = temp_turf.get_translated_turf(V_norm) + if (!locate(/obj/structure/table) in temp_turf) + var/datum/vector/V2 = atoms2vector(src, temp_turf) + vector_translate(V2, 0.1 SECONDS) + user.visible_message("\The [user] slides \the [src] down the table... and straight into the ground!", "You slide \the [src] down the table, and straight into the ground!") + smash(over_location, user, FALSE) + return + while (temp_turf != dest) + + vector_translate(V, 0.1 SECONDS) + user.visible_message("\The [user] expertly slides \the [src] down the table.", "You slide \the [src] down the table. What a pro.") + return + + //////////////////////////////////////////////////////////////////////////////// /// Drinks. END //////////////////////////////////////////////////////////////////////////////// @@ -294,28 +351,6 @@ icon_state = "juicebox" volume = 15 //I figure if you have to craft these it should at least be slightly better than something you can get for free from a watercooler -/obj/item/reagent_containers/food/drinks/sillycup/smallcarton/smash(atom/target, mob/thrower, ranged = FALSE) - if(bartender_check(target) && ranged) - return - var/obj/item/broken_bottle/B = new (loc) - B.icon_state = icon_state - var/icon/I = new('icons/obj/drinks.dmi', src.icon_state) - I.Blend(B.broken_outline, ICON_OVERLAY, rand(5), 1) - I.SwapColor(rgb(255, 0, 220, 255), rgb(0, 0, 0, 0)) - B.icon = I - B.name = "broken [name]" - B.force = 0 - B.throwforce = 0 - B.desc = "A carton with the bottom half burst open. Might give you a papercut." - if(ranged) - var/matrix/M = matrix(B.transform) - M.Turn(rand(-170, 170)) - B.transform = M - B.pixel_x = rand(-12, 12) - B.pixel_y = rand(-12, 12) - transfer_fingerprints_to(B) - qdel(src) - /obj/item/reagent_containers/food/drinks/sillycup/smallcarton/on_reagent_change(changetype) if (reagents.reagent_list.len) switch(reagents.get_master_reagent_id()) diff --git a/code/modules/food_and_drinks/drinks/drinks/bottle.dm b/code/modules/food_and_drinks/drinks/drinks/bottle.dm index 7f2b24ca11..07026e79de 100644 --- a/code/modules/food_and_drinks/drinks/drinks/bottle.dm +++ b/code/modules/food_and_drinks/drinks/drinks/bottle.dm @@ -16,40 +16,6 @@ isGlass = TRUE foodtype = ALCOHOL - -/obj/item/reagent_containers/food/drinks/bottle/smash(mob/living/target, mob/thrower, ranged = FALSE) - //Creates a shattering noise and replaces the bottle with a broken_bottle - if(bartender_check(target) && ranged) - return - var/obj/item/broken_bottle/B = new (loc) - if(!ranged) - thrower.put_in_hands(B) - else - var/matrix/M = matrix(B.transform) - M.Turn(rand(-170, 170)) - B.transform = M - B.pixel_x = rand(-12, 12) - B.pixel_y = rand(-12, 12) - B.icon_state = icon_state - - var/icon/I = new('icons/obj/drinks.dmi', src.icon_state) - I.Blend(B.broken_outline, ICON_OVERLAY, rand(5), 1) - I.SwapColor(rgb(255, 0, 220, 255), rgb(0, 0, 0, 0)) - B.icon = I - - if(isGlass) - if(prob(33)) - new/obj/item/shard(drop_location()) - playsound(src, "shatter", 70, 1) - else - B.force = 0 - B.throwforce = 0 - B.desc = "A carton with the bottom half burst open. Might give you a papercut." - B.name = "broken [name]" - transfer_fingerprints_to(B) - - qdel(src) - /obj/item/reagent_containers/food/drinks/bottle/attack(mob/living/target, mob/living/user) if(!target) @@ -109,7 +75,7 @@ //Keeping this here for now, I'll ask if I should keep it here. /obj/item/broken_bottle name = "broken bottle" - desc = "A bottle with a sharp broken bottom." + desc = "A shattered glass container with sharp edges." icon = 'icons/obj/drinks.dmi' icon_state = "broken_bottle" force = 9 diff --git a/code/modules/food_and_drinks/recipes/drinks_recipes.dm b/code/modules/food_and_drinks/recipes/drinks_recipes.dm index 9df650500a..c94118ddf1 100644 --- a/code/modules/food_and_drinks/recipes/drinks_recipes.dm +++ b/code/modules/food_and_drinks/recipes/drinks_recipes.dm @@ -585,6 +585,14 @@ mix_message = "The mixture develops a sinister glow." mix_sound = 'sound/effects/singlebeat.ogg' +/datum/chemical_reaction/cogchamp + name = "CogChamp" + id = /datum/reagent/consumable/ethanol/cogchamp + results = list(/datum/reagent/consumable/ethanol/cogchamp = 3) + required_reagents = list(/datum/reagent/consumable/ethanol/cognac = 1, /datum/reagent/fuel = 1, /datum/reagent/consumable/ethanol/screwdrivercocktail = 1) + mix_message = "You hear faint sounds of gears turning as it mixes." + mix_sound = 'sound/effects/clockcult_gateway_closing.ogg' + /datum/chemical_reaction/quadruplesec name = "Quadruple Sec" id = /datum/reagent/consumable/ethanol/quadruple_sec diff --git a/code/modules/jobs/job_types/bartender.dm b/code/modules/jobs/job_types/bartender.dm index 0ace449757..cffeceea9c 100644 --- a/code/modules/jobs/job_types/bartender.dm +++ b/code/modules/jobs/job_types/bartender.dm @@ -28,3 +28,7 @@ backpack_contents = list(/obj/item/storage/box/beanbag=1,/obj/item/book/granter/action/drink_fling=1) shoes = /obj/item/clothing/shoes/laceup +/datum/job/bartender/after_spawn(mob/living/H, mob/M, latejoin = FALSE) + . = ..() + var/datum/action/innate/drink_fling/D = new + D.Grant(H) diff --git a/code/modules/mining/mine_items.dm b/code/modules/mining/mine_items.dm index 1ddb3a3189..ac4cee8c42 100644 --- a/code/modules/mining/mine_items.dm +++ b/code/modules/mining/mine_items.dm @@ -93,7 +93,7 @@ req_access = list() circuit = /obj/item/circuitboard/computer/mining_shuttle/common shuttleId = "mining_common" - possible_destinations = "whiteship_home;lavaland_common_away;landing_zone_dock;mining_public" + possible_destinations = "lavaland_common_away;commonmining_home" /**********************Mining car (Crate like thing, not the rail car)**************************/ diff --git a/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm b/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm index 241ec8118e..92bc8e407b 100644 --- a/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm +++ b/code/modules/mob/dead/new_player/sprite_accessories/_sprite_accessories.dm @@ -16,7 +16,7 @@ from doing this unless you absolutely know what you are doing, and have defined a conversion in savefile.dm */ -/proc/init_sprite_accessory_subtypes(prototype, list/L, list/male, list/female,var/roundstart = FALSE)//Roundstart argument builds a specific list for roundstart parts where some parts may be locked +/proc/init_sprite_accessory_subtypes(prototype, list/L, list/male, list/female, roundstart = FALSE, skip_prototype = TRUE)//Roundstart argument builds a specific list for roundstart parts where some parts may be locked if(!istype(L)) L = list() if(!istype(male)) @@ -25,7 +25,7 @@ female = list() for(var/path in typesof(prototype)) - if(path == prototype) + if(path == prototype && skip_prototype) continue if(roundstart) var/datum/sprite_accessory/P = path diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm index 534509523a..1be9a0d72d 100644 --- a/code/modules/mob/living/carbon/life.dm +++ b/code/modules/mob/living/carbon/life.dm @@ -581,6 +581,9 @@ GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put if(cultslurring) cultslurring = max(cultslurring-1, 0) + if(clockcultslurring) + clockcultslurring = max(clockcultslurring-1, 0) + if(silent) silent = max(silent-1, 0) diff --git a/code/modules/mob/living/living_defines.dm b/code/modules/mob/living/living_defines.dm index 84f0004805..031a2e9b94 100644 --- a/code/modules/mob/living/living_defines.dm +++ b/code/modules/mob/living/living_defines.dm @@ -89,6 +89,7 @@ var/stuttering = 0 var/slurring = 0 var/cultslurring = 0 + var/clockcultslurring = 0 var/derpspeech = 0 var/list/implants = null diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index b20511986d..b0f627f82b 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -354,6 +354,9 @@ GLOBAL_LIST_INIT(department_radio_keys, list( if(cultslurring) message = cultslur(message) + + if(clockcultslurring) + message = CLOCK_CULT_SLUR(message) message = capitalize(message) diff --git a/code/modules/mob/living/silicon/pai/pai_defense.dm b/code/modules/mob/living/silicon/pai/pai_defense.dm index 05b2bc77ba..d8e910642d 100644 --- a/code/modules/mob/living/silicon/pai/pai_defense.dm +++ b/code/modules/mob/living/silicon/pai/pai_defense.dm @@ -1,3 +1,4 @@ +#define PAI_EMP_SILENCE_DURATION 3 MINUTES /mob/living/silicon/pai/blob_act(obj/structure/blob/B) return FALSE @@ -8,7 +9,7 @@ return take_holo_damage(50/severity) Knockdown(400/severity) - silent = max((3 MINUTES)/severity, silent) + silent = max(silent, (PAI_EMP_SILENCE_DURATION) / SSmobs.wait / severity) if(holoform) fold_in(force = TRUE) emitter_next_use = world.time + emitter_emp_cd diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index f4133bcf9d..17e0d3d25b 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -147,6 +147,10 @@ . += newletter return sanitize(.) +//Ratvarian Slurring! + +#define CLOCK_CULT_SLUR(phrase) sanitize(text2ratvar(phrase)) + ///Adds stuttering to the message passed in /proc/stutter(phrase) phrase = html_decode(phrase) @@ -420,13 +424,10 @@ It's fairly easy to fix if dealing with single letters but not so much with comp return TRUE /mob/proc/getImplant(type) - if (!istype(src,/mob/living)) - return - var/mob/living/L = src - for (var/I in L.implants) - if (istype(I,type)) - return I - return null + return + +/mob/living/getImplant(type) + return locate(type) in implants /proc/canGhostWrite(var/mob/A, var/obj/target, var/desc="", var/allow_all=FALSE) if(allow_all & TRUE) diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index b15b701272..982afa49c8 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -107,7 +107,7 @@ var/icon_update_needed = FALSE var/obj/machinery/computer/apc_control/remote_control = null var/mob/living/carbon/hijacker - var/hijackerlast = FALSE + var/hijackerlast = TRUE /obj/machinery/power/apc/unlocked locked = FALSE @@ -399,14 +399,14 @@ if (hijacker) var/obj/item/implant/hijack/H = hijacker.getImplant(/obj/item/implant/hijack) hijackerreturn = H && !H.stealthmode - if(last_update_state == update_state && last_update_overlay == update_overlay && hijackerreturn ? hijackerlast : !hijackerlast) + if(last_update_state == update_state && last_update_overlay == update_overlay && hijackerreturn == hijackerlast) return 0 if(last_update_state != update_state) results += 1 - if(last_update_overlay != update_overlay || hijackerreturn ? !hijackerlast : hijackerlast) + if(last_update_overlay != update_overlay || hijackerreturn != hijackerlast) results += 2 - if (hijackerreturn ? !hijackerlast : hijackerlast) - hijackerlast = hijackerreturn ? TRUE : FALSE + if (hijackerreturn != hijackerlast) + hijackerlast = hijackerreturn return results // Used in process so it doesn't update the icon too much diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index e1b62620c7..be43bc48fd 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -150,7 +150,7 @@ if(istype(v, /obj/item/ammo_casing/energy)) //already set ammo_type[v] = isnull(user_can_select)? TRUE : user_can_select else - C = new v //if you put non energycasing/type stuff in here you deserve the runtime + C = new v(src) //if you put non energycasing/type stuff in here you deserve the runtime ammo_type[i] = C ammo_type[C] = isnull(user_can_select)? TRUE : user_can_select set_firemode_index(initial(current_firemode_index)) diff --git a/code/modules/projectiles/projectile/bullets/shotgun.dm b/code/modules/projectiles/projectile/bullets/shotgun.dm index 02ec167b80..c28d85511e 100644 --- a/code/modules/projectiles/projectile/bullets/shotgun.dm +++ b/code/modules/projectiles/projectile/bullets/shotgun.dm @@ -61,7 +61,7 @@ /obj/item/projectile/bullet/pellet/shotgun_buckshot name = "buckshot pellet" - damage = 10 + damage = 12.5 /obj/item/projectile/bullet/pellet/shotgun_rubbershot name = "rubbershot pellet" diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm index 7a3a7eeec2..ccdbbcc915 100644 --- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm @@ -1513,6 +1513,23 @@ All effects don't start immediately, but rather get worse over time; the rate is M.stuttering = min(M.stuttering + 3, 3) ..() +/datum/reagent/consumable/ethanol/cogchamp + name = "CogChamp" + description = "Now you can fill yourself with the power of Ratvar!" + color = rgb(255, 201, 49) + boozepwr = 10 + quality = DRINK_FANTASTIC + taste_description = "a brass taste with a hint of oil" + glass_icon_state = "cogchamp" + glass_name = "CogChamp" + glass_desc = "Not even Ratvar's Four Generals could withstand this! Qevax Jryy!" + value = 8.13 + +/datum/reagent/consumable/ethanol/cogchamp/on_mob_life(mob/living/carbon/M) + M.clockcultslurring = min(M.clockcultslurring + 3, 3) + M.stuttering = min(M.stuttering + 3, 3) + ..() + /datum/reagent/consumable/ethanol/triple_sec name = "Triple Sec" description = "A sweet and vibrant orange liqueur." diff --git a/code/modules/reagents/reagent_containers.dm b/code/modules/reagents/reagent_containers.dm index 23176f8a05..6d5c546e7e 100644 --- a/code/modules/reagents/reagent_containers.dm +++ b/code/modules/reagents/reagent_containers.dm @@ -105,11 +105,11 @@ /obj/item/reagent_containers/proc/bartender_check(atom/target) . = FALSE var/turf/T = get_turf(src) - if(!T || target.CanPass(src, T) || !thrownby || !thrownby.actions) + if(!T || !target.CanPass(src, T) || !thrownby || !thrownby.actions) return - for(var/datum/action/innate/drink_fling/D in thrownby.actions) - if(D.active) - return TRUE + var/datum/action/innate/D = get_action_of_type(thrownby, /datum/action/innate/drink_fling) + if(D?.active) + return TRUE /obj/item/reagent_containers/proc/ForceResetRotation() transform = initial(transform) @@ -131,13 +131,14 @@ if(thrownby) log_combat(thrownby, M, "splashed", R) reagents.reaction(target, TOUCH) - + else if(bartender_check(target) && thrown) visible_message("[src] lands onto the [target.name] without spilling a single drop.") transform = initial(transform) addtimer(CALLBACK(src, .proc/ForceResetRotation), 1) return + else if(isturf(target) && reagents.reagent_list.len && thrownby) log_combat(thrownby, target, "splashed (thrown) [english_list(reagents.reagent_list)]", "in [AREACOORD(target)]") diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index eac8edcbc8..fd4282b1b0 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -423,9 +423,9 @@ else unload_hypo(vial,user) -/obj/item/hypospray/mkii/AltClick(mob/living/user) +/obj/item/hypospray/mkii/CtrlClick(mob/living/user) . = ..() - if(user.canUseTopic(src, FALSE)) + if(user.canUseTopic(src, FALSE) && user.get_active_held_item(src)) switch(mode) if(HYPO_SPRAY) mode = HYPO_INJECT @@ -437,7 +437,7 @@ /obj/item/hypospray/mkii/examine(mob/user) . = ..() - . += "Alt-Click it to toggle its mode from spraying to injecting and vice versa." + . += "Ctrl-Click it to toggle its mode from spraying to injecting and vice versa." #undef HYPO_SPRAY #undef HYPO_INJECT diff --git a/html/changelogs/AutoChangeLog-pr-10861.yml b/html/changelogs/AutoChangeLog-pr-10861.yml new file mode 100644 index 0000000000..5071cc30f9 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-10861.yml @@ -0,0 +1,4 @@ +author: "ancientpower" +delete-after: True +changes: + - rscadd: "Ported drink sliding from /vg/station." diff --git a/html/changelogs/AutoChangeLog-pr-10943.yml b/html/changelogs/AutoChangeLog-pr-10943.yml new file mode 100644 index 0000000000..f45d8b1d39 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-10943.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - bugfix: "Fixed a little inconvenience with the character setup preview dummy having extra unwarranted bits." diff --git a/html/changelogs/AutoChangeLog-pr-10987.yml b/html/changelogs/AutoChangeLog-pr-10987.yml new file mode 100644 index 0000000000..abea439a86 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-10987.yml @@ -0,0 +1,4 @@ +author: "Ghommie" +delete-after: True +changes: + - imageadd: "Fixed dozen missing privates sprites." diff --git a/html/changelogs/AutoChangeLog-pr-10992.yml b/html/changelogs/AutoChangeLog-pr-10992.yml new file mode 100644 index 0000000000..1d6d10396b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-10992.yml @@ -0,0 +1,4 @@ +author: "Hatterhat" +delete-after: True +changes: + - balance: "Buckshot individual pellet damage up from 10 to 12.5. Still firing 6 pellets." diff --git a/html/changelogs/AutoChangeLog-pr-10994.yml b/html/changelogs/AutoChangeLog-pr-10994.yml new file mode 100644 index 0000000000..c27a1afc00 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-10994.yml @@ -0,0 +1,4 @@ +author: "DeltaFire15" +delete-after: True +changes: + - balance: "Nar'Sie runes no longer benefit from runed floors." diff --git a/html/changelogs/AutoChangeLog-pr-11003.yml b/html/changelogs/AutoChangeLog-pr-11003.yml new file mode 100644 index 0000000000..4c551c4d09 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11003.yml @@ -0,0 +1,4 @@ +author: "kevinz000" +delete-after: True +changes: + - bugfix: "Energy weapons now once again have their lens in contents." diff --git a/html/changelogs/AutoChangeLog-pr-11005.yml b/html/changelogs/AutoChangeLog-pr-11005.yml new file mode 100644 index 0000000000..d0576c7ba8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11005.yml @@ -0,0 +1,4 @@ +author: "Arturlang" +delete-after: True +changes: + - tweak: "Hyposprays now switch modes on CTRL click, instead of alt, as it was already reserved for dispension amount." diff --git a/html/changelogs/AutoChangeLog-pr-11012.yml b/html/changelogs/AutoChangeLog-pr-11012.yml new file mode 100644 index 0000000000..1d233f0692 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11012.yml @@ -0,0 +1,4 @@ +author: "keronshb" +delete-after: True +changes: + - rscadd: "Adds the CogChamp drink and Sprite" diff --git a/html/changelogs/AutoChangeLog-pr-11018.yml b/html/changelogs/AutoChangeLog-pr-11018.yml new file mode 100644 index 0000000000..2795317861 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11018.yml @@ -0,0 +1,4 @@ +author: "kevinz000" +delete-after: True +changes: + - bugfix: "pais are no longer muted for literally a whole hour on emp." diff --git a/html/changelogs/AutoChangeLog-pr-11020.yml b/html/changelogs/AutoChangeLog-pr-11020.yml new file mode 100644 index 0000000000..52677b98e9 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11020.yml @@ -0,0 +1,4 @@ +author: "Zellular" +delete-after: True +changes: + - imageadd: "Movement state for pupdozer and its decals" diff --git a/html/changelogs/AutoChangeLog-pr-11029.yml b/html/changelogs/AutoChangeLog-pr-11029.yml new file mode 100644 index 0000000000..17f34bbfa6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11029.yml @@ -0,0 +1,4 @@ +author: "Putnam3145" +delete-after: True +changes: + - tweak: "default should be... default" diff --git a/html/changelogs/AutoChangeLog-pr-11032.yml b/html/changelogs/AutoChangeLog-pr-11032.yml new file mode 100644 index 0000000000..6d026e444a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11032.yml @@ -0,0 +1,4 @@ +author: "kevinz000" +delete-after: True +changes: + - bugfix: "Cryo now actually transfers reagents at tier 4 on enter rather than every 80 machine fire()-process()s regardless of if it was \"reset\" by open/close." diff --git a/html/changelogs/AutoChangeLog-pr-11043.yml b/html/changelogs/AutoChangeLog-pr-11043.yml new file mode 100644 index 0000000000..28217af630 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-11043.yml @@ -0,0 +1,4 @@ +author: "Seris02" +delete-after: True +changes: + - bugfix: "apc icons" diff --git a/modular_citadel/code/modules/arousal/arousal.dm b/modular_citadel/code/modules/arousal/arousal.dm index 3a586d061d..5c7d5a39e9 100644 --- a/modular_citadel/code/modules/arousal/arousal.dm +++ b/modular_citadel/code/modules/arousal/arousal.dm @@ -10,12 +10,6 @@ var/hidden_undershirt = FALSE var/hidden_socks = FALSE -//Species vars -/datum/species - var/list/cum_fluids = list("semen") - var/list/milk_fluids = list("milk") - var/list/femcum_fluids = list("femcum") - //Mob procs /mob/living/carbon/human/proc/underwear_toggle() set name = "Toggle undergarments" @@ -46,20 +40,12 @@ var/list/obj/item/organ/genital/genit_list = list() if(!client?.prefs.arousable || (aphro && (client?.prefs.cit_toggles & NO_APHRO)) || (maso && !HAS_TRAIT(src, TRAIT_MASO))) return // no adjusting made here - if(strength>0) - for(var/obj/item/organ/genital/G in internal_organs) - if(!G.aroused_state && prob(strength*G.sensitivity)) - G.set_aroused_state(TRUE) - G.update_appearance() - if(G.aroused_state) - genit_list += G - else - for(var/obj/item/organ/genital/G in internal_organs) - if(G.aroused_state && prob(strength*G.sensitivity)) - G.set_aroused_state(FALSE) - G.update_appearance() - if(G.aroused_state) - genit_list += G + for(var/obj/item/organ/genital/G in internal_organs) + if(G.genital_flags & GENITAL_CAN_AROUSE && !G.aroused_state && prob(strength*G.sensitivity)) + G.set_aroused_state(strength > 0) + G.update_appearance() + if(G.aroused_state) + genit_list += G return genit_list /obj/item/organ/genital/proc/climaxable(mob/living/carbon/human/H, silent = FALSE) //returns the fluid source (ergo reagents holder) if found. diff --git a/modular_citadel/code/modules/arousal/genitals.dm b/modular_citadel/code/modules/arousal/genitals.dm index ca01ef46cb..b7f178bca5 100644 --- a/modular_citadel/code/modules/arousal/genitals.dm +++ b/modular_citadel/code/modules/arousal/genitals.dm @@ -32,23 +32,20 @@ else update() -/obj/item/organ/genital/Destroy() - if(linked_organ) - update_link(TRUE)//this should remove any other links it has - return ..() - /obj/item/organ/genital/proc/set_aroused_state(new_state) + if(!(genital_flags & GENITAL_CAN_AROUSE)) + return FALSE if(!((HAS_TRAIT(owner,TRAIT_PERMABONER) && !new_state) || HAS_TRAIT(owner,TRAIT_NEVERBONER) && new_state)) aroused_state = new_state return aroused_state -/obj/item/organ/genital/proc/update(removing = FALSE) +/obj/item/organ/genital/proc/update() if(QDELETED(src)) return update_size() update_appearance() - if(linked_organ_slot || (linked_organ && removing)) - update_link(removing) + if(linked_organ_slot || (linked_organ && !owner)) + update_link() //exposure and through-clothing code /mob/living/carbon @@ -113,17 +110,7 @@ set desc = "Allows you to toggle which genitals are showing signs of arousal." var/list/genital_list = list() for(var/obj/item/organ/genital/G in internal_organs) - 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) + if(G.genital_flags & GENITAL_CAN_AROUSE) genital_list += G if(!genital_list.len) //There's nothing that can show arousal return @@ -174,19 +161,18 @@ return TRUE return FALSE -/obj/item/organ/genital/proc/update_link(removing = FALSE) - if(!removing && owner) +/obj/item/organ/genital/proc/update_link() + if(owner) if(linked_organ) - return + return FALSE linked_organ = owner.getorganslot(linked_organ_slot) if(linked_organ) linked_organ.linked_organ = src linked_organ.upon_link() upon_link() return TRUE - else - if(linked_organ) - linked_organ.linked_organ = null + if(linked_organ) + linked_organ.linked_organ = null linked_organ = null return FALSE @@ -200,10 +186,13 @@ update() RegisterSignal(owner, COMSIG_MOB_DEATH, .proc/update_appearance) -/obj/item/organ/genital/Remove(mob/living/carbon/M, special = FALSE, drop_if_replaced = TRUE) - update(TRUE) - if(!QDELETED(owner)) - UnregisterSignal(owner, COMSIG_MOB_DEATH) +/obj/item/organ/genital/Remove(special = FALSE) + . = ..() + var/mob/living/carbon/human/H = . + update() + if(!QDELETED(H)) + UnregisterSignal(H, COMSIG_MOB_DEATH) + H.update_genitals() //proc to give a player their genitals and stuff when they log in /mob/living/carbon/human/proc/give_genitals(clean = FALSE)//clean will remove all pre-existing genitals. proc will then give them any genitals that are enabled in their DNA @@ -238,12 +227,6 @@ /obj/item/organ/genital/proc/get_features(mob/living/carbon/human/H) return -/datum/species/proc/genitals_layertext(layer) - switch(layer) - if(GENITALS_BEHIND_LAYER) - return "BEHIND" - if(GENITALS_FRONT_LAYER) - return "FRONT" //procs to handle sprite overlays being applied to humans @@ -262,8 +245,90 @@ update_genitals() /mob/living/carbon/human/proc/update_genitals() - if(!QDELETED(src)) - dna.species.handle_genitals(src) + if(QDELETED(src)) + return + var/static/list/relevant_layers = list("[GENITALS_BEHIND_LAYER]" = "BEHIND", "[GENITALS_FRONT_LAYER]" = "FRONT") + var/static/list/layers_num + if(!layers_num) + for(var/L in relevant_layers) + LAZYSET(layers_num, L, text2num(L)) + for(var/L in relevant_layers) //Less hardcode + remove_overlay(layers_num[L]) + remove_overlay(GENITALS_EXPOSED_LAYER) + if(!LAZYLEN(internal_organs) || ((NOGENITALS in dna.species.species_traits) && !genital_override) || HAS_TRAIT(src, TRAIT_HUSK)) + return + + //start scanning for genitals + + var/list/gen_index[GENITAL_LAYER_INDEX_LENGTH] + var/list/genitals_to_add + var/list/fully_exposed + for(var/obj/item/organ/genital/G in internal_organs) + if(G.is_exposed()) //Checks appropriate clothing slot and if it's through_clothes + LAZYADD(gen_index[G.layer_index], G) + for(var/L in gen_index) + if(L) //skip nulls + LAZYADD(genitals_to_add, L) + if(!genitals_to_add) + return + //Now we added all genitals that aren't internal and should be rendered + //start applying overlays + for(var/layer in relevant_layers) + var/list/standing = list() + var/layertext = relevant_layers[layer] + for(var/A in genitals_to_add) + var/obj/item/organ/genital/G = A + var/datum/sprite_accessory/S + var/size = G.size + 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 || S.icon_state == "none") + continue + var/aroused_state = G.aroused_state && S.alt_aroused + + var/mutable_appearance/genital_overlay = mutable_appearance(S.icon, layer = -layer) + if(S.center) + genital_overlay = center_image(genital_overlay, S.dimension_x, S.dimension_y) + + if(dna.species.use_skintones && dna.features["genitals_use_skintone"]) + genital_overlay.color = "#[skintone2hex(skin_tone)]" + else + switch(S.color_src) + if("cock_color") + genital_overlay.color = "#[dna.features["cock_color"]]" + if("balls_color") + genital_overlay.color = "#[dna.features["balls_color"]]" + if("breasts_color") + genital_overlay.color = "#[dna.features["breasts_color"]]" + if("vag_color") + genital_overlay.color = "#[dna.features["vag_color"]]" + + genital_overlay.icon_state = "[G.slot]_[S.icon_state]_[size][dna.species.use_skintones ? "_s" : ""]_[aroused_state]_[layertext]" + + if(layer == GENITALS_FRONT_LAYER && CHECK_BITFIELD(G.genital_flags, GENITAL_THROUGH_CLOTHES)) + genital_overlay.layer = -GENITALS_EXPOSED_LAYER + LAZYADD(fully_exposed, genital_overlay) // to be added to a layer with higher priority than clothes, hence the name of the bitflag. + else + standing += genital_overlay + + if(LAZYLEN(standing)) + overlays_standing[layers_num[layer]] = standing + + if(LAZYLEN(fully_exposed)) + overlays_standing[GENITALS_EXPOSED_LAYER] = fully_exposed + apply_overlay(GENITALS_EXPOSED_LAYER) + + for(var/L in relevant_layers) + apply_overlay(layers_num[L]) + //Checks to see if organs are new on the mob, and changes their colours so that they don't get crazy colours. /mob/living/carbon/human/proc/emergent_genital_call() @@ -292,86 +357,3 @@ else if (willyCheck == FALSE) dna.features["cock_color"] = dna.features["breasts_color"] return TRUE - -/datum/species/proc/handle_genitals(mob/living/carbon/human/H)//more like handle sadness - if(!H)//no args - CRASH("H = null") - if(!LAZYLEN(H.internal_organs) || ((NOGENITALS in species_traits) && !H.genital_override) || HAS_TRAIT(H, TRAIT_HUSK)) - return - var/list/relevant_layers = list(GENITALS_BEHIND_LAYER, GENITALS_FRONT_LAYER) - - for(var/L in relevant_layers) //Less hardcode - H.remove_overlay(L) - H.remove_overlay(GENITALS_EXPOSED_LAYER) - //start scanning for genitals - - var/list/gen_index[GENITAL_LAYER_INDEX_LENGTH] - var/list/genitals_to_add - var/list/fully_exposed - for(var/obj/item/organ/genital/G in H.internal_organs) - if(G.is_exposed()) //Checks appropriate clothing slot and if it's through_clothes - LAZYADD(gen_index[G.layer_index], G) - for(var/L in gen_index) - if(L) //skip nulls - LAZYADD(genitals_to_add, L) - if(!genitals_to_add) - return - //Now we added all genitals that aren't internal and should be rendered - //start applying overlays - for(var/layer in relevant_layers) - var/list/standing = list() - var/layertext = genitals_layertext(layer) - for(var/A in genitals_to_add) - var/obj/item/organ/genital/G = A - var/datum/sprite_accessory/S - var/size = G.size - var/aroused_state = G.aroused_state - 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 || S.icon_state == "none") - continue - - var/mutable_appearance/genital_overlay = mutable_appearance(S.icon, layer = -layer) - genital_overlay.icon_state = "[G.slot]_[S.icon_state]_[size]_[aroused_state]_[layertext]" - - if(S.center) - genital_overlay = center_image(genital_overlay, S.dimension_x, S.dimension_y) - - if(use_skintones && H.dna.features["genitals_use_skintone"]) - genital_overlay.color = "#[skintone2hex(H.skin_tone)]" - else - switch(S.color_src) - if("cock_color") - genital_overlay.color = "#[H.dna.features["cock_color"]]" - if("balls_color") - genital_overlay.color = "#[H.dna.features["balls_color"]]" - if("breasts_color") - genital_overlay.color = "#[H.dna.features["breasts_color"]]" - if("vag_color") - genital_overlay.color = "#[H.dna.features["vag_color"]]" - - genital_overlay.icon_state = "[G.slot]_[S.icon_state]_[size]-s_[aroused_state]_[layertext]" - - if(layer == GENITALS_FRONT_LAYER && CHECK_BITFIELD(G.genital_flags, GENITAL_THROUGH_CLOTHES)) - genital_overlay.layer = -GENITALS_EXPOSED_LAYER - LAZYADD(fully_exposed, genital_overlay) // to be added to a layer with higher priority than clothes, hence the name of the bitflag. - else - standing += genital_overlay - - if(LAZYLEN(standing)) - H.overlays_standing[layer] = standing - - if(LAZYLEN(fully_exposed)) - H.overlays_standing[GENITALS_EXPOSED_LAYER] = fully_exposed - H.apply_overlay(GENITALS_EXPOSED_LAYER) - - for(var/L in relevant_layers) - H.apply_overlay(L) diff --git a/modular_citadel/code/modules/arousal/genitals_sprite_accessories.dm b/modular_citadel/code/modules/arousal/genitals_sprite_accessories.dm index 0c1763b8e2..594fc83e46 100644 --- a/modular_citadel/code/modules/arousal/genitals_sprite_accessories.dm +++ b/modular_citadel/code/modules/arousal/genitals_sprite_accessories.dm @@ -85,36 +85,36 @@ //Vaginas /datum/sprite_accessory/vagina icon = 'modular_citadel/icons/obj/genitals/vagina_onmob.dmi' - icon_state = null name = "vagina" color_src = "vag_color" + alt_aroused = TRUE /datum/sprite_accessory/vagina/human icon_state = "human" name = "Human" - alt_aroused = TRUE /datum/sprite_accessory/vagina/tentacles icon_state = "tentacle" name = "Tentacle" - alt_aroused = TRUE /datum/sprite_accessory/vagina/dentata icon_state = "dentata" name = "Dentata" - alt_aroused = TRUE /datum/sprite_accessory/vagina/hairy icon_state = "hairy" name = "Hairy" + alt_aroused = FALSE /datum/sprite_accessory/vagina/spade icon_state = "spade" name = "Spade" + alt_aroused = FALSE /datum/sprite_accessory/vagina/furred icon_state = "furred" name = "Furred" + alt_aroused = FALSE /datum/sprite_accessory/vagina/gaping icon_state = "gaping" @@ -125,7 +125,6 @@ icon = 'modular_citadel/icons/obj/genitals/breasts_onmob.dmi' name = "breasts" color_src = "breasts_color" - alt_aroused = TRUE /datum/sprite_accessory/breasts/pair icon_state = "pair" diff --git a/modular_citadel/code/modules/arousal/organs/breasts.dm b/modular_citadel/code/modules/arousal/organs/breasts.dm index 1537d5cebe..dc7923e448 100644 --- a/modular_citadel/code/modules/arousal/organs/breasts.dm +++ b/modular_citadel/code/modules/arousal/organs/breasts.dm @@ -1,3 +1,6 @@ +#define BREASTS_ICON_MIN_SIZE 1 +#define BREASTS_ICON_MAX_SIZE 6 + /obj/item/organ/genital/breasts name = "breasts" desc = "Female milk producing organs." @@ -9,7 +12,7 @@ fluid_id = /datum/reagent/consumable/milk fluid_rate = MILK_RATE shape = "pair" - genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH|GENITAL_FUID_PRODUCTION + genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH|GENITAL_FUID_PRODUCTION|GENITAL_CAN_AROUSE masturbation_verb = "massage" arousal_verb = "Your breasts start feeling sensitive" unarousal_verb = "Your breasts no longer feel sensitive" @@ -49,21 +52,21 @@ var/datum/reagent/R = GLOB.chemical_reagents_list[fluid_id] if(R) desc += " They're leaking [lowertext(R.name)]." - var/string + var/datum/sprite_accessory/S = GLOB.breasts_shapes_list[shape] + var/icon_shape = S ? S.icon_state : "pair" + var/icon_size = CLAMP(breast_values[size], BREASTS_ICON_MIN_SIZE, BREASTS_ICON_MAX_SIZE) + icon_state = "breasts_[icon_shape]_[breast_values[icon_size]]" if(owner) if(owner.dna.species.use_skintones && owner.dna.features["genitals_use_skintone"]) if(ishuman(owner)) // Check before recasting type, although someone fucked up if you're not human AND have use_skintones somehow... var/mob/living/carbon/human/H = owner // only human mobs have skin_tone, which we need. color = "#[skintone2hex(H.skin_tone)]" - string = "breasts_[GLOB.breasts_shapes_icons[shape]]_[size]-s" + icon_state += "_s" else color = "#[owner.dna.features["breasts_color"]]" - string = "breasts_[GLOB.breasts_shapes_icons[shape]]_[size]" if(ishuman(owner)) var/mob/living/carbon/human/H = owner - icon_state = sanitize_text(string) H.update_genitals() - icon_state = sanitize_text(string) //Allows breasts to grow and change size, with sprite changes too. //maximum wah @@ -130,3 +133,6 @@ cached_size = size size = breast_values[size] prev_size = cached_size + +#undef BREASTS_ICON_MIN_SIZE +#undef BREASTS_ICON_MAX_SIZE \ No newline at end of file diff --git a/modular_citadel/code/modules/arousal/organs/penis.dm b/modular_citadel/code/modules/arousal/organs/penis.dm index c6d3c764ac..38f463a97c 100644 --- a/modular_citadel/code/modules/arousal/organs/penis.dm +++ b/modular_citadel/code/modules/arousal/organs/penis.dm @@ -8,13 +8,13 @@ masturbation_verb = "stroke" arousal_verb = "You pop a boner" unarousal_verb = "Your boner goes down" - genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH + genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH|GENITAL_CAN_AROUSE linked_organ_slot = ORGAN_SLOT_TESTICLES fluid_transfer_factor = 0.5 size = 2 //arbitrary value derived from length and girth for sprites. layer_index = PENIS_LAYER_INDEX var/length = 6 //inches - var/prev_length = 6 //really should be renamed to prev_length + var/prev_length = 6 var/girth = 4.38 var/girth_ratio = COCK_GIRTH_RATIO_DEF //0.73; check citadel_defines.dm @@ -73,22 +73,21 @@ /obj/item/organ/genital/penis/update_appearance() . = ..() - var/string + var/datum/sprite_accessory/S = GLOB.cock_shapes_list[shape] + var/icon_shape = S ? S.icon_state : "human" + icon_state = "penis_[icon_shape]_[size]" var/lowershape = lowertext(shape) desc = "You see [aroused_state ? "an erect" : "a flaccid"] [lowershape] [name]. You estimate it's about [round(length, 0.25)] inch[round(length, 0.25) != 1 ? "es" : ""] long and [round(girth, 0.25)] inch[round(girth, 0.25) != 1 ? "es" : ""] in girth." - if(owner) if(owner.dna.species.use_skintones && owner.dna.features["genitals_use_skintone"]) if(ishuman(owner)) // Check before recasting type, although someone fucked up if you're not human AND have use_skintones somehow... var/mob/living/carbon/human/H = owner // only human mobs have skin_tone, which we need. color = "#[skintone2hex(H.skin_tone)]" - string = "penis_[GLOB.cock_shapes_icons[shape]]_[size]-s" + icon_state += "_s" else color = "#[owner.dna.features["cock_color"]]" - string = "penis_[GLOB.cock_shapes_icons[shape]]_[size]" if(ishuman(owner)) var/mob/living/carbon/human/H = owner - icon_state = sanitize_text(string) H.update_genitals() /obj/item/organ/genital/penis/get_features(mob/living/carbon/human/H) diff --git a/modular_citadel/code/modules/arousal/organs/testicles.dm b/modular_citadel/code/modules/arousal/organs/testicles.dm index 9573020417..eb6c1536cb 100644 --- a/modular_citadel/code/modules/arousal/organs/testicles.dm +++ b/modular_citadel/code/modules/arousal/organs/testicles.dm @@ -43,19 +43,19 @@ /obj/item/organ/genital/testicles/update_appearance() . = ..() desc = "You see an [size_name] pair of testicles." + var/datum/sprite_accessory/S = GLOB.balls_shapes_list[shape] + var/icon_shape = S ? S.icon_state : "single" + icon_state = "testicles_[icon_shape]_[size]" if(owner) - var/string if(owner.dna.species.use_skintones && owner.dna.features["genitals_use_skintone"]) if(ishuman(owner)) // Check before recasting type, although someone fucked up if you're not human AND have use_skintones somehow... var/mob/living/carbon/human/H = owner // only human mobs have skin_tone, which we need. color = "#[skintone2hex(H.skin_tone)]" - string = "testicles_[GLOB.balls_shapes_icons[shape]]_[size]-s" + icon_state += "_s" else color = "#[owner.dna.features["balls_color"]]" - string = "testicles_[GLOB.balls_shapes_icons[shape]]_[size]" if(ishuman(owner)) var/mob/living/carbon/human/H = owner - icon_state = sanitize_text(string) H.update_genitals() /obj/item/organ/genital/testicles/get_features(mob/living/carbon/human/H) diff --git a/modular_citadel/code/modules/arousal/organs/vagina.dm b/modular_citadel/code/modules/arousal/organs/vagina.dm index 3f1bcc5f9b..311afe75b0 100644 --- a/modular_citadel/code/modules/arousal/organs/vagina.dm +++ b/modular_citadel/code/modules/arousal/organs/vagina.dm @@ -6,7 +6,7 @@ zone = BODY_ZONE_PRECISE_GROIN slot = "vagina" size = 1 //There is only 1 size right now - genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH + genital_flags = CAN_MASTURBATE_WITH|CAN_CLIMAX_WITH|GENITAL_CAN_AROUSE masturbation_verb = "finger" arousal_verb = "You feel wetness on your crotch" unarousal_verb = "You no longer feel wet" @@ -22,7 +22,7 @@ /obj/item/organ/genital/vagina/update_appearance() . = ..() - var/string //Keeping this code here, so making multiple sprites for the different kinds is easier. + icon_state = "vagina" var/lowershape = lowertext(shape) var/details @@ -55,13 +55,11 @@ if(ishuman(owner)) // Check before recasting type, although someone fucked up if you're not human AND have use_skintones somehow... var/mob/living/carbon/human/H = owner // only human mobs have skin_tone, which we need. color = "#[skintone2hex(H.skin_tone)]" - string = "vagina-s" + icon_state += "_s" else color = "#[owner.dna.features["vag_color"]]" - string = "vagina" if(ishuman(owner)) var/mob/living/carbon/human/H = owner - icon_state = sanitize_text(string) H.update_genitals() /obj/item/organ/genital/vagina/get_features(mob/living/carbon/human/H) diff --git a/modular_citadel/icons/mob/widerobot.dmi b/modular_citadel/icons/mob/widerobot.dmi index a77a109eb9..3f48c3902c 100644 Binary files a/modular_citadel/icons/mob/widerobot.dmi and b/modular_citadel/icons/mob/widerobot.dmi differ diff --git a/modular_citadel/icons/obj/genitals/breasts.dmi b/modular_citadel/icons/obj/genitals/breasts.dmi index d70207ee69..24656062d2 100644 Binary files a/modular_citadel/icons/obj/genitals/breasts.dmi and b/modular_citadel/icons/obj/genitals/breasts.dmi differ diff --git a/modular_citadel/icons/obj/genitals/breasts_onmob.dmi b/modular_citadel/icons/obj/genitals/breasts_onmob.dmi index 371041b6f4..578086c4c3 100644 Binary files a/modular_citadel/icons/obj/genitals/breasts_onmob.dmi and b/modular_citadel/icons/obj/genitals/breasts_onmob.dmi differ diff --git a/modular_citadel/icons/obj/genitals/penis.dmi b/modular_citadel/icons/obj/genitals/penis.dmi index 517758b248..c3fd184a7c 100644 Binary files a/modular_citadel/icons/obj/genitals/penis.dmi and b/modular_citadel/icons/obj/genitals/penis.dmi differ diff --git a/modular_citadel/icons/obj/genitals/penis_onmob.dmi b/modular_citadel/icons/obj/genitals/penis_onmob.dmi index 4f84c52360..4a92bffa2a 100644 Binary files a/modular_citadel/icons/obj/genitals/penis_onmob.dmi and b/modular_citadel/icons/obj/genitals/penis_onmob.dmi differ diff --git a/modular_citadel/icons/obj/genitals/taur_penis_onmob.dmi b/modular_citadel/icons/obj/genitals/taur_penis_onmob.dmi index ae2339e2e0..e8efbec216 100644 Binary files a/modular_citadel/icons/obj/genitals/taur_penis_onmob.dmi and b/modular_citadel/icons/obj/genitals/taur_penis_onmob.dmi differ diff --git a/modular_citadel/icons/obj/genitals/testicles.dmi b/modular_citadel/icons/obj/genitals/testicles.dmi index 3d7a5f4f48..386eab0956 100644 Binary files a/modular_citadel/icons/obj/genitals/testicles.dmi and b/modular_citadel/icons/obj/genitals/testicles.dmi differ diff --git a/modular_citadel/icons/obj/genitals/vagina.dmi b/modular_citadel/icons/obj/genitals/vagina.dmi index 39bdd48e89..1bbe62ba0e 100644 Binary files a/modular_citadel/icons/obj/genitals/vagina.dmi and b/modular_citadel/icons/obj/genitals/vagina.dmi differ diff --git a/modular_citadel/icons/obj/genitals/vagina_onmob.dmi b/modular_citadel/icons/obj/genitals/vagina_onmob.dmi index ab71b22e3b..6c34ffadfa 100644 Binary files a/modular_citadel/icons/obj/genitals/vagina_onmob.dmi and b/modular_citadel/icons/obj/genitals/vagina_onmob.dmi differ diff --git a/tgstation.dme b/tgstation.dme index a747c823db..927027d448 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -152,6 +152,7 @@ #include "code\__HELPERS\type2type_vr.dm" #include "code\__HELPERS\typelists.dm" #include "code\__HELPERS\unsorted.dm" +#include "code\__HELPERS\vector.dm" #include "code\__HELPERS\view.dm" #include "code\__HELPERS\sorts\__main.dm" #include "code\__HELPERS\sorts\InsertSort.dm"