mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-10 17:52:36 +00:00
Merge branch 'master' into upstream-25-06d
This commit is contained in:
@@ -16,3 +16,17 @@
|
||||
#define COMSIG_OOC_ESCAPE "ooc_escape"
|
||||
/// From [/datum/outfit]: (datum/outfit)
|
||||
#define COMSIG_OUTFIT_EQUIP "outfit_equip"
|
||||
/// From /mob/proc/equip_to_slot_if_possible()
|
||||
#define COMSIG_MOB_POST_EQUIP "mob_post_equip"
|
||||
/// From /mob/living/carbon/human/verb/toggle_undies()
|
||||
#define COMSIG_HUMAN_TOGGLE_UNDERWEAR "human_toggle_undies"
|
||||
/// From /obj/item/restraints/handcuffs/proc/apply_cuffs()
|
||||
#define COMSIG_MOB_HANDCUFFED "mob_handcuffed"
|
||||
/// From /datum/bodypart_overlay/simple/emote/Destroy() - Calls when an emote that applies a temporary visual effect expires
|
||||
#define COMSIG_EMOTE_OVERLAY_EXPIRE "emote_overlay_exprie"
|
||||
/// From /mob/living/carbon/human/proc/adjust_arousal() - Triggered by status
|
||||
#define COMSIG_HUMAN_ADJUST_AROUSAL "human_adjust_arousal"
|
||||
/// from /mob/living/carbon/human/verb/toggle_arousal() - Triggered by player toggle
|
||||
#define COMSIG_HUMAN_TOGGLE_AROUSAL "human_toggle_arousal"
|
||||
/// From /mob/living/carbon/human/verb/toggle_genitals()
|
||||
#define COMSIG_HUMAN_TOGGLE_GENITALS "human_toggle_genitals"
|
||||
|
||||
@@ -202,6 +202,7 @@ GLOBAL_LIST_INIT(WALLITEMS_INTERIOR, typecacheof(list(
|
||||
/obj/structure/sign/poster/official/random,
|
||||
/obj/structure/sign/poster/random,
|
||||
/obj/structure/urinal,
|
||||
/obj/structure/lewd_portal, //BUBBER EDIT ADDITION - Lewd Portals
|
||||
)))
|
||||
|
||||
// Wall mounted machinery which are visually coming out of the wall.
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
if(!referenced_bodypart)
|
||||
return ..()
|
||||
referenced_bodypart.remove_bodypart_overlay(src)
|
||||
if(!isnull(usr))
|
||||
SEND_SIGNAL(usr, COMSIG_EMOTE_OVERLAY_EXPIRE) //BUBBER EDIT ADDITION - Used for lewd portals, blush expiring breaks it
|
||||
return ..()
|
||||
|
||||
/**
|
||||
|
||||
@@ -158,6 +158,7 @@
|
||||
cuffs = new type()
|
||||
|
||||
target.equip_to_slot(cuffs, ITEM_SLOT_HANDCUFFED)
|
||||
SEND_SIGNAL(target, COMSIG_MOB_HANDCUFFED) //BUBBER EDIT ADDITION
|
||||
|
||||
if(trashtype && !dispense)
|
||||
qdel(src)
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
var/result_path
|
||||
var/wall_external = FALSE // For frames that are external to the wall they are placed on, like light fixtures and cameras.
|
||||
var/pixel_shift //The amount of pixels
|
||||
var/multi_use = 0 //BUBBER EDIT ADDITION - User for lewd portals to allow you to place more than one
|
||||
var/bypass_unpowered = FALSE //BUBBER EDIT ADDITION - Some wallframes can be placed in unpowered areas, specifically lewd portals in this case
|
||||
var/bypass_floor = FALSE //BUBBER EDIT ADDITION - Some wallframes can be placed in areas without floors, specifically lewd portals in this case
|
||||
|
||||
/obj/item/wallframe/proc/try_build(turf/on_wall, mob/user)
|
||||
if(get_dist(on_wall,user) > 1)
|
||||
@@ -20,10 +23,10 @@
|
||||
return
|
||||
var/turf/T = get_turf(user)
|
||||
var/area/A = get_area(T)
|
||||
if(!isfloorturf(T))
|
||||
if(!isfloorturf(T) && !bypass_floor) //BUBBER EDIT - allows for wallmounts in floorless areas
|
||||
balloon_alert(user, "cannot place here!")
|
||||
return
|
||||
if(A.always_unpowered)
|
||||
if(A.always_unpowered && !bypass_unpowered) //BUBBER EDIT - allows for wallmounts in unpowered areas
|
||||
balloon_alert(user, "cannot place in this area!")
|
||||
return
|
||||
if(check_wall_item(T, floor_to_wall, wall_external))
|
||||
@@ -53,9 +56,14 @@
|
||||
if(WEST)
|
||||
hanging_object.pixel_x = -pixel_shift
|
||||
after_attach(hanging_object)
|
||||
|
||||
//BUBBER EDIT START - For lewd_portals, you can place multiple with the same frame.
|
||||
if(multi_use > 1)
|
||||
multi_use--
|
||||
return
|
||||
//BUBBER EDIT END
|
||||
qdel(src)
|
||||
|
||||
|
||||
/obj/item/wallframe/proc/after_attach(obj/attached_to)
|
||||
transfer_fingerprints_to(attached_to)
|
||||
|
||||
|
||||
@@ -21,7 +21,13 @@
|
||||
/turf/closed/indestructible/attackby(obj/item/attacking_item, mob/user, list/modifiers)
|
||||
if(istype(attacking_item, /obj/item/poster) && Adjacent(user))
|
||||
return place_poster(attacking_item, user)
|
||||
|
||||
//BUBBER EDIT START - Its almost certain that people are going to want to make use of lewd portals on the interlink so they can be placed on reinforced walls
|
||||
if(istype(attacking_item, /obj/item/wallframe/lewd_portal) && Adjacent(user))
|
||||
var/obj/item/wallframe/lewd_portal = attacking_item
|
||||
if(lewd_portal.try_build(src, user))
|
||||
lewd_portal.attach(src, user)
|
||||
return TRUE
|
||||
//BUBBER EDIT END
|
||||
return ..()
|
||||
|
||||
/turf/closed/indestructible/oldshuttle
|
||||
|
||||
@@ -297,27 +297,38 @@
|
||||
return COMPONENT_CANCEL_ATTACK_CHAIN
|
||||
|
||||
/mob/living/silicon/robot/proc/ninjadrain_charge(mob/living/carbon/human/ninja, obj/item/mod/module/hacker/hacking_module)
|
||||
//SKYRAT EDIT: ADDITION START
|
||||
//BUBBER ADDITION BEGIN - Role selection
|
||||
var/list/modelselected = list()
|
||||
modelselected["Assault"] = "/obj/item/robot_model/ninja"
|
||||
modelselected["Medical"] = "/obj/item/robot_model/ninja/ninja_medical"
|
||||
modelselected["Saboteur"] = "/obj/item/robot_model/ninja_saboteur"
|
||||
//SKYRAT EDIT: ADDITION END
|
||||
//BUBBER ADDITION END - Role selection
|
||||
if(!do_after(ninja, 6 SECONDS, target = src, hidden = TRUE))
|
||||
return
|
||||
spark_system.start()
|
||||
playsound(loc, SFX_SPARKS, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
|
||||
//BUBBER ADDITION BEGIN - No ai shells
|
||||
if(shell)
|
||||
ResetModel()
|
||||
return TRUE
|
||||
//BUBBER ADDITION END
|
||||
to_chat(src, span_danger("UPLOAD COMPLETE. NEW CYBORG MODEL DETECTED. INSTALLING..."))
|
||||
faction = list(ROLE_NINJA)
|
||||
bubble_icon = "syndibot"
|
||||
UnlinkSelf()
|
||||
//BUBBER ADDITION BEGIN - Harder to unsubvert ninja borgs
|
||||
scrambledcodes = TRUE
|
||||
SetEmagged(TRUE)
|
||||
//BUBBER ADDITION END
|
||||
ionpulse = TRUE
|
||||
laws = new /datum/ai_laws/ninja_override()
|
||||
//SKYRAT EDIT CHANGE BEGIN - Role Selection
|
||||
//BUBBER ADDITION BEGIN - Role Selection
|
||||
//model.transform_to(pick(/obj/item/robot_model/syndicate, /obj/item/robot_model/syndicate_medical, /obj/item/robot_model/saboteur)) - SKYRAT EDIT - ORIGINAL
|
||||
var/choice = input(src,"What role do you wish to become?","Select Role") in sort_list(modelselected)
|
||||
var/choice = tgui_input_list(src, "What role do you wish to become?","Select Role", modelselected)
|
||||
if(!choice)
|
||||
choice = pick(modelselected)
|
||||
model.transform_to(modelselected[choice])
|
||||
//SKYRAT EDIT CHANGE END
|
||||
//BUBBER ADDITION END
|
||||
|
||||
|
||||
var/datum/antagonist/ninja/ninja_antag = ninja.mind.has_antag_datum(/datum/antagonist/ninja)
|
||||
|
||||
@@ -234,10 +234,6 @@
|
||||
show_grid = !show_grid
|
||||
if("finalize")
|
||||
. = TRUE
|
||||
if(isobserver(user)) // Ghosts cant finalize
|
||||
return
|
||||
if(istype(user, /mob/living/silicon) && !Adjacent(user, src)) // Silicons cant finalize unless adjacent
|
||||
return
|
||||
finalize(user)
|
||||
if("patronage")
|
||||
. = TRUE
|
||||
|
||||
@@ -505,6 +505,7 @@
|
||||
to_chat(src, span_warning("You are unable to equip that!"))
|
||||
return FALSE
|
||||
equip_to_slot(W, slot, initial, redraw_mob, indirect_action = indirect_action) //This proc should not ever fail.
|
||||
SEND_SIGNAL(src, COMSIG_MOB_POST_EQUIP, W, slot) //BUBBER EDIT ADDITION
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
|
||||
@@ -1242,8 +1242,28 @@ mutant_styles: The mutant style - taur bodytype, STYLE_TESHARI, etc. // SKYRAT E
|
||||
return
|
||||
|
||||
my_head.update_limb(is_creating = update_limb_data)
|
||||
//BUBBER EDIT START - We need to account for different heights when using this proc
|
||||
var/my_head_icon = my_head.get_limb_icon(dropped = FALSE, update_on = src)
|
||||
|
||||
add_overlay(my_head.get_limb_icon(dropped = FALSE, update_on = src))
|
||||
if(mob_height != HUMAN_HEIGHT_MEDIUM)
|
||||
var/string_form_index = num2text(HEAD_LAYER)
|
||||
var/offset_type = GLOB.layers_to_offset[string_form_index]
|
||||
if(isnull(offset_type))
|
||||
if(islist(my_head_icon))
|
||||
for(var/image/applied_appearance in my_head_icon)
|
||||
apply_height_filters(applied_appearance)
|
||||
else if(isimage(my_head_icon))
|
||||
apply_height_filters(my_head_icon)
|
||||
else
|
||||
if(islist(my_head_icon))
|
||||
for(var/image/applied_appearance in my_head_icon)
|
||||
apply_height_offsets(applied_appearance, offset_type)
|
||||
else if(isimage(my_head_icon))
|
||||
apply_height_offsets(my_head_icon, offset_type)
|
||||
|
||||
add_overlay(my_head_icon)
|
||||
//add_overlay(my_head.get_limb_icon(dropped = FALSE, update_on = src))
|
||||
//BUBBER EDIT END
|
||||
update_worn_head()
|
||||
update_worn_mask()
|
||||
|
||||
|
||||
6
html/changelogs/AutoChangeLog-bubber-pr-3787.yml
Normal file
6
html/changelogs/AutoChangeLog-bubber-pr-3787.yml
Normal file
@@ -0,0 +1,6 @@
|
||||
author: "pixelkitty286"
|
||||
delete-after: True
|
||||
changes:
|
||||
- balance: "AI shells can no longer get a free ninja shell from a ninja."
|
||||
- balance: "Cyborgs hacked by a ninja now set scrambled codes and are emagged."
|
||||
- bugfix: "When a ninja hacks a cyborg it now uses Tgui instead of the byond selection."
|
||||
4
html/changelogs/AutoChangeLog-bubber-pr-4105.yml
Normal file
4
html/changelogs/AutoChangeLog-bubber-pr-4105.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
author: "ReturnToZender"
|
||||
delete-after: True
|
||||
changes:
|
||||
- rscadd: "Restored the holy vetted examine text, even if it's redundant now. It can wait a bit before going to the retirement home."
|
||||
4
html/changelogs/AutoChangeLog-bubber-pr-4142.yml
Normal file
4
html/changelogs/AutoChangeLog-bubber-pr-4142.yml
Normal file
@@ -0,0 +1,4 @@
|
||||
author: "Iamgoofball"
|
||||
delete-after: True
|
||||
changes:
|
||||
- rscdel: "Removes pay-to-win military gloves from the loadout"
|
||||
@@ -197,3 +197,22 @@
|
||||
shellspeed1:
|
||||
- bugfix: The elevator on persistence works again. Pretty sure we had Jimmy Hoffa
|
||||
stuck there or say the SOSHA folks say.
|
||||
2025-06-29:
|
||||
Arturlang:
|
||||
- bugfix: Fixes/changes some conversion messages to make it make more sense
|
||||
- bugfix: mindshielded conversion
|
||||
- bugfix: SAD's should no longer nuke nitrogen lungs
|
||||
Bombermansam:
|
||||
- rscadd: More Mutation Toxins
|
||||
- rscadd: Mutation Toxins Recipes
|
||||
- rscadd: Hemophage Virus to go with the mutation toxin
|
||||
- bugfix: Updates the xenomorph virus to the xenos we use rather than the old ones
|
||||
Odairu:
|
||||
- balance: changed point values on tellers so they run a bit earlier/later depending
|
||||
on teller
|
||||
SpaceCatSS13:
|
||||
- rscadd: The Lustwish Portal Bore has been added, equipped with both a gloryhole
|
||||
and stuck in wall mode, your lower half can now be in dorms while your head
|
||||
performs your job
|
||||
xPokee:
|
||||
- bugfix: fixed crusader belts spawning without the storage pouch
|
||||
|
||||
@@ -231,7 +231,9 @@
|
||||
|
||||
|
||||
/obj/item/clothing/head/helmet/space/akula_wetsuit/attack_hand_secondary(mob/user)
|
||||
..()
|
||||
. = ..()
|
||||
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
|
||||
return
|
||||
if(!attached_hat)
|
||||
return
|
||||
|
||||
|
||||
@@ -104,12 +104,3 @@
|
||||
/datum/loadout_item/gloves/diamondring
|
||||
name = "Diamond Ring"
|
||||
item_path = /obj/item/clothing/gloves/ring/diamond
|
||||
|
||||
/*
|
||||
* DONATOR
|
||||
*/
|
||||
|
||||
/datum/loadout_item/gloves/military
|
||||
name = "Military Gloves"
|
||||
item_path = /obj/item/clothing/gloves/military
|
||||
donator_only = TRUE
|
||||
|
||||
@@ -227,11 +227,13 @@
|
||||
|
||||
/obj/structure/deployable_barricade/attack_hand_secondary(mob/user, list/modifiers)
|
||||
. = ..()
|
||||
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
|
||||
return
|
||||
if(anchored)
|
||||
to_chat(usr, span_warning("It is secured to the floor, you can't turn it!"))
|
||||
return FALSE
|
||||
|
||||
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
||||
setDir(turn(dir, 270))
|
||||
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
||||
|
||||
|
||||
/*----------------------*/
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
var/high_message = pick("You feel hyper.", "You feel like you need to go faster.", "You feel like you can run the world.")
|
||||
if(SPT_PROB(2.5, seconds_per_tick))
|
||||
to_chat(M, span_notice("[high_message]"))
|
||||
M.add_mood_event("tweaking", /datum/mood_event/stimulant_medium, 1, name)
|
||||
M.add_mood_event("tweaking", /datum/mood_event/stimulant_medium, name)
|
||||
M.AdjustStun(-40 * REM * seconds_per_tick)
|
||||
M.AdjustKnockdown(-40 * REM * seconds_per_tick)
|
||||
M.AdjustUnconscious(-40 * REM * seconds_per_tick)
|
||||
|
||||
@@ -544,7 +544,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/cryopod, 32)
|
||||
return
|
||||
to_chat(user, span_notice("You tuck [occupant.name] into their pod!"))
|
||||
qdel(weapon)
|
||||
user.add_mood_event("tucked", /datum/mood_event/tucked_in, 1, occupant)
|
||||
user.add_mood_event("tucked", /datum/mood_event/tucked_in, occupant)
|
||||
tucked = TRUE
|
||||
|
||||
/obj/machinery/cryopod/update_icon_state()
|
||||
|
||||
@@ -418,7 +418,7 @@
|
||||
user.changeNext_move(CLICK_CD_MELEE) // To avoid spam, in some cases (sadly not all of them)
|
||||
var/mob/living/living_user = user
|
||||
if(istype(living_user))
|
||||
living_user.add_mood_event("hug", /datum/mood_event/warmhug/rubi, 1, src)
|
||||
living_user.add_mood_event("hug", /datum/mood_event/warmhug/rubi, src)
|
||||
user.visible_message(span_notice("[user] hugs \the [src]."), span_notice("You hug \the [src]."))
|
||||
|
||||
/datum/mood_event/warmhug/rubi
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
/obj/item/melee/cleric_mace,
|
||||
/obj/item/knife,
|
||||
/obj/item/melee/baton,
|
||||
/obj/item/melee/baton,
|
||||
/obj/item/nullrod, //holds any subset of nullrod in the sheath-storage - - -
|
||||
),
|
||||
canthold = list( // - - - except the second list's items (no fedora in the sheath)
|
||||
@@ -39,13 +38,11 @@
|
||||
/obj/item/nullrod/staff,
|
||||
/obj/item/nullrod/fedora,
|
||||
/obj/item/nullrod/godhand,
|
||||
/obj/item/nullrod/staff,
|
||||
/obj/item/nullrod/whip,
|
||||
),
|
||||
)
|
||||
atom_storage.allow_big_nesting = TRUE // Lets the pouch work
|
||||
AddElement(/datum/element/update_icon_updates_onmob)
|
||||
PopulateContents()
|
||||
|
||||
//Overrides normal dumping code to instead dump from the pouch item inside
|
||||
/datum/storage/belt/crusader/dump_content_at(atom/dest_object, mob/dumping_mob)
|
||||
@@ -75,7 +72,9 @@
|
||||
to_chat(user, span_notice("You fumble for [drawn_item] and it falls on the floor."))
|
||||
update_appearance()
|
||||
return CLICK_ACTION_SUCCESS
|
||||
user.visible_message(span_notice("[user] takes [drawn_item] out of [src]."), span_notice("You take [drawn_item] out of [src]."))
|
||||
user.visible_message(
|
||||
span_notice("[user] takes [drawn_item] out of [src]."),
|
||||
span_notice("You take [drawn_item] out of [src]."))
|
||||
update_appearance()
|
||||
else
|
||||
to_chat(user, span_warning("[src] is empty!"))
|
||||
|
||||
@@ -102,6 +102,7 @@
|
||||
if("hide")
|
||||
underwear_visibility = UNDERWEAR_HIDE_UNDIES | UNDERWEAR_HIDE_SHIRT | UNDERWEAR_HIDE_SOCKS | UNDERWEAR_HIDE_BRA
|
||||
update_body()
|
||||
SEND_SIGNAL(src, COMSIG_HUMAN_TOGGLE_UNDERWEAR, picked_choice)
|
||||
return
|
||||
|
||||
/mob/living/carbon/human/revive(full_heal_flags = NONE, excess_healing = 0, force_grab_ghost = FALSE)
|
||||
|
||||
@@ -176,3 +176,6 @@
|
||||
|
||||
|
||||
#undef HEMOPHAGE_SPAWN_TEXT
|
||||
|
||||
/mob/living/carbon/human/species/hemophage //Why was this never added?
|
||||
race = /datum/species/hemophage
|
||||
|
||||
@@ -528,6 +528,7 @@
|
||||
if(picked_visibility && picked_organ && (picked_organ in organs))
|
||||
picked_organ.visibility_preference = gen_vis_trans[picked_visibility]
|
||||
update_body()
|
||||
SEND_SIGNAL(src, COMSIG_HUMAN_TOGGLE_GENITALS)
|
||||
return
|
||||
|
||||
//Removing ERP IC verb depending on config
|
||||
@@ -566,4 +567,5 @@
|
||||
picked_organ.aroused = gen_arous_trans[picked_arousal]
|
||||
picked_organ.update_sprite_suffix()
|
||||
update_body()
|
||||
SEND_SIGNAL(src, COMSIG_HUMAN_TOGGLE_AROUSAL)
|
||||
return
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
|
||||
constant_dose_time += seconds_per_tick
|
||||
|
||||
our_guy.add_mood_event("tweaking", /datum/mood_event/stimulant_heavy/sundowner, 1, name)
|
||||
our_guy.add_mood_event("tweaking", /datum/mood_event/stimulant_heavy/sundowner, name)
|
||||
|
||||
our_guy.adjustStaminaLoss(-10 * REM * seconds_per_tick)
|
||||
our_guy.AdjustSleeping(-20 * REM * seconds_per_tick)
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
else
|
||||
user.visible_message(span_notice("[usr] brushes [human_target]'s hair!"), span_notice("You brush [human_target]'s hair."), ignored_mobs=list(human_target))
|
||||
human_target.show_message(span_notice("[usr] brushes your hair!"), MSG_VISUAL)
|
||||
human_target.add_mood_event("brushed", /datum/mood_event/brushed, 1, user)
|
||||
human_target.add_mood_event("brushed", /datum/mood_event/brushed, user)
|
||||
|
||||
else if(istype(target, /mob/living/basic/pet))
|
||||
if(!do_after(usr, brush_speed, target))
|
||||
@@ -55,4 +55,4 @@
|
||||
to_chat(user, span_notice("[target] closes [target.p_their()] eyes as you brush [target.p_them()]!"))
|
||||
var/mob/living/living_user = user
|
||||
if(istype(living_user))
|
||||
living_user.add_mood_event("brushed", /datum/mood_event/brushed/pet, 1, target)
|
||||
living_user.add_mood_event("brushed", /datum/mood_event/brushed/pet, target)
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
var/list/datum/interaction/interactions
|
||||
var/interact_last = 0
|
||||
var/interact_next = 0
|
||||
///Holds a reference to a relayed body if one exists
|
||||
var/obj/body_relay = null
|
||||
|
||||
/datum/component/interactable/Initialize(...)
|
||||
if(QDELETED(parent))
|
||||
@@ -53,7 +55,8 @@
|
||||
if(interaction.lewd && !target.client?.prefs?.read_preference(/datum/preference/toggle/erp))
|
||||
return FALSE
|
||||
if(!interaction.distance_allowed && !target.Adjacent(self))
|
||||
return FALSE
|
||||
if(!body_relay || !target.Adjacent(body_relay))
|
||||
return FALSE
|
||||
if(interaction.category == INTERACTION_CAT_HIDE)
|
||||
return FALSE
|
||||
if(self == target && interaction.usage == INTERACTION_OTHER)
|
||||
@@ -98,6 +101,9 @@
|
||||
data["ref_user"] = REF(user)
|
||||
data["ref_self"] = REF(self)
|
||||
data["self"] = self.name
|
||||
if(body_relay)
|
||||
if(!can_see(user, self))
|
||||
data["self"] = body_relay.name
|
||||
data["block_interact"] = interact_next >= world.time
|
||||
data["interactions"] = categories
|
||||
|
||||
@@ -147,7 +153,10 @@
|
||||
var/mob/living/carbon/human/user = locate(params["userref"])
|
||||
if(!can_interact(GLOB.interaction_instances[interaction_id], user))
|
||||
return FALSE
|
||||
GLOB.interaction_instances[interaction_id].act(user, locate(params["selfref"]))
|
||||
if(body_relay && !can_see(user, self))
|
||||
GLOB.interaction_instances[interaction_id].act(user, locate(params["selfref"]), body_relay)
|
||||
else
|
||||
GLOB.interaction_instances[interaction_id].act(user, locate(params["selfref"]))
|
||||
var/datum/component/interactable/interaction_component = user.GetComponent(/datum/component/interactable)
|
||||
interaction_component.interact_last = world.time
|
||||
interact_next = interaction_component.interact_last + INTERACTION_COOLDOWN
|
||||
|
||||
@@ -83,7 +83,7 @@ GLOBAL_LIST_EMPTY_TYPED(interaction_instances, /datum/interaction)
|
||||
CRASH("Unimplemented interaction requirement '[requirement]'")
|
||||
return TRUE
|
||||
|
||||
/datum/interaction/proc/act(mob/living/carbon/human/user, mob/living/carbon/human/target)
|
||||
/datum/interaction/proc/act(mob/living/carbon/human/user, mob/living/carbon/human/target, obj/body_relay = null)
|
||||
if(!allow_act(user, target))
|
||||
return
|
||||
if(!message)
|
||||
@@ -93,6 +93,8 @@ GLOBAL_LIST_EMPTY_TYPED(interaction_instances, /datum/interaction)
|
||||
message_admins("Deprecated message handling for '[name]'. Correct format is a list with one entry. This message will only show once.")
|
||||
message = list(message)
|
||||
var/msg = pick(message)
|
||||
if(!isnull(body_relay))
|
||||
msg = replacetext(msg, "%TARGET%", "\the [body_relay.name]")
|
||||
// We replace %USER% with nothing because manual_emote already prepends it.
|
||||
msg = trim(replacetext(replacetext(msg, "%TARGET%", "[target]"), "%USER%", ""), INTERACTION_MAX_CHAR)
|
||||
if(lewd)
|
||||
@@ -101,10 +103,14 @@ GLOBAL_LIST_EMPTY_TYPED(interaction_instances, /datum/interaction)
|
||||
user.manual_emote(msg)
|
||||
if(user_messages.len)
|
||||
var/user_msg = pick(user_messages)
|
||||
if(!isnull(body_relay))
|
||||
user_msg = replacetext(user_msg, "%TARGET%", "\the [body_relay.name]")
|
||||
user_msg = replacetext(replacetext(user_msg, "%TARGET%", "[target]"), "%USER%", "[user]")
|
||||
to_chat(user, user_msg)
|
||||
if(target_messages.len)
|
||||
var/target_msg = pick(target_messages)
|
||||
if(!isnull(body_relay))
|
||||
target_msg = replacetext(target_msg, "%USER%", "Unknown")
|
||||
target_msg = replacetext(replacetext(target_msg, "%TARGET%", "[target]"), "%USER%", "[user]")
|
||||
to_chat(target, target_msg)
|
||||
if(sound_use)
|
||||
@@ -125,6 +131,9 @@ GLOBAL_LIST_EMPTY_TYPED(interaction_instances, /datum/interaction)
|
||||
target.adjust_pleasure(target_pleasure)
|
||||
target.adjust_arousal(target_arousal)
|
||||
target.adjust_pain(target_pain)
|
||||
if(body_relay)
|
||||
var/obj/lewd_portal_relay/body_portal_relay = body_relay
|
||||
body_portal_relay.update_visuals()
|
||||
|
||||
/datum/interaction/proc/load_from_json(path)
|
||||
var/fpath = path
|
||||
|
||||
@@ -56,8 +56,11 @@
|
||||
. += span_notice("It seems like you could use an <b>empty hand</b> to remove the magazine.")
|
||||
|
||||
/obj/item/gun/ballistic/automatic/smart_machine_gun/attack_hand_secondary(mob/user, list/modifiers)
|
||||
if(!user.can_perform_action(src))
|
||||
. = ..()
|
||||
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
|
||||
return
|
||||
if(!user.can_perform_action(src))
|
||||
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
||||
cover_open = !cover_open
|
||||
to_chat(user, span_notice("You [cover_open ? "open" : "close"] [src]'s cover."))
|
||||
playsound(src, 'sound/items/weapons/gun/l6/l6_door.ogg', 60, TRUE)
|
||||
|
||||
@@ -101,10 +101,13 @@
|
||||
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
||||
|
||||
/obj/item/clothing/neck/link_scryer/loaded/nifsoft/attack_hand_secondary(mob/user, list/modifiers)
|
||||
. = ..()
|
||||
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
|
||||
return
|
||||
var/new_label = reject_bad_text(tgui_input_text(user, "Change the visible name", "Set Name", label, MAX_NAME_LEN))
|
||||
if(!new_label)
|
||||
balloon_alert(user, "invalid name!")
|
||||
return
|
||||
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
||||
label = new_label
|
||||
balloon_alert(user, "name set!")
|
||||
update_name()
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
tool_behaviors = list(TOOL_WIRECUTTER, TOOL_SCREWDRIVER, TOOL_WELDER) //To cut the leather and fasten/weld the sheath detailing
|
||||
time = 30
|
||||
category = CAT_CLOTHING
|
||||
delete_contents = FALSE // Otherwise the storage pouch gets deleted when crafted.
|
||||
|
||||
/datum/crafting_recipe/crusader_satchel
|
||||
name = "Crusader Satchel"
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
target_genital.aroused = arousal_status
|
||||
target_genital.update_sprite_suffix()
|
||||
target.update_body()
|
||||
SEND_SIGNAL(src, COMSIG_HUMAN_ADJUST_AROUSAL)
|
||||
|
||||
arousal = clamp(arousal + arous, AROUSAL_MINIMUM, AROUSAL_LIMIT)
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#define CLIMAX_ON_FLOOR "On the floor"
|
||||
#define CLIMAX_IN_OR_ON "Climax in or on someone"
|
||||
#define CLIMAX_OPEN_CONTAINER "Fill reagent container"
|
||||
#define CLIMAX_PORTAL "Through the portal"
|
||||
|
||||
/mob/living/carbon/human
|
||||
/// Used to prevent nightmare scenarios.
|
||||
@@ -91,6 +92,11 @@
|
||||
if(interactable_inrange_open_containers.len)
|
||||
buttons += CLIMAX_OPEN_CONTAINER
|
||||
|
||||
// If your using a LustWish portal lets you cum through it
|
||||
var/obj/structure/lewd_portal/portal = src.buckled
|
||||
if(istype(portal, /obj/structure/lewd_portal))
|
||||
buttons += CLIMAX_PORTAL
|
||||
|
||||
var/penis_climax_choice = tgui_alert(src, "Choose where to shoot your load.", "Load preference!", buttons)
|
||||
|
||||
var/create_cum_decal = FALSE
|
||||
@@ -135,6 +141,11 @@
|
||||
visible_message(span_userlove("[src] shoots [self_their] sticky load onto the floor!"), \
|
||||
span_userlove("You shoot string after string of hot cum, hitting the floor!"))
|
||||
|
||||
else if(penis_climax_choice == CLIMAX_PORTAL)
|
||||
to_chat(src, "You shoot string after string of hot cum, hitting whatever is on the other side!")
|
||||
portal.relayed_body.visible_message("[portal.relayed_body] shoots its sticky load onto the floor!")
|
||||
add_cum_splatter_floor(get_turf(portal.relayed_body))
|
||||
|
||||
else
|
||||
var/target_choice = tgui_input_list(src, "Choose a person to cum in or on.", "Choose target!", interactable_inrange_humans)
|
||||
if(!target_choice)
|
||||
@@ -209,3 +220,4 @@
|
||||
#undef CLIMAX_ON_FLOOR
|
||||
#undef CLIMAX_IN_OR_ON
|
||||
#undef CLIMAX_OPEN_CONTAINER
|
||||
#undef CLIMAX_PORTAL
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
// Notify the user that they're overdosing. Doesn't affect their mood.
|
||||
/datum/reagent/drug/aphrodisiac/camphor/overdose_start(mob/living/carbon/human/exposed_mob)
|
||||
to_chat(exposed_mob, span_userdanger("You feel like you took too much [name]!"))
|
||||
exposed_mob.add_mood_event("[type]_overdose", /datum/mood_event/minor_overdose, 1, name)
|
||||
exposed_mob.add_mood_event("[type]_overdose", /datum/mood_event/minor_overdose, name)
|
||||
|
||||
/datum/chemical_reaction/camphor
|
||||
results = list(/datum/reagent/drug/aphrodisiac/camphor = 6)
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
/datum/reagent/drug/aphrodisiac/dopamine/on_mob_add(mob/living/carbon/human/exposed_mob)
|
||||
if(!(exposed_mob.client?.prefs.read_preference(/datum/preference/toggle/erp/aphro)))
|
||||
return ..()
|
||||
exposed_mob.add_mood_event("[type]_start", /datum/mood_event/orgasm, 1, name)
|
||||
exposed_mob.add_mood_event("[type]_start", /datum/mood_event/orgasm, name)
|
||||
return ..()
|
||||
|
||||
/datum/reagent/drug/aphrodisiac/dopamine/life_effects(mob/living/carbon/human/exposed_mob)
|
||||
@@ -35,7 +35,7 @@
|
||||
/datum/reagent/drug/aphrodisiac/dopamine/overdose_start(mob/living/carbon/human/exposed_mob)
|
||||
. = ..()
|
||||
to_chat(exposed_mob, span_purple("You feel so happy!"))
|
||||
exposed_mob.add_mood_event("[type]_overdose", /datum/mood_event/overgasm, 1, name)
|
||||
exposed_mob.add_mood_event("[type]_overdose", /datum/mood_event/overgasm, name)
|
||||
|
||||
/datum/reagent/drug/aphrodisiac/dopamine/overdose_effects(mob/living/carbon/human/exposed_mob)
|
||||
if(!(exposed_mob.get_timed_status_effect_duration(/datum/status_effect/hallucination) / (2 SECONDS) < volume && prob(20)))
|
||||
|
||||
@@ -167,7 +167,7 @@
|
||||
// Notify the user that they're overdosing. Doesn't affect their mood.
|
||||
/datum/reagent/drug/aphrodisiac/incubus_draft/overdose_start(mob/living/carbon/human/exposed_mob)
|
||||
to_chat(exposed_mob, span_userdanger("You feel like you took too much [name]!"))
|
||||
exposed_mob.add_mood_event("[type]_overdose", /datum/mood_event/minor_overdose, 1, name)
|
||||
exposed_mob.add_mood_event("[type]_overdose", /datum/mood_event/minor_overdose, name)
|
||||
|
||||
/datum/chemical_reaction/incubus_draft
|
||||
results = list(/datum/reagent/drug/aphrodisiac/incubus_draft = 8)
|
||||
|
||||
@@ -154,7 +154,7 @@
|
||||
// Notify the user that they're overdosing. Doesn't affect their mood.
|
||||
/datum/reagent/drug/aphrodisiac/succubus_milk/overdose_start(mob/living/carbon/human/exposed_mob)
|
||||
to_chat(exposed_mob, span_userdanger("You feel like you took too much [name]!"))
|
||||
exposed_mob.add_mood_event("[type]_overdose", /datum/mood_event/minor_overdose, 1, name)
|
||||
exposed_mob.add_mood_event("[type]_overdose", /datum/mood_event/minor_overdose, name)
|
||||
|
||||
/datum/chemical_reaction/succubus_milk
|
||||
results = list(/datum/reagent/drug/aphrodisiac/succubus_milk = 8)
|
||||
|
||||
@@ -150,6 +150,7 @@
|
||||
/obj/item/storage/box/shibari_stand = 4,
|
||||
/obj/item/storage/box/strippole_kit = 4,
|
||||
/obj/item/storage/box/xstand_kit = 4,
|
||||
/obj/item/wallframe/lewd_portal = 8,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
if(SPT_PROB(2.5, seconds_per_tick))
|
||||
var/high_message = pick("You feel jittery.", "You feel like you gotta go fast.", "You feel like you need to step it up.")
|
||||
to_chat(M, span_notice("[high_message]"))
|
||||
M.add_mood_event("zoinked", /datum/mood_event/stimulant_heavy, 1, name)
|
||||
M.add_mood_event("zoinked", /datum/mood_event/stimulant_heavy, name)
|
||||
M.AdjustStun(-15 * REM * seconds_per_tick)
|
||||
M.AdjustKnockdown(-15 * REM * seconds_per_tick)
|
||||
M.AdjustUnconscious(-15 * REM * seconds_per_tick)
|
||||
@@ -134,7 +134,7 @@
|
||||
if(SPT_PROB(2.5, seconds_per_tick))
|
||||
var/high_message = pick("You feel jittery.", "You feel like you gotta go fast.", "You feel like you need to step it up.")
|
||||
to_chat(M, span_notice("[high_message]"))
|
||||
M.add_mood_event("zoinked", /datum/mood_event/stimulant_heavy, 1, name)
|
||||
M.add_mood_event("zoinked", /datum/mood_event/stimulant_heavy, name)
|
||||
M.AdjustStun(-12 * REM * seconds_per_tick)
|
||||
M.AdjustKnockdown(-12 * REM * seconds_per_tick)
|
||||
M.AdjustUnconscious(-12 * REM * seconds_per_tick)
|
||||
@@ -186,7 +186,7 @@
|
||||
if(SPT_PROB(2.5, seconds_per_tick))
|
||||
var/high_message = pick("You feel jittery.", "You feel like you gotta go fast.", "You feel like you need to step it up.")
|
||||
to_chat(M, span_notice("[high_message]"))
|
||||
M.add_mood_event("zoinked", /datum/mood_event/stimulant_heavy, 1, name)
|
||||
M.add_mood_event("zoinked", /datum/mood_event/stimulant_heavy, name)
|
||||
M.AdjustStun(-18 * REM * seconds_per_tick)
|
||||
M.AdjustKnockdown(-18 * REM * seconds_per_tick)
|
||||
M.AdjustUnconscious(-18 * REM * seconds_per_tick)
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
var/high_message = pick("You feel euphoric.", "You feel on top of the world.")
|
||||
if(SPT_PROB(2.5, seconds_per_tick))
|
||||
to_chat(M, span_notice("[high_message]"))
|
||||
M.add_mood_event("smacked out", /datum/mood_event/narcotic_heavy, 1, name)
|
||||
M.add_mood_event("smacked out", /datum/mood_event/narcotic_heavy, name)
|
||||
M.adjustBruteLoss(-0.1 * REM * seconds_per_tick, 0) //can be used as a (shitty) painkiller
|
||||
M.adjustFireLoss(-0.1 * REM * seconds_per_tick, 0)
|
||||
M.overlay_fullscreen("heroin_euphoria", /atom/movable/screen/fullscreen/color_vision/heroin_color)
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
game_plane_master_controller.add_filter("weed_blur", 10, angular_blur_filter(0, 0, 0.45))
|
||||
if(SPT_PROB(2.5, seconds_per_tick))
|
||||
to_chat(M, span_notice("[high_message]"))
|
||||
M.add_mood_event("stoned", /datum/mood_event/stoned, 1, name)
|
||||
M.add_mood_event("stoned", /datum/mood_event/stoned, name)
|
||||
M.throw_alert("stoned", /atom/movable/screen/alert/stoned)
|
||||
M.sound_environment_override = SOUND_ENVIRONMENT_DRUGGED
|
||||
M.set_dizzy_if_lower(5 * REM * seconds_per_tick * 2 SECONDS)
|
||||
|
||||
@@ -177,16 +177,19 @@
|
||||
|
||||
/obj/machinery/mounted_machine_gun/attack_hand_secondary(mob/living/user, list/modifiers)
|
||||
. = ..()
|
||||
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
|
||||
return
|
||||
if(!istype(user))
|
||||
return
|
||||
if(!can_interact(user))
|
||||
return
|
||||
if(!cover_open)
|
||||
balloon_alert(user, "cover closed!")
|
||||
return
|
||||
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
||||
if(!ammo_box)
|
||||
return
|
||||
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
||||
remove_ammo_box(user)
|
||||
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
||||
|
||||
/obj/machinery/mounted_machine_gun/attackby(obj/item/weapon, mob/user, params)
|
||||
. = ..()
|
||||
|
||||
@@ -156,6 +156,9 @@
|
||||
to_chat(user, span_warning("The vitals readout is blank, the stasis unit is unoccupied!"))
|
||||
|
||||
/obj/machinery/stasissleeper/attack_hand_secondary(mob/user)
|
||||
. = ..()
|
||||
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
|
||||
return
|
||||
if(occupant)
|
||||
if(occupant == user)
|
||||
to_chat(user, span_notice("You read the bloodstream readout on the inside of the stasis unit."))
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
#define SUBTLE_ONE_TILE_TEXT "1-Tile Range"
|
||||
#define SUBTLE_SAME_TILE_TEXT "Same Tile"
|
||||
|
||||
#define PORTAL_ONE_TILE_TEXT "Portal 1-Tile Range"
|
||||
#define PORTAL_SAME_TILE_TEXT "Portal Tile"
|
||||
|
||||
/datum/emote/living/subtle
|
||||
key = "subtle"
|
||||
message = null
|
||||
@@ -113,6 +116,9 @@
|
||||
in_view.Remove(mob)
|
||||
|
||||
var/list/targets = list(SUBTLE_ONE_TILE_TEXT, SUBTLE_SAME_TILE_TEXT) + in_view
|
||||
var/obj/structure/lewd_portal/portal = user?.buckled
|
||||
if(istype(portal, /obj/structure/lewd_portal))
|
||||
targets.Insert(1, PORTAL_ONE_TILE_TEXT, PORTAL_SAME_TILE_TEXT)
|
||||
target = tgui_input_list(user, "Pick a target", "Target Selection", targets)
|
||||
if(!target)
|
||||
return FALSE
|
||||
@@ -145,22 +151,36 @@
|
||||
var/obj/effect/overlay/holo_pad_hologram/hologram = GLOB.hologram_impersonators[user]
|
||||
if((get_dist(user.loc, target_mob.loc) <= subtler_range) || (hologram && get_dist(hologram.loc, target_mob.loc) <= subtler_range))
|
||||
target_mob.show_message(subtler_message, alt_msg = subtler_message)
|
||||
// Optional sound notification
|
||||
var/datum/preferences/prefs = target_mob.client?.prefs
|
||||
if(prefs && prefs.read_preference(/datum/preference/toggle/subtler_sound))
|
||||
target_mob.playsound_local(get_turf(target_mob), 'sound/effects/achievement/glockenspiel_ping.ogg', 50)
|
||||
subtler_sound(target_mob)
|
||||
else
|
||||
to_chat(user, span_warning("Your emote was unable to be sent to your target: Too far away."))
|
||||
else if(istype(target, /obj/effect/overlay/holo_pad_hologram))
|
||||
var/obj/effect/overlay/holo_pad_hologram/hologram = target
|
||||
if(hologram.Impersonation?.client)
|
||||
hologram.Impersonation.show_message(subtler_message, alt_msg = subtler_message)
|
||||
// Optional sound notification
|
||||
var/datum/preferences/prefs = hologram.Impersonation.client?.prefs
|
||||
if(prefs && prefs.read_preference(/datum/preference/toggle/subtler_sound))
|
||||
hologram.Impersonation.playsound_local(get_turf(hologram.Impersonation), 'sound/effects/achievement/glockenspiel_ping.ogg', 50)
|
||||
subtler_sound(hologram.Impersonation)
|
||||
else if(istype(target, /obj/lewd_portal_relay)) //Direct Message to a portal user
|
||||
var/obj/lewd_portal_relay/portal_relay = target
|
||||
user.show_message(subtler_message, alt_msg = subtler_message)
|
||||
if(portal_relay.owner?.client)
|
||||
subtler_message = span_subtler("<b>Unknown</b>[space]<i>[user.apply_message_emphasis(subtler_emote)]</i>")
|
||||
portal_relay.owner.show_message(subtler_message, alt_msg = subtler_message)
|
||||
subtler_sound(portal_relay.owner)
|
||||
else
|
||||
var/ghostless = get_hearers_in_view(target, user) - GLOB.dead_mob_list
|
||||
var/ghostless
|
||||
if(target == PORTAL_SAME_TILE_TEXT || target == PORTAL_ONE_TILE_TEXT)
|
||||
switch(target)
|
||||
if(PORTAL_ONE_TILE_TEXT)
|
||||
target = SUBTLE_ONE_TILE
|
||||
if(PORTAL_SAME_TILE_TEXT)
|
||||
target = SUBTLE_SAME_TILE_DISTANCE
|
||||
var/obj/structure/lewd_portal/portal_reference = user.buckled
|
||||
var/obj/lewd_portal_relay/output_portal = portal_reference?.relayed_body
|
||||
ghostless = get_hearers_in_view(target, output_portal) //Broadcast message through portal
|
||||
user.show_message(subtler_message, alt_msg = subtler_message)
|
||||
subtler_message = span_subtler("<b>[output_portal]</b>[space]<i>[user.apply_message_emphasis(subtler_emote)]</i>")
|
||||
else
|
||||
ghostless = get_hearers_in_view(target, user) - GLOB.dead_mob_list
|
||||
|
||||
var/obj/effect/overlay/holo_pad_hologram/hologram = GLOB.hologram_impersonators[user]
|
||||
if(hologram)
|
||||
@@ -173,12 +193,22 @@
|
||||
for(var/mob/receiver in ghostless)
|
||||
receiver.show_message(subtler_message, alt_msg = subtler_message)
|
||||
// Optional sound notification
|
||||
var/datum/preferences/prefs = receiver.client?.prefs
|
||||
if(prefs && prefs.read_preference(/datum/preference/toggle/subtler_sound))
|
||||
receiver.playsound_local(get_turf(receiver), 'sound/effects/achievement/glockenspiel_ping.ogg', 50)
|
||||
subtler_sound(receiver)
|
||||
|
||||
for(var/obj/lewd_portal_relay/portal in ghostless) //Message portal owners caught in range
|
||||
if(portal?.owner?.client && portal.owner != user)
|
||||
subtler_message = span_subtler("<b>Unknown</b>[space]<i>[user.apply_message_emphasis(subtler_emote)]</i>")
|
||||
portal.owner.show_message(subtler_message, alt_msg = subtler_message)
|
||||
subtler_sound(portal.owner)
|
||||
|
||||
return TRUE
|
||||
|
||||
// Optional sound notification for subtler
|
||||
/datum/emote/living/subtler/proc/subtler_sound(mob/hearer)
|
||||
var/datum/preferences/prefs = hearer.client?.prefs
|
||||
if(prefs && prefs.read_preference(/datum/preference/toggle/subtler_sound))
|
||||
hearer.playsound_local(get_turf(hearer), 'sound/effects/achievement/glockenspiel_ping.ogg', 50)
|
||||
|
||||
/*
|
||||
* VERB CODE
|
||||
*/
|
||||
@@ -216,3 +246,6 @@
|
||||
|
||||
#undef SUBTLE_ONE_TILE_TEXT
|
||||
#undef SUBTLE_SAME_TILE_TEXT
|
||||
|
||||
#undef PORTAL_ONE_TILE_TEXT
|
||||
#undef PORTAL_SAME_TILE_TEXT
|
||||
|
||||
@@ -146,6 +146,8 @@
|
||||
|
||||
/obj/machinery/xenoarch/researcher/attack_hand_secondary(mob/user, list/modifiers)
|
||||
. = ..()
|
||||
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
|
||||
return
|
||||
var/turf/src_turf = get_turf(src)
|
||||
var/choice = tgui_input_list(user, "Choose which reward you would like!", "Reward Choice", list("Lavaland Chest (150)", "Anomalous Crystal (150)", "Bepis Tech (100)"))
|
||||
if(!choice)
|
||||
|
||||
@@ -1,8 +1,20 @@
|
||||
|
||||
/datum/quirk
|
||||
/// special case logic for quirks that don't quite handle being transferred properly
|
||||
var/cleanup = TRUE
|
||||
|
||||
/// Remove any quirks that the client's prefs do not have, and apply any new ones
|
||||
/datum/controller/subsystem/processing/quirks/proc/OverrideQuirks(mob/living/user, client/applied_client)
|
||||
var/list/required_quirks = applied_client.prefs.all_quirks
|
||||
var/list/present_quirks = list()
|
||||
for(var/datum/quirk/quirk in user.quirks)
|
||||
if(!(quirk.name in required_quirks))
|
||||
user.remove_quirk(quirk.type)
|
||||
AssignQuirks(user, applied_client)
|
||||
present_quirks[quirk.name] = TRUE
|
||||
quirk.cleanup = FALSE
|
||||
quirk.remove_from_current_holder(TRUE)
|
||||
|
||||
for(var/quirk_name in required_quirks)
|
||||
var/existing_quirk = present_quirks[quirk_name]
|
||||
var/quirk_type = quirks[quirk_name]
|
||||
var/datum/quirk/quirk = new quirk_type
|
||||
quirk.add_to_holder(user, existing_quirk, applied_client)
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/datum/disease/transformation/hemophage
|
||||
name = "Hemophagic Viral Infection"
|
||||
cure_text = "Garlic"
|
||||
cures = list(/datum/reagent/consumable/garlic)
|
||||
agent = "Hemophagic Viral Infection"
|
||||
desc = "A gift of the night"
|
||||
cure_chance = 2.5
|
||||
severity = DISEASE_SEVERITY_BIOHAZARD
|
||||
visibility_flags = NONE
|
||||
stage1 = list("You dont feel very well")
|
||||
stage2 = list("You feel cold")
|
||||
stage3 = list(span_danger("Your heart skips a beat"), span_danger("You have a dull pain in your heart"))
|
||||
stage4 = list(span_danger("You're hungry but normal food does not seem appetizing"))
|
||||
stage5 = list(span_danger("Blood....Blood..."))
|
||||
new_form = /mob/living/carbon/human/species/hemophage
|
||||
infectable_biotypes = MOB_ORGANIC|MOB_UNDEAD
|
||||
|
||||
/datum/disease/transformation/xeno
|
||||
new_form = /mob/living/carbon/alien/adult/skyrat/drone
|
||||
@@ -22,6 +22,12 @@
|
||||
/// Are we taking damage?
|
||||
var/life_support_failed = FALSE
|
||||
|
||||
/datum/quirk/equipping/entombed/add(client/client_source)
|
||||
if(modsuit) return
|
||||
modsuit = quirk_holder.get_item_by_slot(ITEM_SLOT_BACK)
|
||||
if(!istype(modsuit))
|
||||
modsuit = null
|
||||
|
||||
/datum/quirk/equipping/entombed/process(seconds_per_tick)
|
||||
var/mob/living/carbon/human/human_holder = quirk_holder
|
||||
if(human_holder.stat == DEAD)
|
||||
@@ -33,6 +39,7 @@
|
||||
// we've got no modsuit or life support and we're not on stasis. take damage ow
|
||||
human_holder.adjustToxLoss(ENTOMBED_TICK_DAMAGE * seconds_per_tick, updating_health = TRUE, forced = TRUE)
|
||||
human_holder.set_jitter_if_lower(10 SECONDS)
|
||||
return
|
||||
|
||||
if (!modsuit.active)
|
||||
if (!life_support_timer)
|
||||
@@ -122,6 +129,8 @@
|
||||
modsuit.quick_activation()
|
||||
|
||||
/datum/quirk/equipping/entombed/remove()
|
||||
if(!cleanup)
|
||||
return
|
||||
var/mob/living/carbon/human/human_holder = quirk_holder
|
||||
if (deploy_locked && HAS_TRAIT_FROM(human_holder, TRAIT_NODISMEMBER, QUIRK_TRAIT))
|
||||
REMOVE_TRAIT(human_holder, TRAIT_NODISMEMBER, QUIRK_TRAIT)
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
/// Looking through pillows on sofas when rightclicked
|
||||
/obj/structure/chair/sofa/attack_hand_secondary(mob/user, list/modifiers)
|
||||
. = ..()
|
||||
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
|
||||
return
|
||||
if(!ishuman(user) || !user.ckey)
|
||||
return ..()
|
||||
return
|
||||
balloon_alert(user, "searching under pillows...")
|
||||
to_chat(user, span_alert("You start scouring through the sofa's pillows...."))
|
||||
if(do_after(user, 10 SECONDS, src))
|
||||
@@ -16,3 +19,4 @@
|
||||
new /obj/item/coin/iron(loc)
|
||||
else
|
||||
balloon_alert(user, "nothing")
|
||||
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
|
||||
/obj/structure/chalkboard/attack_hand_secondary(mob/user)
|
||||
. = ..()
|
||||
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
|
||||
return
|
||||
to_chat(user, span_warning("You pick up the eraser and begin to clear the board."))
|
||||
if(!written_text)
|
||||
to_chat(user, span_warning("You pick up the eraser and give the board a few pap-paps, but it has nothing on it to erase."))
|
||||
|
||||
466
modular_zubbers/code/game/objects/structures/lewd_portals.dm
Normal file
466
modular_zubbers/code/game/objects/structures/lewd_portals.dm
Normal file
@@ -0,0 +1,466 @@
|
||||
#define GLORYHOLE "gloryhole"
|
||||
#define WALLSTUCK "wallstuck"
|
||||
#define PORTAL_SIGNAL_LIST list( \
|
||||
COMSIG_MOB_POST_EQUIP, \
|
||||
COMSIG_HUMAN_UNEQUIPPED_ITEM, \
|
||||
COMSIG_HUMAN_TOGGLE_UNDERWEAR, \
|
||||
COMSIG_MOB_HANDCUFFED, \
|
||||
COMSIG_MOB_EMOTE, \
|
||||
COMSIG_EMOTE_OVERLAY_EXPIRE, \
|
||||
COMSIG_HUMAN_ADJUST_AROUSAL, \
|
||||
COMSIG_HUMAN_TOGGLE_AROUSAL, \
|
||||
COMSIG_HUMAN_TOGGLE_GENITALS \
|
||||
)
|
||||
|
||||
/obj/structure/lewd_portal
|
||||
name = "LustWish Portal"
|
||||
desc = "A portal that people can partially fit through."
|
||||
icon = 'modular_zubbers/icons/obj/structures/lewd_portals.dmi'
|
||||
icon_state = "portal"
|
||||
can_buckle = TRUE
|
||||
anchored = TRUE
|
||||
max_buckled_mobs = 1
|
||||
buckle_lying = 0
|
||||
buckle_prevents_pull = TRUE
|
||||
///Human currently occupying
|
||||
var/mob/living/carbon/human/current_mob = null
|
||||
///Portal mode, gloryhole for crotch, wallstuck for lower body
|
||||
var/portal_mode = GLORYHOLE
|
||||
///The other end of the portal
|
||||
var/obj/structure/lewd_portal/linked_portal
|
||||
///The relayed body portion associated with this.
|
||||
var/obj/lewd_portal_relay/relayed_body
|
||||
///Gloryhole mode needs to make a characters penis invisible, this records the previous state
|
||||
var/initial_genital_visibility
|
||||
///This variable is used to get the scale of the buckled mob without touching the rotaiton, used for larger/small characters
|
||||
var/datum/decompose_matrix/mob_scale_manager
|
||||
///How offset someones head should be when stuck in a wall.
|
||||
var/wallstuck_offset_amount = 12
|
||||
|
||||
/obj/structure/lewd_portal/Initialize(mapload)
|
||||
LAZYINITLIST(buckled_mobs)
|
||||
. = ..()
|
||||
register_context()
|
||||
|
||||
/obj/structure/lewd_portal/Destroy()
|
||||
visible_message("[src] vanishes!")
|
||||
linked_portal?.linked_portal = null
|
||||
if(linked_portal)
|
||||
qdel(linked_portal)
|
||||
return ..()
|
||||
|
||||
/obj/structure/lewd_portal/examine(mob/user)
|
||||
. = ..()
|
||||
var/inspect_mode = "gloryhole"
|
||||
if(portal_mode == WALLSTUCK)
|
||||
inspect_mode = "stuck in wall"
|
||||
. += span_notice("Its currently in [inspect_mode] mode.")
|
||||
. += span_notice("Right click to change modes.")
|
||||
|
||||
/obj/structure/lewd_portal/add_context(atom/source, list/context, obj/item/held_item, mob/living/user)
|
||||
if(portal_mode == GLORYHOLE)
|
||||
context[SCREENTIP_CONTEXT_RMB] = "Stuck In Wall Mode"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
else
|
||||
context[SCREENTIP_CONTEXT_RMB] = "Gloryhole Mode"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
|
||||
/obj/structure/lewd_portal/user_buckle_mob(mob/living/M, mob/user, check_loc)
|
||||
if(!M.check_erp_prefs(/datum/preference/toggle/erp/sex_toy, user, src))
|
||||
to_chat(user, span_danger("Looks like [M] doesn't want you to do that."))
|
||||
return FALSE
|
||||
if (!ishuman(M))
|
||||
balloon_alert(user, "[M.p_they()] does not fit!")
|
||||
return FALSE
|
||||
if(portal_mode == GLORYHOLE)
|
||||
var/mob/living/carbon/human/penis_inspection = M
|
||||
var/obj/item/organ/genital/penis/penis_reference = M.get_organ_slot(ORGAN_SLOT_PENIS)
|
||||
if(!penis_inspection.has_penis(REQUIRE_GENITAL_EXPOSED) || penis_reference?.visibility_preference == GENITAL_NEVER_SHOW)
|
||||
balloon_alert(user, "a penis is required to operate!")
|
||||
return FALSE
|
||||
if (!linked_portal)
|
||||
balloon_alert(user, "portal not linked!")
|
||||
return FALSE
|
||||
if (!isnull(linked_portal.current_mob))
|
||||
balloon_alert(user, "portal already occupied!")
|
||||
return FALSE
|
||||
visible_message("[user] slots [M] into the [src]!")
|
||||
return ..(M, user, check_loc = FALSE)
|
||||
|
||||
/obj/structure/lewd_portal/post_buckle_mob(mob/living/buckled_mob)
|
||||
if (!ishuman(buckled_mob))
|
||||
return
|
||||
if(LAZYLEN(buckled_mobs))
|
||||
if(ishuman(buckled_mobs[1]))
|
||||
current_mob = buckled_mobs[1]
|
||||
mob_scale_manager = current_mob.transform.decompose()
|
||||
offset_algorithm()
|
||||
|
||||
if(!isnull(current_mob.dna.species))
|
||||
relayed_body = new /obj/lewd_portal_relay(linked_portal.loc, current_mob, linked_portal)
|
||||
relayed_body.transform = relayed_body.transform.Scale(mob_scale_manager.scale_x, mob_scale_manager.scale_y)
|
||||
switch(linked_portal.dir)
|
||||
if(NORTH)
|
||||
relayed_body.pixel_y = 24
|
||||
if(portal_mode == GLORYHOLE)
|
||||
relayed_body.pixel_y += 3
|
||||
if(SOUTH)
|
||||
relayed_body.pixel_y = -24
|
||||
relayed_body.transform = turn(relayed_body.transform, ROTATION_FLIP)
|
||||
if(portal_mode == GLORYHOLE)
|
||||
relayed_body.pixel_y -= 3
|
||||
if(EAST)
|
||||
relayed_body.pixel_x = 24
|
||||
if(portal_mode == WALLSTUCK)
|
||||
relayed_body.transform = turn(relayed_body.transform, ROTATION_COUNTERCLOCKWISE)
|
||||
else
|
||||
relayed_body.pixel_y = 7
|
||||
if(WEST)
|
||||
relayed_body.pixel_x = -24
|
||||
if(portal_mode == WALLSTUCK)
|
||||
relayed_body.transform = turn(relayed_body.transform, ROTATION_CLOCKWISE)
|
||||
else
|
||||
relayed_body.pixel_y = 7
|
||||
relayed_body.update_visuals()
|
||||
if(portal_mode == GLORYHOLE)
|
||||
var/obj/item/organ/genital/penis/penis_reference = current_mob.get_organ_slot(ORGAN_SLOT_PENIS)
|
||||
initial_genital_visibility = penis_reference?.visibility_preference
|
||||
hide_penis()
|
||||
RegisterSignals(current_mob, PORTAL_SIGNAL_LIST, PROC_REF(hide_penis))
|
||||
current_mob.dir = dir
|
||||
switch(dir)
|
||||
if(NORTH)
|
||||
current_mob.pixel_y += 24
|
||||
if(SOUTH)
|
||||
current_mob.pixel_y += -6
|
||||
if(EAST)
|
||||
current_mob.pixel_x += 12
|
||||
if(WEST)
|
||||
current_mob.pixel_x += -12
|
||||
else
|
||||
current_mob.dir = SOUTH
|
||||
head_only()
|
||||
RegisterSignals(current_mob, PORTAL_SIGNAL_LIST, PROC_REF(head_only))
|
||||
switch(dir)
|
||||
if(NORTH)
|
||||
current_mob.pixel_y += wallstuck_offset_amount
|
||||
if(SOUTH)
|
||||
current_mob.pixel_y += -wallstuck_offset_amount
|
||||
current_mob.transform = turn(current_mob.transform, ROTATION_FLIP)
|
||||
if(EAST)
|
||||
current_mob.pixel_x += wallstuck_offset_amount
|
||||
current_mob.transform = turn(current_mob.transform, ROTATION_COUNTERCLOCKWISE)
|
||||
if(WEST)
|
||||
current_mob.pixel_x += -wallstuck_offset_amount
|
||||
current_mob.transform = turn(current_mob.transform, ROTATION_CLOCKWISE)
|
||||
else
|
||||
unbuckle_all_mobs()
|
||||
..()
|
||||
|
||||
///Algorithm that calculates what a mob head offset should be based on mob scale.
|
||||
/obj/structure/lewd_portal/proc/offset_algorithm()
|
||||
var/transform_scale_height = mob_scale_manager.scale_y
|
||||
if(transform_scale_height <= 1)
|
||||
wallstuck_offset_amount = (-30 * transform_scale_height) + 42
|
||||
else
|
||||
wallstuck_offset_amount = (-24 * transform_scale_height) + 36
|
||||
wallstuck_offset_amount = clamp(round(wallstuck_offset_amount), 0, 18)
|
||||
|
||||
|
||||
///Hides the buckled mob's penis
|
||||
/obj/structure/lewd_portal/proc/hide_penis()
|
||||
SIGNAL_HANDLER
|
||||
var/obj/item/organ/genital/penis/affected_penis = current_mob.get_organ_slot(ORGAN_SLOT_PENIS) //Stolen from Strapon code, this is bad we should probably have a cleaner way
|
||||
affected_penis?.visibility_preference = GENITAL_NEVER_SHOW
|
||||
current_mob.update_body()
|
||||
affected_penis?.visibility_preference = initial_genital_visibility //These seems weird but I need to hide the penis when people use the gloryhole while maintaining its visability so it can be interacted with.
|
||||
|
||||
///Removes everything besides the head for the buckled mob, used in wallstuck mode
|
||||
/obj/structure/lewd_portal/proc/head_only()
|
||||
SIGNAL_HANDLER
|
||||
current_mob.cut_overlays()
|
||||
current_mob.update_body_parts_head_only()
|
||||
var/obj/item/clothing/glasses = current_mob.glasses
|
||||
if(glasses)
|
||||
current_mob.update_worn_glasses()
|
||||
current_mob.remove_overlay(BODY_ADJ_LAYER)
|
||||
current_mob.remove_overlay(BODY_LAYER)
|
||||
current_mob.remove_overlay(HANDS_LAYER)
|
||||
var/obj/item/bodypart/head/mob_head = current_mob.get_bodypart(BODY_ZONE_HEAD)
|
||||
if(mob_head.head_flags & HEAD_EYESPRITES)
|
||||
var/obj/item/organ/eyes/eye_organ = current_mob.get_organ_slot(ORGAN_SLOT_EYES)
|
||||
if(eye_organ)
|
||||
eye_organ.refresh(call_update = FALSE)
|
||||
current_mob.overlays_standing[BODY_LAYER] += eye_organ.generate_body_overlay(current_mob)
|
||||
current_mob.apply_overlay(BODY_LAYER)
|
||||
|
||||
/obj/structure/lewd_portal/post_unbuckle_mob(mob/living/unbuckled_mob)
|
||||
UnregisterSignal(current_mob, PORTAL_SIGNAL_LIST)
|
||||
visible_message("[current_mob] exits the [src]")
|
||||
current_mob = null
|
||||
mob_scale_manager = null
|
||||
QDEL_NULL(relayed_body)
|
||||
unbuckled_mob.cut_overlays()
|
||||
unbuckled_mob.regenerate_icons()
|
||||
var/offset_amount = 24
|
||||
if(portal_mode == WALLSTUCK)
|
||||
offset_amount = wallstuck_offset_amount
|
||||
wallstuck_offset_amount = 12
|
||||
switch(dir)
|
||||
if(NORTH)
|
||||
unbuckled_mob.pixel_y -= offset_amount
|
||||
if(SOUTH)
|
||||
if(portal_mode == WALLSTUCK)
|
||||
unbuckled_mob.pixel_y += offset_amount
|
||||
unbuckled_mob.transform = turn(unbuckled_mob.transform, ROTATION_FLIP)
|
||||
else
|
||||
unbuckled_mob.pixel_y += 6
|
||||
if(EAST)
|
||||
if(portal_mode == WALLSTUCK)
|
||||
unbuckled_mob.pixel_x -= offset_amount
|
||||
unbuckled_mob.transform = turn(unbuckled_mob.transform, ROTATION_CLOCKWISE)
|
||||
else
|
||||
unbuckled_mob.pixel_x -= 12
|
||||
if(WEST)
|
||||
if(portal_mode == WALLSTUCK)
|
||||
unbuckled_mob.pixel_x += offset_amount
|
||||
unbuckled_mob.transform = turn(unbuckled_mob.transform, ROTATION_COUNTERCLOCKWISE)
|
||||
else
|
||||
unbuckled_mob.pixel_x += 12
|
||||
if(portal_mode == GLORYHOLE)
|
||||
var/obj/item/organ/genital/penis/affected_penis = unbuckled_mob.get_organ_slot(ORGAN_SLOT_PENIS) //Stolen from Strapon code, this is bad we should probably have a cleaner way
|
||||
affected_penis?.visibility_preference = initial_genital_visibility
|
||||
initial_genital_visibility = null
|
||||
unbuckled_mob.update_body()
|
||||
. = ..()
|
||||
|
||||
/obj/structure/lewd_portal/wrench_act_secondary(mob/living/user, obj/item/weapon)
|
||||
..()
|
||||
weapon.play_tool_sound(src)
|
||||
deconstruct(disassembled = TRUE)
|
||||
return TRUE
|
||||
|
||||
/obj/structure/lewd_portal/attack_hand_secondary(mob/user, list/modifiers)
|
||||
. = ..()
|
||||
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
|
||||
return
|
||||
if(isnull(linked_portal))
|
||||
balloon_alert(user, "portal not linked")
|
||||
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
||||
if(!isnull(current_mob) || !isnull(linked_portal.current_mob))
|
||||
balloon_alert(user, "portal occupied")
|
||||
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
||||
if(portal_mode == GLORYHOLE)
|
||||
portal_mode = WALLSTUCK
|
||||
linked_portal.portal_mode = WALLSTUCK
|
||||
balloon_alert(user, "switched to stuck in wall mode")
|
||||
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
||||
else
|
||||
portal_mode = GLORYHOLE
|
||||
linked_portal.portal_mode = GLORYHOLE
|
||||
balloon_alert(user, "switched to gloryhole mode")
|
||||
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
||||
|
||||
|
||||
/obj/item/wallframe/lewd_portal
|
||||
name = "Lustwish Portal Bore"
|
||||
desc = "A device utilizing bluespace technology to transpose portions of people from one space to another."
|
||||
icon = 'modular_zubbers/icons/obj/structures/lewd_portals.dmi'
|
||||
icon_state = "device"
|
||||
result_path = /obj/structure/lewd_portal
|
||||
pixel_shift = 32
|
||||
multi_use = 2
|
||||
bypass_unpowered = TRUE
|
||||
bypass_floor = TRUE
|
||||
///The mode portals created by this device will be in
|
||||
var/creation_mode = GLORYHOLE
|
||||
///The previous portal placed by the bore, recorded so that they can be linked.
|
||||
var/obj/structure/lewd_portal/previous_portal
|
||||
|
||||
/obj/item/wallframe/lewd_portal/examine(mob/user)
|
||||
. = ..()
|
||||
var/inspect_mode = "gloryhole"
|
||||
if(creation_mode == WALLSTUCK)
|
||||
inspect_mode = "stuck in wall"
|
||||
. += span_notice("Its currently in [inspect_mode] mode.")
|
||||
. += span_notice("Use in hand to change modes.")
|
||||
|
||||
/obj/item/wallframe/lewd_portal/after_attach(obj/attached_to)
|
||||
var/obj/structure/lewd_portal/portal_result = attached_to
|
||||
portal_result.portal_mode = creation_mode
|
||||
if(!previous_portal)
|
||||
previous_portal = portal_result
|
||||
else
|
||||
portal_result.linked_portal = previous_portal
|
||||
previous_portal.linked_portal = portal_result
|
||||
previous_portal = null
|
||||
. = ..()
|
||||
|
||||
/obj/item/wallframe/lewd_portal/attack_self(mob/user)
|
||||
if(previous_portal)
|
||||
balloon_alert(user, "portals must match")
|
||||
return
|
||||
if(creation_mode == GLORYHOLE)
|
||||
creation_mode = WALLSTUCK
|
||||
balloon_alert(user, "switched to stuck in wall mode")
|
||||
else
|
||||
creation_mode = GLORYHOLE
|
||||
balloon_alert(user, "switched to gloryhole mode")
|
||||
|
||||
/obj/lewd_portal_relay
|
||||
name = "portal relay"
|
||||
desc = "Someone's behind hanging out from a portal."
|
||||
anchored = TRUE
|
||||
layer = ABOVE_MOB_LAYER
|
||||
///Mob that this relay is connected to
|
||||
var/mob/living/carbon/human/owner
|
||||
///Portal that spawns this relay
|
||||
var/obj/structure/lewd_portal/owning_portal
|
||||
///What mode this portal is in
|
||||
var/portal_mode = GLORYHOLE
|
||||
|
||||
/obj/lewd_portal_relay/Initialize(mapload, mob/living/carbon/human/owner_ref, obj/structure/lewd_portal/owning_portal_reference)
|
||||
. = ..()
|
||||
appearance_flags |= KEEP_TOGETHER
|
||||
if(!owner_ref || !owning_portal_reference)
|
||||
return INITIALIZE_HINT_QDEL
|
||||
owning_portal = owning_portal_reference
|
||||
portal_mode = owning_portal.portal_mode
|
||||
owner = owner_ref
|
||||
if(portal_mode == GLORYHOLE)
|
||||
var/obj/item/organ/genital/penis/penis_reference = owner.get_organ_slot(ORGAN_SLOT_PENIS)
|
||||
var/penis_type = penis_reference.genital_name
|
||||
name = LOWER_TEXT("[penis_type] penis")
|
||||
desc = "Someone's penis hanging out from a portal."
|
||||
dir = SOUTH
|
||||
if (owning_portal.dir == EAST || owning_portal.dir == WEST)
|
||||
dir = REVERSE_DIR(owning_portal.dir)
|
||||
else
|
||||
dir = NORTH
|
||||
var/species_name
|
||||
if(owner.dna?.species?.lore_protected || !owner.dna?.features["custom_species"])
|
||||
species_name = owner.dna.species.name
|
||||
else
|
||||
species_name = owner.dna.features["custom_species"]
|
||||
name = LOWER_TEXT("[species_name] behind")
|
||||
|
||||
RegisterSignals(owner, PORTAL_SIGNAL_LIST, PROC_REF(update_visuals))
|
||||
become_hearing_sensitive(ROUNDSTART_TRAIT)
|
||||
var/datum/component/interactable/interact_component = owner.GetComponent(/datum/component/interactable)
|
||||
interact_component?.body_relay = src
|
||||
|
||||
/obj/lewd_portal_relay/Destroy(force)
|
||||
if(!isnull(owner))
|
||||
UnregisterSignal(owner, PORTAL_SIGNAL_LIST)
|
||||
var/datum/component/interactable/interact_component = owner.GetComponent(/datum/component/interactable)
|
||||
owner = null
|
||||
owning_portal = null
|
||||
interact_component?.body_relay = null
|
||||
visible_message("[src] vanishes into the portal!")
|
||||
lose_hearing_sensitivity(ROUNDSTART_TRAIT)
|
||||
return ..()
|
||||
|
||||
/obj/lewd_portal_relay/examine(mob/user)
|
||||
. = ..()
|
||||
for(var/genital in GLOB.possible_genitals)
|
||||
if(genital == ORGAN_SLOT_BREASTS)
|
||||
continue
|
||||
if(owner.dna.species.mutant_bodyparts[genital])
|
||||
var/datum/sprite_accessory/genital/gential_sprite = SSaccessories.sprite_accessories[genital][owner.dna.species.mutant_bodyparts[genital][MUTANT_INDEX_NAME]]
|
||||
if(gential_sprite)
|
||||
if(!(gential_sprite.is_hidden(owner)))
|
||||
. += "<span class='notice'>It has exposed genitals... <a href='byond://?src=[REF(src)];lookup_info=genitals'>\[Look closer...\]</a></span>"
|
||||
break
|
||||
|
||||
/obj/lewd_portal_relay/Topic(href, href_list)
|
||||
. = ..()
|
||||
if(href_list["lookup_info"])
|
||||
if(href_list["lookup_info"] == "genitals")
|
||||
var/list/line = list()
|
||||
for(var/genital in GLOB.possible_genitals)
|
||||
if(!owner.dna.species.mutant_bodyparts[genital] || genital == ORGAN_SLOT_BREASTS)
|
||||
continue
|
||||
var/datum/sprite_accessory/genital/gential_sprite = SSaccessories.sprite_accessories[genital][owner.dna.species.mutant_bodyparts[genital][MUTANT_INDEX_NAME]]
|
||||
if(!gential_sprite)
|
||||
continue
|
||||
if(gential_sprite.is_hidden(owner))
|
||||
continue
|
||||
var/obj/item/organ/genital/organ = owner.get_organ_slot(gential_sprite.associated_organ_slot)
|
||||
if(!organ)
|
||||
continue
|
||||
line += organ.get_description_string(gential_sprite)
|
||||
if(length(line))
|
||||
to_chat(usr, span_notice("[jointext(line, "\n")]"))
|
||||
|
||||
/obj/lewd_portal_relay/proc/update_visuals()
|
||||
SIGNAL_HANDLER
|
||||
if(portal_mode == GLORYHOLE)
|
||||
penis_only()
|
||||
else
|
||||
lower_body_only()
|
||||
|
||||
/obj/lewd_portal_relay/proc/penis_only()
|
||||
cut_overlays()
|
||||
var/obj/item/organ/genital/penis/penis_reference = owner.get_organ_slot(ORGAN_SLOT_PENIS)
|
||||
var/mutable_appearance/penis_image = penis_reference.bodypart_overlay.get_overlay(EXTERNAL_FRONT)
|
||||
add_overlay(penis_image)
|
||||
|
||||
/obj/lewd_portal_relay/proc/lower_body_only()
|
||||
owner.dna.species.handle_body(owner) //Suboptimal way for doing this but I couldn't figure out another way to maintain underwear when dropping items
|
||||
cut_overlays()
|
||||
for(var/limb in list(BODY_ZONE_R_LEG, BODY_ZONE_L_LEG, BODY_ZONE_CHEST))
|
||||
var/obj/item/bodypart/limb_object = owner.get_bodypart(limb)
|
||||
if(istype(limb_object))
|
||||
var/limb_icon_list = limb_object.get_limb_icon()
|
||||
if(limb_object == owner.get_bodypart(BODY_ZONE_CHEST))
|
||||
limb_icon_list = torso_only(limb_icon_list)
|
||||
add_overlay(limb_icon_list)
|
||||
if(owner.shoes)
|
||||
add_overlay(owner.overlays_standing[SHOES_LAYER])
|
||||
if(owner.w_uniform)
|
||||
var/image/uniform_overlay = image(owner.overlays_standing[UNIFORM_LAYER])
|
||||
uniform_overlay.add_filter("upper_body_removal", 1, list("type" = "alpha", "icon" = icon('modular_zubbers/icons/obj/structures/lewd_portals.dmi', "mask")))
|
||||
add_overlay(uniform_overlay)
|
||||
var/list/body_layer_overlays = list()
|
||||
for(var/image/body_layer_overlay in owner.overlays_standing[BODY_LAYER])
|
||||
var/image/new_body_layer_overlay = image(body_layer_overlay)
|
||||
new_body_layer_overlay.add_filter("upper_body_removal", 1, list("type" = "alpha", "icon" = icon('modular_zubbers/icons/obj/structures/lewd_portals.dmi', "mask")))
|
||||
body_layer_overlays += new_body_layer_overlay
|
||||
add_overlay(body_layer_overlays)
|
||||
|
||||
/obj/lewd_portal_relay/proc/torso_only(limb_icon_list)
|
||||
var/list/new_limb_icon_list = list()//There may be special cases where body overlays should not pass through portals, such as moth wings, this is used to removed them
|
||||
for(var/image/limb_icon in limb_icon_list)
|
||||
if(compare_organ_icon(ORGAN_SLOT_EXTERNAL_WINGS, limb_icon.icon)) //Moth wings are attached to the upper back so shouldn't be portalled, their weird sprite size also messes with rotations
|
||||
continue
|
||||
var/limb_icon_layer = limb_icon.layer * -1
|
||||
if(limb_icon_layer != BODY_BEHIND_LAYER && limb_icon_layer != BODY_FRONT_LAYER || compare_organ_icon(ORGAN_SLOT_BREASTS, limb_icon.icon)) //Tails need to be portaled
|
||||
limb_icon.add_filter("upper_body_removal", 1, list("type" = "alpha", "icon" = icon('modular_zubbers/icons/obj/structures/lewd_portals.dmi', "mask")))
|
||||
new_limb_icon_list += limb_icon
|
||||
return new_limb_icon_list
|
||||
|
||||
/obj/lewd_portal_relay/proc/compare_organ_icon(organ_slot, icon_to_compare)
|
||||
var/obj/item/organ/organ_ref = owner?.get_organ_slot(organ_slot)
|
||||
var/datum/bodypart_overlay/mutant/overlay_ref = organ_ref?.bodypart_overlay
|
||||
var/datum/sprite_accessory/accessory_ref = overlay_ref?.sprite_datum
|
||||
return accessory_ref?.icon == icon_to_compare
|
||||
|
||||
/obj/lewd_portal_relay/attack_hand_secondary(mob/living/user)
|
||||
if(!user.can_perform_action(src, NEED_DEXTERITY|NEED_HANDS|ALLOW_RESTING))
|
||||
return ..()
|
||||
if(portal_mode == GLORYHOLE)
|
||||
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
||||
if(dir == NORTH)
|
||||
dir = SOUTH
|
||||
else
|
||||
dir = NORTH
|
||||
to_chat(user, span_info("You flip \the [name] over."))
|
||||
to_chat(owner, span_info("You feel your behind flip over."))
|
||||
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
||||
|
||||
/obj/lewd_portal_relay/click_ctrl_shift(mob/user)
|
||||
owner.click_ctrl_shift(user)
|
||||
|
||||
#undef GLORYHOLE
|
||||
#undef WALLSTUCK
|
||||
#undef PORTAL_SIGNAL_LIST
|
||||
@@ -135,7 +135,7 @@
|
||||
pay_cost(TEMP_GHOULIZE_COST - bloodcost)
|
||||
log_combat(owner, target, "tremere revived", addition="Revived their ghoul using dominate")
|
||||
return FALSE
|
||||
if(!bloodsuckerdatum_power.make_ghoul(target) )
|
||||
if(!bloodsuckerdatum_power.make_ghoul(target))
|
||||
owner.balloon_alert(owner, "not a valid target for ghouling!.")
|
||||
return
|
||||
|
||||
|
||||
@@ -187,6 +187,7 @@
|
||||
unbuckle_mob(buckled_carbons)
|
||||
else
|
||||
user_unbuckle_mob(buckled_carbons, user)
|
||||
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
||||
|
||||
/**
|
||||
* Attempts to buckle target into the ghoulrack
|
||||
@@ -331,8 +332,8 @@
|
||||
return
|
||||
// Convert to Ghoul!
|
||||
bloodsuckerdatum.AdjustBloodVolume(-TORTURE_CONVERSION_COST)
|
||||
remove_loyalties(target)
|
||||
if(bloodsuckerdatum.make_ghoul(target))
|
||||
remove_loyalties(target)
|
||||
SEND_SIGNAL(bloodsuckerdatum, COMSIG_BLOODSUCKER_MADE_GHOUL, user, target)
|
||||
|
||||
/obj/structure/bloodsucker/ghoulrack/proc/do_torture(mob/living/user, mob/living/carbon/target, mult = 1)
|
||||
@@ -378,7 +379,7 @@
|
||||
target.apply_damages(brute = torture_dmg_brute, burn = torture_dmg_burn, def_zone = selected_bodypart.body_zone)
|
||||
return TRUE
|
||||
|
||||
/// Offer them the oppertunity to join now.
|
||||
/// Offer them the opportunity to join now.
|
||||
/obj/structure/bloodsucker/ghoulrack/proc/do_disloyalty(mob/living/user, mob/living/target)
|
||||
if(disloyalty_offered)
|
||||
return FALSE
|
||||
@@ -399,8 +400,13 @@
|
||||
switch(alert_response)
|
||||
if("Accept")
|
||||
disloyalty_confirm = TRUE
|
||||
target.visible_message(
|
||||
span_notice("[target] gives in to [user]'s offer of servitude!"),
|
||||
span_userdanger("You give in to [user]'s offer of servitude!"))
|
||||
else
|
||||
target.balloon_alert_to_viewers("stares defiantly", "refused ghouling!")
|
||||
target.visible_message(
|
||||
span_danger("[target] stares defiantly at [user], refusing to give in!"),
|
||||
span_danger("You stare defiantly at [user], refusing to give in!"))
|
||||
disloyalty_offered = FALSE
|
||||
return TRUE
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@
|
||||
return
|
||||
|
||||
owner.current.visible_message(
|
||||
span_deconversion_message("[owner.current]'s eyes dart feverishly from side to side, and then stop. [owner.current.p_they(TRUE)] seem[owner.current.p_s()] calm, \
|
||||
span_deconversion_message("[owner.current]'s eyes dart feverishly from side to side, and then stop. [owner.current.p_They(TRUE)] seem[owner.current.p_s()] to calm, \
|
||||
like [owner.current.p_they()] [owner.current.p_have()] regained some lost part of [owner.current.p_them()]self."), \
|
||||
span_deconversion_message("With a snap, you are no longer enslaved to [master.owner]! You breathe in heavily, having regained your free will."))
|
||||
owner.current.playsound_local(null, 'sound/effects/magic/mutate.ogg', 100, FALSE, pressure_affected = FALSE)
|
||||
|
||||
@@ -62,6 +62,8 @@
|
||||
|
||||
/obj/machinery/computer/nanite_cloud_controller/attack_hand_secondary(mob/user, list/modifiers)
|
||||
. = ..()
|
||||
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
|
||||
return
|
||||
if(disk && user.can_perform_action(src, !issilicon(user)))
|
||||
to_chat(user, span_notice("You take out [disk] from [src]."))
|
||||
eject(user)
|
||||
|
||||
@@ -92,6 +92,8 @@
|
||||
|
||||
/obj/machinery/nanite_program_hub/attack_hand_secondary(mob/user, list/modifiers)
|
||||
. = ..()
|
||||
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
|
||||
return
|
||||
if(disk && user.can_perform_action(src, !issilicon(user)))
|
||||
to_chat(user, span_notice("You take out [disk] from [src]."))
|
||||
eject(user)
|
||||
|
||||
@@ -58,6 +58,8 @@
|
||||
|
||||
/obj/machinery/nanite_programmer/attack_hand_secondary(mob/user, list/modifiers)
|
||||
. = ..()
|
||||
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
|
||||
return
|
||||
if(disk && user.can_perform_action(src, !issilicon(user)))
|
||||
to_chat(user, span_notice("You take out [disk] from [src]."))
|
||||
eject(user)
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
/datum/chemical_reaction/mutationtoxin/abductor
|
||||
results = list(/datum/reagent/mutationtoxin/abductor = 1)
|
||||
required_reagents = list(/datum/reagent/liquid_dark_matter = 1, /datum/reagent/consumable/ethanol/abduction_fruit = 3, /datum/reagent/medicine/psicodine = 2, /datum/reagent/mutationtoxin = 1)
|
||||
required_temp = 320
|
||||
|
||||
/datum/chemical_reaction/mutationtoxin/akula
|
||||
results = list(/datum/reagent/mutationtoxin/akula = 1)
|
||||
required_reagents = list(/datum/reagent/consumable/ethanol/salt_and_swell = 3, /datum/reagent/toxin/carpotoxin = 2, /datum/reagent/ammonia = 2, /datum/reagent/mutationtoxin = 1)
|
||||
required_temp = 300
|
||||
|
||||
/datum/chemical_reaction/mutationtoxin/android
|
||||
results = list(/datum/reagent/mutationtoxin/android = 1)
|
||||
required_reagents = list(/datum/reagent/consumable/ethanol/oil_drum = 3, /datum/reagent/medicine/nanite_slurry = 2, /datum/reagent/consumable/ethanol/synthanol/robottears = 2, /datum/reagent/mutationtoxin = 1)
|
||||
required_temp = 320
|
||||
|
||||
/datum/chemical_reaction/mutationtoxin/ash
|
||||
results = list(/datum/reagent/mutationtoxin/ash = 1)
|
||||
required_reagents = list(/datum/reagent/consumable/ethanol/coldscales = 3, /datum/reagent/consumable/ethanol/lizardwine = 3, /datum/reagent/ash = 2, /datum/reagent/mutationtoxin = 1)
|
||||
required_temp = 400
|
||||
|
||||
/datum/chemical_reaction/mutationtoxin/dwarf
|
||||
results = list(/datum/reagent/mutationtoxin/dwarf = 1)
|
||||
required_reagents = list(/datum/reagent/consumable/ethanol/manly_dorf = 3, /datum/reagent/consumable/ethanol/bacchus_blessing = 2, /datum/reagent/consumable/ethanol/golden_grog = 2, /datum/reagent/mutationtoxin = 1)
|
||||
required_temp = 320
|
||||
|
||||
/datum/chemical_reaction/mutationtoxin/felinid
|
||||
results = list(/datum/reagent/mutationtoxin/felinid = 1)
|
||||
required_reagents = list(/datum/reagent/toxin/mindbreaker = 5, /datum/reagent/consumable/ethanol/frisky_kitty = 3, /datum/reagent/drug/aphrodisiac/crocin = 2, /datum/reagent/mutationtoxin = 1)
|
||||
required_temp = 320
|
||||
|
||||
/datum/chemical_reaction/mutationtoxin/felinid/primitive
|
||||
results = list(/datum/reagent/mutationtoxin/felinid/primitive = 1)
|
||||
required_reagents = list(/datum/reagent/consumable/frostoil = 5, /datum/reagent/consumable/ethanol/frisky_kitty = 3, /datum/reagent/drug/aphrodisiac/crocin = 2, /datum/reagent/mutationtoxin = 1)
|
||||
required_temp = 270
|
||||
|
||||
/datum/chemical_reaction/mutationtoxin/fly
|
||||
results = list(/datum/reagent/mutationtoxin/fly = 1)
|
||||
required_reagents = list(/datum/reagent/consumable/ethanol/bug_zapper = 3, /datum/reagent/yuck = 3, /datum/reagent/toxin/bad_food = 3, /datum/reagent/mutationtoxin = 1)
|
||||
required_temp = 320
|
||||
|
||||
/datum/chemical_reaction/mutationtoxin/ghoul
|
||||
results = list(/datum/reagent/mutationtoxin/ghoul = 1)
|
||||
required_reagents = list(/datum/reagent/consumable/ethanol/velvet_kiss = 3, /datum/reagent/medicine/strange_reagent = 2, /datum/reagent/toxin/ghoulpowder = 2, /datum/reagent/mutationtoxin = 1)
|
||||
required_temp = 320
|
||||
|
||||
/datum/chemical_reaction/mutationtoxin/golem
|
||||
results = list(/datum/reagent/mutationtoxin/golem = 1)
|
||||
required_reagents = list(/datum/reagent/consumable/ethanol/laval_spit = 3, /datum/reagent/drug/space_drugs = 2, /datum/reagent/smart_foaming_agent = 2, /datum/reagent/mutationtoxin = 1)
|
||||
required_temp = 320
|
||||
|
||||
/datum/chemical_reaction/mutationtoxin/hemophage
|
||||
results = list(/datum/reagent/mutationtoxin/hemophage = 1)
|
||||
required_reagents = list(/datum/reagent/consumable/ethanol/velvet_kiss = 3, /datum/reagent/blood = 2, /datum/reagent/consumable/ethanol/wine = 2, /datum/reagent/mutationtoxin = 1)
|
||||
required_temp = 320
|
||||
|
||||
/datum/chemical_reaction/mutationtoxin/jelly
|
||||
results = list(/datum/reagent/mutationtoxin/jelly = 1)
|
||||
required_reagents = list(/datum/reagent/consumable/ethanol/jell_wyrm = 3, /datum/reagent/medicine/regen_jelly = 3, /datum/reagent/medicine/c2/synthflesh = 2, /datum/reagent/mutationtoxin = 1)
|
||||
required_temp = 320
|
||||
|
||||
/datum/chemical_reaction/mutationtoxin/lizard
|
||||
results = list(/datum/reagent/mutationtoxin/lizard = 1)
|
||||
required_reagents = list(/datum/reagent/consumable/ethanol/coldscales = 3, /datum/reagent/consumable/ethanol/lizardwine = 3, /datum/reagent/consumable/mushroom_tea = 2, /datum/reagent/mutationtoxin = 1)
|
||||
required_temp = 350
|
||||
|
||||
/datum/chemical_reaction/mutationtoxin/monkey
|
||||
results = list(/datum/reagent/mutationtoxin/monkey = 1)
|
||||
required_reagents = list(/datum/reagent/consumable/funky_monkey = 3, /datum/reagent/medicine/coagulant/banana_peel = 2, /datum/reagent/potassium = 2, /datum/reagent/mutationtoxin = 1)
|
||||
required_temp = 320
|
||||
|
||||
/datum/chemical_reaction/mutationtoxin/moth
|
||||
results = list(/datum/reagent/mutationtoxin/moth = 1)
|
||||
required_reagents = list(/datum/reagent/consumable/moth_milk = 3, /datum/reagent/medicine/mannitol = 2, /datum/reagent/medicine/oculine = 2, /datum/reagent/mutationtoxin = 1)
|
||||
required_temp = 320
|
||||
|
||||
/datum/chemical_reaction/mutationtoxin/plasma
|
||||
results = list(/datum/reagent/mutationtoxin/plasma = 1)
|
||||
required_reagents = list(/datum/reagent/medicine/cryoxadone = 2, /datum/reagent/stable_plasma = 2, /datum/reagent/bone_dust = 2, /datum/reagent/mutationtoxin = 1)
|
||||
required_temp = 180
|
||||
|
||||
/datum/chemical_reaction/mutationtoxin/pod
|
||||
results = list(/datum/reagent/mutationtoxin/pod = 1)
|
||||
required_reagents = list(/datum/reagent/cellulose = 20, /datum/reagent/consumable/ethanol/mush_crush = 3, /datum/reagent/plantnutriment/robustharvestnutriment = 3, /datum/reagent/mutationtoxin = 1)
|
||||
required_temp = 320
|
||||
|
||||
/datum/chemical_reaction/mutationtoxin/skeleton
|
||||
results = list(/datum/reagent/mutationtoxin/skeleton = 1)
|
||||
required_reagents = list(/datum/reagent/consumable/ethanol/hollow_bone = 3, /datum/reagent/liquid_dark_matter = 5, /datum/reagent/medicine/strange_reagent = 5, /datum/reagent/consumable/milk = 30, /datum/reagent/bone_dust = 2, /datum/reagent/water/hollowwater = 5, /datum/reagent/mutationtoxin = 1)
|
||||
required_temp = 400
|
||||
|
||||
/datum/chemical_reaction/mutationtoxin/skrell
|
||||
results = list(/datum/reagent/mutationtoxin/skrell = 1)
|
||||
required_reagents = list(/datum/reagent/consumable/ethanol/tropical_storm = 3, /datum/reagent/toxin/carpotoxin = 2, /datum/reagent/ammonia = 2, /datum/reagent/mutationtoxin = 1)
|
||||
required_temp = 320
|
||||
|
||||
/datum/chemical_reaction/mutationtoxin/shadow
|
||||
results = list(/datum/reagent/mutationtoxin/shadow = 1)
|
||||
required_reagents = list(/datum/reagent/liquid_dark_matter = 5, /datum/reagent/consumable/ethanol/singulo = 2, /datum/reagent/smoke_powder = 2, /datum/reagent/mutationtoxin = 1)
|
||||
required_temp = 180
|
||||
|
||||
/datum/chemical_reaction/mutationtoxin/snail
|
||||
results = list(/datum/reagent/snail = 1)
|
||||
required_reagents = list(/datum/reagent/consumable/cucumberlemonade = 3, /datum/reagent/toxin/slimejelly = 2, /datum/reagent/lube = 2, /datum/reagent/mutationtoxin = 1)
|
||||
required_temp = 320
|
||||
|
||||
/datum/chemical_reaction/mutationtoxin/tajaran
|
||||
results = list(/datum/reagent/mutationtoxin/tajaran = 1)
|
||||
required_reagents = list(/datum/reagent/consumable/ethanol/frisky_kitty = 3, /datum/reagent/consumable/frostoil = 2, /datum/reagent/consumable/ice = 2, /datum/reagent/mutationtoxin = 1)
|
||||
required_temp = 270
|
||||
|
||||
/datum/chemical_reaction/mutationtoxin/teshari
|
||||
results = list(/datum/reagent/mutationtoxin/teshari = 1)
|
||||
required_reagents = list(/datum/reagent/consumable/ethanol/antifreeze = 3, /datum/reagent/drug/maint/sludge = 2, /datum/reagent/lube = 2, /datum/reagent/mutationtoxin = 1)
|
||||
required_temp = 320
|
||||
|
||||
/datum/chemical_reaction/mutationtoxin/vox
|
||||
results = list(/datum/reagent/mutationtoxin/vox = 1)
|
||||
required_reagents = list(/datum/reagent/consumable/ethanol/toxins_special= 3, /datum/reagent/medicine/nanite_slurry = 2, /datum/reagent/nitrogen = 2, /datum/reagent/mutationtoxin = 1)
|
||||
required_temp = 320
|
||||
|
||||
/datum/chemical_reaction/mutationtoxin/vox_primalis
|
||||
results = list(/datum/reagent/mutationtoxin/vox_primalis = 1)
|
||||
required_reagents = list(/datum/reagent/consumable/hot_ice_coffee = 3, /datum/reagent/medicine/nanite_slurry = 2, /datum/reagent/nitrogen = 2, /datum/reagent/mutationtoxin = 1)
|
||||
required_temp = 320
|
||||
|
||||
/datum/chemical_reaction/mutationtoxin/xenohybrid
|
||||
results = list(/datum/reagent/mutationtoxin/xenohybrid = 1)
|
||||
required_reagents = list(/datum/reagent/consumable/ethanol/neurotoxin = 3, /datum/reagent/silicon = 2, /datum/reagent/toxin/acid/fluacid = 2, /datum/reagent/mutationtoxin = 1)
|
||||
required_temp = 320
|
||||
|
||||
/datum/chemical_reaction/mutationtoxin/zombie
|
||||
results = list(/datum/reagent/mutationtoxin/zombie = 1)
|
||||
required_reagents = list(/datum/reagent/liquid_dark_matter = 5, /datum/reagent/toxin/zombiepowder = 2, /datum/reagent/medicine/strange_reagent = 2, /datum/reagent/mutationtoxin = 1)
|
||||
required_temp = 320
|
||||
@@ -0,0 +1,99 @@
|
||||
/datum/reagent/mutationtoxin/akula
|
||||
name = "Akula Mutation Toxin"
|
||||
description = "An akula toxin."
|
||||
color = "#5EFF3B" //RGB: 94, 255, 59
|
||||
race = /datum/species/akula
|
||||
taste_description = "fishy"
|
||||
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED|REAGENT_NO_RANDOM_RECIPE
|
||||
|
||||
/datum/reagent/mutationtoxin/dwarf
|
||||
name = "Dwarf Mutation Toxin"
|
||||
description = "A dwarf toxin."
|
||||
color = "#5EFF3B" //RGB: 94, 255, 59
|
||||
race = /datum/species/dwarf
|
||||
taste_description = "earthy"
|
||||
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED|REAGENT_NO_RANDOM_RECIPE
|
||||
|
||||
/datum/reagent/mutationtoxin/felinid/primitive
|
||||
name = "Ice Walker Mutation Toxin"
|
||||
description = "A ice Walker toxin."
|
||||
color = "#5EFF3B" //RGB: 94, 255, 59
|
||||
race = /datum/species/human/felinid/primitive
|
||||
taste_description = "something ancient and cold"
|
||||
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED|REAGENT_NO_RANDOM_RECIPE
|
||||
|
||||
/datum/reagent/mutationtoxin/ghoul
|
||||
name = "Ghoul Mutation Toxin"
|
||||
description = "A ghoul toxin."
|
||||
color = "#5EFF3B" //RGB: 94, 255, 59
|
||||
race = /datum/species/ghoul
|
||||
taste_description = "rotting flesh"
|
||||
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED|REAGENT_NO_RANDOM_RECIPE
|
||||
|
||||
/datum/reagent/mutationtoxin/hemophage
|
||||
name = "Hemophage Corruption Virus"
|
||||
description = "A hemophage virus."
|
||||
color = BLOOD_COLOR_RED
|
||||
taste_description = "blood"
|
||||
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED|REAGENT_NO_RANDOM_RECIPE
|
||||
|
||||
/datum/reagent/mutationtoxin/hemophage/expose_mob(mob/living/exposed_mob, methods=TOUCH, reac_volume, show_message = TRUE, touch_protection = 0)
|
||||
. = ..()
|
||||
if((methods & (PATCH|INGEST|INJECT|INHALE)) || ((methods & (VAPOR|TOUCH)) && prob(min(reac_volume,100)*(1 - touch_protection))))
|
||||
exposed_mob.ForceContractDisease(new /datum/disease/transformation/hemophage(), FALSE, TRUE)
|
||||
|
||||
/datum/reagent/mutationtoxin/monkey
|
||||
name = "Monkey Mutation Toxin"
|
||||
description = "A monkey toxin."
|
||||
color = "#5EFF3B" //RGB: 94, 255, 59
|
||||
race = /datum/species/monkey
|
||||
taste_description = "bananas"
|
||||
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED|REAGENT_NO_RANDOM_RECIPE
|
||||
|
||||
/datum/reagent/mutationtoxin/skrell
|
||||
name = "Skrell Mutation Toxin"
|
||||
description = "A skrell toxin."
|
||||
color = "#5EFF3B" //RGB: 94, 255, 59
|
||||
race = /datum/species/skrell
|
||||
taste_description = "squid"
|
||||
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED|REAGENT_NO_RANDOM_RECIPE
|
||||
|
||||
/datum/reagent/mutationtoxin/tajaran
|
||||
name = "Tajaran Mutation Toxin"
|
||||
description = "A tajaran toxin."
|
||||
color = "#5EFF3B" //RGB: 94, 255, 59
|
||||
race = /datum/species/tajaran
|
||||
taste_description = "toxoplasmosis"
|
||||
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED|REAGENT_NO_RANDOM_RECIPE
|
||||
|
||||
/datum/reagent/mutationtoxin/teshari
|
||||
name = "Teshari Mutation Toxin"
|
||||
description = "A teshari toxin."
|
||||
color = "#5EFF3B" //RGB: 94, 255, 59
|
||||
race = /datum/species/teshari
|
||||
taste_description = "fried chicken"
|
||||
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED|REAGENT_NO_RANDOM_RECIPE
|
||||
|
||||
/datum/reagent/mutationtoxin/vox
|
||||
name = "Vox Mutation Toxin"
|
||||
description = "A voxin."
|
||||
color = "#5EFF3B" //RGB: 94, 255, 59
|
||||
race = /datum/species/vox
|
||||
taste_description = "skreeing with a metallic tinge"
|
||||
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED|REAGENT_NO_RANDOM_RECIPE
|
||||
|
||||
/datum/reagent/mutationtoxin/vox_primalis
|
||||
name = "Vox Primalis Mutation Toxin"
|
||||
description = "A vox primalis toxin."
|
||||
color = "#5EFF3B" //RGB: 94, 255, 59
|
||||
race = /datum/species/vox_primalis
|
||||
taste_description = "screeching with a metallic tinge"
|
||||
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED|REAGENT_NO_RANDOM_RECIPE
|
||||
|
||||
/datum/reagent/mutationtoxin/xenohybrid
|
||||
name = "Xenohybrid Mutation Toxin"
|
||||
description = "A xenohybrid toxin."
|
||||
color = "#5EFF3B" //RGB: 94, 255, 59
|
||||
race = /datum/species/xeno
|
||||
taste_description = "sour"
|
||||
chemical_flags = REAGENT_CAN_BE_SYNTHESIZED|REAGENT_NO_RANDOM_RECIPE
|
||||
@@ -5,6 +5,6 @@
|
||||
/datum/storyteller_data/tracks
|
||||
var/threshold_mundane = 1200
|
||||
var/threshold_moderate = 1800
|
||||
var/threshold_major = 8000
|
||||
var/threshold_major = 7000
|
||||
var/threshold_crewset = 1800
|
||||
var/threshold_ghostset = 7000
|
||||
var/threshold_ghostset = 6000
|
||||
|
||||
@@ -18,6 +18,6 @@
|
||||
/datum/storyteller_data/tracks/fragile
|
||||
threshold_mundane = 1200
|
||||
threshold_moderate = 1800
|
||||
threshold_major = 8000
|
||||
threshold_major = 10000
|
||||
threshold_crewset = 3000
|
||||
threshold_ghostset = 8000
|
||||
|
||||
@@ -17,5 +17,5 @@
|
||||
|
||||
/datum/storyteller_data/tracks/gamer
|
||||
threshold_moderate = 1300
|
||||
threshold_major = 6150
|
||||
threshold_major = 4000
|
||||
threshold_ghostset = 6000
|
||||
|
||||
21
modular_zubbers/code/modules/vetted/examine.dm
Normal file
21
modular_zubbers/code/modules/vetted/examine.dm
Normal file
@@ -0,0 +1,21 @@
|
||||
/mob/living/silicon/get_silicon_flavortext()
|
||||
. = ..()
|
||||
if(!CONFIG_GET(flag/check_vetted))
|
||||
return
|
||||
if(!client || !SSplayer_ranks.initialized)
|
||||
return
|
||||
if(SSplayer_ranks.is_vetted(client, admin_bypass = FALSE))
|
||||
. += span_greenannounce("This player has been vetted as 18+ by staff.")
|
||||
else
|
||||
. += span_velvet("THIS PLAYER IS NOT VETTED! CONTINUE AT YOUR OWN RISK!")
|
||||
|
||||
/mob/living/carbon/human/examine(mob/user)
|
||||
. = ..()
|
||||
if(!CONFIG_GET(flag/check_vetted))
|
||||
return
|
||||
if(!client || !SSplayer_ranks.initialized)
|
||||
return
|
||||
if(SSplayer_ranks.is_vetted(client, admin_bypass = FALSE))
|
||||
. += span_greenannounce("This player has been vetted as 18+ by staff.")
|
||||
else
|
||||
. += span_velvet("THIS PLAYER IS NOT VETTED! CONTINUE AT YOUR OWN RISK!")
|
||||
BIN
modular_zubbers/icons/obj/structures/lewd_portals.dmi
Normal file
BIN
modular_zubbers/icons/obj/structures/lewd_portals.dmi
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 797 B |
@@ -237,6 +237,9 @@
|
||||
handle_dumping(user, tool)
|
||||
|
||||
/obj/machinery/cauldron/attack_hand_secondary(mob/user, list/modifiers)
|
||||
. = ..()
|
||||
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
|
||||
return
|
||||
if(user.can_perform_action(src))
|
||||
if(!length(ingredients))
|
||||
balloon_alert(user, "it's empty!")
|
||||
|
||||
@@ -8889,6 +8889,7 @@
|
||||
#include "modular_zubbers\code\datums\components\vore\z_undefs.dm"
|
||||
#include "modular_zubbers\code\datums\computer_datums\protolathe_modifications.dm"
|
||||
#include "modular_zubbers\code\datums\diseases\advance\presets.dm"
|
||||
#include "modular_zubbers\code\datums\diseases\advance\transformation.dm"
|
||||
#include "modular_zubbers\code\datums\elements\examine_when_worn.dm"
|
||||
#include "modular_zubbers\code\datums\elements\nanite_organ.dm"
|
||||
#include "modular_zubbers\code\datums\greyscale\config_types\greyscale_configs\greyscale_clothes.dm"
|
||||
@@ -9048,6 +9049,7 @@
|
||||
#include "modular_zubbers\code\game\objects\items\tanks\tank_types.dm"
|
||||
#include "modular_zubbers\code\game\objects\structures\aliens.dm"
|
||||
#include "modular_zubbers\code\game\objects\structures\chalkboard.dm"
|
||||
#include "modular_zubbers\code\game\objects\structures\lewd_portals.dm"
|
||||
#include "modular_zubbers\code\game\objects\structures\ore_vent.dm"
|
||||
#include "modular_zubbers\code\game\objects\structures\spirit_board.dm"
|
||||
#include "modular_zubbers\code\game\objects\structures\tables_racks.dm"
|
||||
@@ -9548,6 +9550,8 @@
|
||||
#include "modular_zubbers\code\modules\ratqueen\regalrat.dm"
|
||||
#include "modular_zubbers\code\modules\reagents\drink_reagents.dm"
|
||||
#include "modular_zubbers\code\modules\reagents\chemistry\reagents\food_reagents.dm"
|
||||
#include "modular_zubbers\code\modules\reagents\chemistry\reagents\other_reagents.dm"
|
||||
#include "modular_zubbers\code\modules\reagents\chemistry\reagents\Recipes\others.dm"
|
||||
#include "modular_zubbers\code\modules\reagents\reagent_containers\condiment.dm"
|
||||
#include "modular_zubbers\code\modules\reagents\reagent_containers\medigel.dm"
|
||||
#include "modular_zubbers\code\modules\reagents\reagent_containers\cups\bottle.dm"
|
||||
@@ -9688,6 +9692,7 @@
|
||||
#include "modular_zubbers\code\modules\vending\multisec.dm"
|
||||
#include "modular_zubbers\code\modules\vending\vending.dm"
|
||||
#include "modular_zubbers\code\modules\vending\wardrobe.dm"
|
||||
#include "modular_zubbers\code\modules\vetted\examine.dm"
|
||||
#include "modular_zubbers\code\modules\vetted\vetted.dm"
|
||||
#include "modular_zubbers\code\modules\vetted\overrides\erp_preferences.dm"
|
||||
#include "modular_zubbers\code\modules\voting\_votes.dm"
|
||||
|
||||
Reference in New Issue
Block a user